mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-16 16:16:40 +03:00
76d655bed6
More types of messages are now supported than before. SubscribeError handling has been improved. A new error has been added when no catalog. Existing messages have been reviewed to eliminate inconsistencies in the migration from draft-11 to draft-14 support. Fix log levels
190 lines
5.8 KiB
JavaScript
190 lines
5.8 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.msf.Receiver');
|
|
|
|
goog.require('shaka.log');
|
|
goog.require('shaka.msf.Utils');
|
|
|
|
goog.requireType('shaka.msf.Reader');
|
|
|
|
|
|
shaka.msf.Receiver = class {
|
|
/**
|
|
* @param {!shaka.msf.Reader} reader
|
|
*/
|
|
constructor(reader) {
|
|
/** @private {!shaka.msf.Reader} */
|
|
this.reader_ = reader;
|
|
}
|
|
|
|
/**
|
|
* @return {!Promise<shaka.msf.Utils.ServerSetup>}
|
|
*/
|
|
async server() {
|
|
const SERVER_SETUP = shaka.msf.Utils.MessageTypeId.SERVER_SETUP;
|
|
shaka.log.v1('Decoding server setup message...');
|
|
|
|
const type = await this.reader_.u53();
|
|
shaka.log.v1(`Setup message type: 0x${type.toString(16)}
|
|
(expected 0x${SERVER_SETUP.toString(16)})`);
|
|
|
|
if (type !== SERVER_SETUP) {
|
|
const errorMsg =
|
|
`Server SETUP type must be ${SERVER_SETUP}, got ${type}`;
|
|
shaka.log.error(errorMsg);
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
// Read the 16-bit MSB length field
|
|
const lengthBytes = await this.reader_.read(2);
|
|
const messageLength = (lengthBytes[0] << 8) | lengthBytes[1]; // MSB format
|
|
shaka.log.v1(`Message length (16-bit MSB): ${messageLength} bytes`);
|
|
|
|
// Store the current position to validate length later
|
|
const startPosition = this.reader_.getByteLength();
|
|
|
|
const version = await this.reader_.u53();
|
|
shaka.log.v1(`Server selected version: 0x${version.toString(16)}`);
|
|
|
|
const params = await this.parameters();
|
|
shaka.log.v1(
|
|
`Parameters: ${params ? `${params.length} parameters` : 'none'}`);
|
|
|
|
// Log each parameter in detail
|
|
if (params && params.length > 0) {
|
|
for (const param of params) {
|
|
if (typeof param.value === 'bigint') {
|
|
shaka.log.v1(
|
|
`Parameter ID: ${param.type}, value: ${param.value} (bigint)`);
|
|
} else {
|
|
shaka.log.v1(`Parameter ID: ${param.type}, length:
|
|
${param.value.byteLength} bytes, value:
|
|
${this.formatBytes_(param.value)}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate that we read the expected number of bytes
|
|
const endPosition = this.reader_.getByteLength();
|
|
const bytesRead = startPosition - endPosition;
|
|
|
|
if (bytesRead !== messageLength) {
|
|
const warningMsg = `Message length mismatch: expected ${messageLength}
|
|
bytes, read ${bytesRead} bytes`;
|
|
shaka.log.warning(warningMsg);
|
|
// Not throwing an error here as we've already read the data
|
|
}
|
|
|
|
const result = {
|
|
version,
|
|
params,
|
|
};
|
|
|
|
shaka.log.debug('Server setup message decoded:', result);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param {!Uint8Array} bytes
|
|
* @return {string}
|
|
* @private
|
|
*/
|
|
formatBytes_(bytes) {
|
|
if (bytes.length <= 16) {
|
|
return Array.from(bytes)
|
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
.join(' ');
|
|
} else {
|
|
const start = Array.from(bytes.slice(0, 8))
|
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
.join(' ');
|
|
const end = Array.from(bytes.slice(-8))
|
|
.map((b) => b.toString(16).padStart(2, '0'))
|
|
.join(' ');
|
|
return `${start} ... ${end} (${bytes.length} bytes total)`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return {!Promise<(Array<shaka.msf.Utils.KeyValuePair> | undefined)>}
|
|
*/
|
|
async parameters() {
|
|
const countResult = await this.reader_.u53WithSize();
|
|
const count = countResult.value;
|
|
|
|
shaka.log.v1(`Parameter count: ${count}, count field:
|
|
${countResult.bytesRead} bytes`);
|
|
|
|
if (count === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const params = [];
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
// Read parameter type (key)
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const typeResult = await this.reader_.u62WithSize();
|
|
const paramType = typeResult.value;
|
|
|
|
// Check if the type is even or odd
|
|
const isEven = paramType % BigInt(2) === BigInt(0);
|
|
|
|
if (isEven) {
|
|
// Even type: value is a single var int
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const valueResult = await this.reader_.u62WithSize();
|
|
const value = valueResult.value;
|
|
shaka.log.v1(`Parameter ${i + 1}/${count}: Type ${paramType} (even),
|
|
Value: ${value} (${valueResult.bytesRead} bytes)`);
|
|
|
|
// Check for duplicates
|
|
const existingIndex = params.findIndex((p) => p.type === paramType);
|
|
if (existingIndex !== -1) {
|
|
shaka.log.warning(`Duplicate parameter type: ${paramType},
|
|
overwriting previous value`);
|
|
params.splice(existingIndex, 1);
|
|
}
|
|
|
|
params.push({type: paramType, value});
|
|
} else {
|
|
// Odd type: value is a byte sequence with length
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const lengthResult = await this.reader_.u53WithSize();
|
|
const length = lengthResult.value;
|
|
|
|
// Check maximum length (2^16-1)
|
|
if (length > 65535) {
|
|
const errorMsg =
|
|
`Parameter value length exceeds maximum: ${length} > 65535`;
|
|
shaka.log.error(errorMsg);
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
// Read the value bytes
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const value = await this.reader_.read(length);
|
|
// At this point, value should always be a Uint8Array
|
|
shaka.log.v1(`Parameter ${i + 1}/${count}: Type ${paramType} (odd),
|
|
Length: ${length}, Value: ${this.formatBytes_(value)}`);
|
|
|
|
// Check for duplicates
|
|
const existingIndex = params.findIndex((p) => p.type === paramType);
|
|
if (existingIndex !== -1) {
|
|
shaka.log.warning(`Duplicate parameter type: ${paramType},
|
|
overwriting previous value`);
|
|
params.splice(existingIndex, 1);
|
|
}
|
|
|
|
params.push({type: paramType, value});
|
|
}
|
|
}
|
|
|
|
return params;
|
|
}
|
|
};
|