UNPKG

shaka-player

Version:
849 lines (770 loc) 26.6 kB
/*! @license * Shaka Player * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.msf.BufferControlWriter'); goog.require('shaka.msf.Utils'); goog.require('shaka.util.DataViewWriter'); /** * BufferControlWriter class for writing control messages to a buffer * following the draft-14/16 specification. * * The typical pattern is to instantiate the class and call one of the * marshal methods to write a message to the buffer. The format is always: * wire format type, 16-bit length, message fields, etc. */ shaka.msf.BufferControlWriter = class { /** * Creates a new BufferControlWriter with an initial buffer size * @param {!shaka.msf.Utils.Version} version * @param {number=} initialSize */ constructor(version, initialSize = 1024) { /** @private {!shaka.msf.Utils.Version} */ this.version_ = version; /** @private {!shaka.util.DataViewWriter} */ this.writer_ = new shaka.util.DataViewWriter( initialSize, shaka.util.DataViewWriter.Endianness.BIG_ENDIAN); } /** * Gets the current buffer with only the written data * @return {!Uint8Array} */ getBytes() { return this.writer_.getBytes(); } /** * Resets the buffer to start writing from the beginning */ reset() { this.writer_.reset(); } /** * Writes a boolean value as a uint8 to the buffer * @param {boolean} value * @private */ writeBoolAsUint8_(value) { this.writer_.writeUint8(value ? 1 : 0); } /** * Writes an array with a var int length prefix * @param {!Array<T>} array * @param {function(T)} writeFn * @template T * @private */ writeArray_(array, writeFn) { this.writer_.writeVarInt53(array.length); for (const item of array) { writeFn(item); } } /** * Writes a string to the buffer * @param {string} str * @private */ writeString_(str) { this.writer_.writeStringVarInt(str); } /** * Writes a tuple (array of strings) to the buffer * @param {Array<string>} tuple * @private */ writeTuple_(tuple) { this.writeArray_(tuple || [], (element) => { this.writeString_(element); }); } /** * Writes a location to the buffer * @param {shaka.msf.Utils.Location} location * @private */ writeLocation_(location) { this.writer_.writeVarInt62(location.group); this.writer_.writeVarInt62(location.object); } /** * Writes a single key-value pair to the buffer * @param {shaka.msf.Utils.KeyValuePair} pair * @private */ writeKeyValuePair_(pair) { this.writer_.writeVarInt62(pair.type); // Handle the value based on whether the key is odd or even if (pair.type % BigInt(2) === BigInt(0)) { // Even keys have bigint values if (typeof pair.value !== 'bigint') { throw new Error( 'Invalid value type for even key ' + pair.type + ': expected bigint, got ' + typeof pair.value, ); } this.writer_.writeVarInt62(pair.value); } else { // Odd keys have Uint8Array values if (!ArrayBuffer.isView(pair.value)) { throw new Error( 'Invalid value type for odd key ' + pair.type + ': expected Uint8Array or ArrayBuffer view, got ' + typeof pair.value, ); } const bytes = /** @type {!Uint8Array} */ (pair.value); this.writer_.writeVarInt53(bytes.byteLength); this.writer_.writeBytes(bytes); } } /** * Writes an array of key-value pairs to the buffer * @param {(Array<shaka.msf.Utils.KeyValuePair>|undefined)} pairs * @private */ writeKeyValuePairs_(pairs) { const numPairs = pairs ? pairs.length : 0; this.writer_.writeVarInt53(numPairs); if (!pairs || !pairs.length) { return; } for (const pair of pairs) { this.writeKeyValuePair_(pair); } } /** * Writes delta-encoded key-value pairs (draft-16+). * Parameters are sorted by ascending type, then each type is encoded * as a delta from the previous type. * @param {(Array<shaka.msf.Utils.KeyValuePair>|undefined)} pairs * @private */ writeDeltaKeyValuePairs_(pairs) { const numPairs = pairs ? pairs.length : 0; this.writer_.writeVarInt53(numPairs); if (!pairs || !pairs.length) { return; } // Sort by ascending type for delta encoding /** @type {!Array<shaka.msf.Utils.KeyValuePair>} */ const sorted = [...pairs].sort((a, b) => { if (a.type < b.type) { return -1; } if (a.type > b.type) { return 1; } return 0; }); let prevType = BigInt(0); for (const pair of sorted) { // Write delta type const delta = pair.type - prevType; this.writer_.writeVarInt62(delta); prevType = pair.type; if (pair.type % BigInt(2) === BigInt(0)) { // Even keys have bigint values if (typeof pair.value !== 'bigint') { throw new Error( 'Invalid value type for even key ' + pair.type + ': expected bigint, got ' + typeof pair.value, ); } this.writer_.writeVarInt62(pair.value); } else { // Odd keys have Uint8Array values if (!ArrayBuffer.isView(pair.value)) { throw new Error('Invalid value type for odd key ' + pair.type + ': expected Uint8Array'); } const bytes = /** @type {!Uint8Array} */ (pair.value); this.writer_.writeVarInt53(bytes.byteLength); this.writer_.writeBytes(bytes); } } } /** * Writes params using the appropriate encoding for the current version * @param {(Array<shaka.msf.Utils.KeyValuePair>|undefined)} pairs * @private */ writeParams_(pairs) { if (shaka.msf.Utils.isDraft16(this.version_)) { this.writeDeltaKeyValuePairs_(pairs); } else { this.writeKeyValuePairs_(pairs); } } /** * Encodes a subscription filter into bytes for the SUBSCRIPTION_FILTER * parameter * * @param {shaka.msf.Utils.FilterType} filterType * @param {(shaka.msf.Utils.Location|undefined)} startLocation * @param {(bigint|undefined)} endGroup * @return {!Uint8Array} * @private */ encodeFilterBytes_(filterType, startLocation, endGroup) { const tempWriter = new shaka.util.DataViewWriter( /* initialSize= */ 32, shaka.util.DataViewWriter.Endianness.BIG_ENDIAN); tempWriter.writeVarInt53(filterType); if (filterType === shaka.msf.Utils.FilterType.ABSOLUTE_START || filterType === shaka.msf.Utils.FilterType.ABSOLUTE_RANGE) { if (!startLocation) { throw new Error('Missing startLocation for absolute filter'); } tempWriter.writeVarInt62(startLocation.group); tempWriter.writeVarInt62(startLocation.object); } if (filterType === shaka.msf.Utils.FilterType.ABSOLUTE_START) { if (endGroup === undefined) { throw new Error('Missing endGroup for absolute range filter'); } tempWriter.writeVarInt62(endGroup); } return tempWriter.getBytes(); } /** * Helper method to marshal a message with proper type and length * @param {shaka.msf.Utils.MessageTypeId} messageType * @param {function()} writeContent */ marshalWithLength(messageType, writeContent) { this.writer_.writeUint8(messageType); // Reserve space for the 16-bit length field const lengthPosition = this.writer_.getPosition(); this.writer_.writeUint16(0); // Placeholder const contentStart = this.writer_.getPosition(); writeContent(); const contentLength = this.writer_.getPosition() - contentStart; this.writer_.patchUint16(lengthPosition, contentLength); } /** * Helper to marshal a message and return this * @param {shaka.msf.Utils.MessageTypeId} type * @param {function()} fn * @return {!shaka.msf.BufferControlWriter} * @private */ marshal_(type, fn) { this.marshalWithLength(type, fn); return this; } /** * Marshals a Goaway message to the buffer * @param {shaka.msf.Utils.Goaway} msg * @return {!shaka.msf.BufferControlWriter} */ marshalGoaway(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.GOAWAY, () => { this.writeString_(msg.newSessionUri); }); } /** * Marshals a MaxRequestId message to the buffer * @param {shaka.msf.Utils.MaxRequestId} msg * @return {!shaka.msf.BufferControlWriter} */ marshalMaxRequestId(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.MAX_REQUEST_ID, () => { this.writer_.writeVarInt62(msg.requestId); }); } /** * Marshals a RequestsBlocked message to the buffer * @param {shaka.msf.Utils.RequestsBlocked} msg * @return {!shaka.msf.BufferControlWriter} */ marshalRequestsBlocked(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.REQUESTS_BLOCKED, () => { this.writer_.writeVarInt62(msg.maximumRequestId); }); } /** * Marshals a Subscribe message to the buffer * @param {shaka.msf.Utils.Subscribe} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribe(msg) { if (shaka.msf.Utils.isDraft16(this.version_)) { return this.marshalSubscribeDraft16_(msg); } return this.marshalSubscribeDraft14_(msg); } /** * Marshals a Subscribe message to the buffer * @param {shaka.msf.Utils.Subscribe} msg * @return {!shaka.msf.BufferControlWriter} * @private */ marshalSubscribeDraft14_(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE, () => { this.writer_.writeVarInt62(msg.requestId); this.writeTuple_(msg.namespace); this.writeString_(msg.name); this.writer_.writeUint8(msg.subscriberPriority); this.writer_.writeUint8(msg.groupOrder); this.writeBoolAsUint8_(msg.forward); this.writer_.writeUint8(msg.filterType); if (msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_START || msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_RANGE) { if (!msg.startLocation) { throw new Error('Missing startLocation for absolute filter'); } this.writeLocation_(msg.startLocation); } if (msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_RANGE) { if (!msg.endGroup) { throw new Error('Missing endGroup for absolute range filter'); } this.writer_.writeVarInt62(msg.endGroup); } this.writeKeyValuePairs_(msg.params); }); } /** * Marshals a Subscribe message to the buffer * @param {shaka.msf.Utils.Subscribe} msg * @return {!shaka.msf.BufferControlWriter} * @private */ marshalSubscribeDraft16_(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE, () => { this.writer_.writeVarInt62(msg.requestId); this.writeTuple_(msg.namespace); this.writeString_(msg.name); /** @type {!Array<shaka.msf.Utils.KeyValuePair>} */ const params = msg.params || []; const PARAM_FORWARD = BigInt(0x10); const PARAM_SUBSCRIBER_PRIORITY = BigInt(0x20); const PARAM_SUBSCRIPTION_FILTER = BigInt(0x21); const PARAM_GROUP_ORDER = BigInt(0x22); params.push({ type: PARAM_FORWARD, value: BigInt(msg.forward ? 1 : 0), }); params.push({ type: PARAM_SUBSCRIBER_PRIORITY, value: BigInt(msg.subscriberPriority), }); const filterType = /** @type {shaka.msf.Utils.FilterType} */(msg.filterType); params.push({ type: PARAM_SUBSCRIPTION_FILTER, value: this.encodeFilterBytes_( filterType, msg.startLocation, msg.endGroup), }); params.push({ type: PARAM_GROUP_ORDER, value: BigInt(msg.groupOrder), }); this.writeDeltaKeyValuePairs_(params); }); } /** * Marshals a SubscribeOk message to the buffer * @param {shaka.msf.Utils.SubscribeOk} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeOk(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_OK, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.expires); this.writer_.writeUint8(msg.groupOrder); this.writeBoolAsUint8_(msg.contentExists); if (msg.contentExists) { if (!msg.largest) { throw new Error('Missing largest for contentExists'); } this.writeLocation_(msg.largest); } this.writeParams_(msg.params); }); } /** * Marshals a SubscribeError message to the buffer * @param {shaka.msf.Utils.SubscribeError} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeError(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_ERROR, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); if (shaka.msf.Utils.isDraft16(this.version_)) { // Draft-16 REQUEST_ERROR: includes retryInterval this.writer_.writeVarInt62(msg.retryInterval ?? BigInt(0)); } this.writeString_(msg.reason); }); } /** * Marshals a SubscribeUpdate / REQUEST_UPDATE message to the buffer * @param {shaka.msf.Utils.SubscribeUpdate} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeUpdate(msg) { if (shaka.msf.Utils.isDraft16(this.version_)) { return this.marshalSubscribeUpdateDraft16_(msg); } return this.marshalSubscribeUpdateDraft14_(msg); } /** * Marshals a SubscribeUpdate / REQUEST_UPDATE message to the buffer * @param {shaka.msf.Utils.SubscribeUpdate} msg * @return {!shaka.msf.BufferControlWriter} * @private */ marshalSubscribeUpdateDraft14_(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_UPDATE, () => { this.writer_.writeVarInt62(msg.requestId); this.writeLocation_(msg.startLocation); this.writer_.writeVarInt62(msg.endGroup); this.writer_.writeUint8(msg.subscriberPriority); this.writeBoolAsUint8_(msg.forward); this.writeKeyValuePairs_(msg.params); }); } /** * Marshals a SubscribeUpdate / REQUEST_UPDATE message to the buffer * @param {shaka.msf.Utils.SubscribeUpdate} msg * @return {!shaka.msf.BufferControlWriter} * @private */ marshalSubscribeUpdateDraft16_(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_UPDATE, () => { this.writer_.writeVarInt62(msg.requestId); /** @type {!Array<shaka.msf.Utils.KeyValuePair>} */ const params = msg.params || []; const PARAM_FORWARD = BigInt(0x10); const PARAM_SUBSCRIBER_PRIORITY = BigInt(0x20); const PARAM_SUBSCRIPTION_FILTER = BigInt(0x21); params.push({ type: PARAM_FORWARD, value: BigInt(msg.forward ? 1 : 0), }); params.push({ type: PARAM_SUBSCRIBER_PRIORITY, value: BigInt(msg.subscriberPriority), }); // Encode filter const filterType = msg.endGroup > BigInt(0) ? shaka.msf.Utils.FilterType.ABSOLUTE_RANGE : shaka.msf.Utils.FilterType.ABSOLUTE_START; params.push({ type: PARAM_SUBSCRIPTION_FILTER, value: this.encodeFilterBytes_( filterType, msg.startLocation, msg.endGroup), }); this.writeDeltaKeyValuePairs_(params); }); } /** * Marshals an Unsubscribe message to the buffer * @param {shaka.msf.Utils.Unsubscribe} msg * @return {!shaka.msf.BufferControlWriter} */ marshalUnsubscribe(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.UNSUBSCRIBE, () => { this.writer_.writeVarInt62(msg.requestId); }); } /** * Marshals a PublishDone message to the buffer * @param {shaka.msf.Utils.PublishDone} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishDone(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_DONE, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); this.writer_.writeVarInt53(msg.streamCount); }); } /** * Marshals a Publish message to the buffer * @param {shaka.msf.Utils.Publish} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublish(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH, () => { this.writer_.writeVarInt62(msg.requestId); this.writeTuple_(msg.namespace); this.writeString_(msg.name); this.writer_.writeVarInt62(msg.trackAlias); this.writer_.writeUint8(msg.groupOrder); this.writeBoolAsUint8_(msg.contentExists); if (msg.contentExists) { if (!msg.largestLocation) { throw new Error('Missing largestLocation for contentExists'); } this.writeLocation_(msg.largestLocation); } this.writeBoolAsUint8_(msg.forward); this.writeParams_(msg.params); }); } /** * Marshals a PublishOk message to the buffer * @param {shaka.msf.Utils.PublishOk} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishOk(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_OK, () => { this.writer_.writeVarInt62(msg.requestId); this.writeBoolAsUint8_(msg.forward); this.writer_.writeUint8(msg.subscriberPriority); this.writer_.writeUint8(msg.groupOrder); this.writer_.writeUint8(msg.filterType); if (msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_START || msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_RANGE) { if (!msg.startLocation) { throw new Error('Missing startLocation for absolute filter'); } this.writeLocation_(msg.startLocation); } if (msg.filterType === shaka.msf.Utils.FilterType.ABSOLUTE_RANGE) { if (!msg.endGroup) { throw new Error('Missing endGroup for absolute range filter'); } this.writer_.writeVarInt62(msg.endGroup); } this.writeParams_(msg.params); }); } /** * Marshals a PublishError message to the buffer * @param {shaka.msf.Utils.PublishError} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishError(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_ERROR, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); }); } /** * Marshals a Fetch message to the buffer (standalone fetch type) * @param {shaka.msf.Utils.Fetch} msg * @return {!shaka.msf.BufferControlWriter} */ marshalFetch(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.FETCH, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeUint8(msg.subscriberPriority); this.writer_.writeUint8(msg.groupOrder); this.writer_.writeVarInt62(BigInt(msg.fetchType)); // Standalone fetch includes namespace, trackName, start/end this.writeTuple_(msg.namespace); this.writeString_(msg.trackName); this.writer_.writeVarInt62(msg.startGroup); this.writer_.writeVarInt62(msg.startObject); this.writer_.writeVarInt62(msg.endGroup); this.writer_.writeVarInt62(msg.endObject); this.writeParams_(msg.params); }); } /** * Marshals a Fetch message to the buffer (standalone fetch type) * @param {shaka.msf.Utils.FetchOk} msg * @return {!shaka.msf.BufferControlWriter} */ marshalFetchOk(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.FETCH, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeUint8(msg.groupOrder); this.writer_.writeVarInt62(BigInt(msg.endOfTrack)); this.writer_.writeVarInt62(msg.endGroup); this.writer_.writeVarInt62(msg.endObject); this.writeParams_(msg.params); }); } /** * Marshals a FetchError message to the buffer * @param {shaka.msf.Utils.FetchError} msg * @return {!shaka.msf.BufferControlWriter} */ marshalFetchError(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.FETCH_ERROR, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); }); } /** * Marshals a FetchCancel message to the buffer * @param {shaka.msf.Utils.FetchCancel} msg * @return {!shaka.msf.BufferControlWriter} */ marshalFetchCancel(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.FETCH_CANCEL, () => { this.writer_.writeVarInt62(msg.requestId); }); } /** * Marshals an PublishNamespace message to the buffer * @param {shaka.msf.Utils.PublishNamespace} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishNamespace(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_NAMESPACE, () => { this.writer_.writeVarInt62(msg.requestId); this.writeTuple_(msg.namespace); this.writeParams_(msg.params); }); } /** * Marshals an PublishNamespaceOk / REQUEST_OK message to the buffer * @param {shaka.msf.Utils.PublishNamespaceOk} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishNamespaceOk(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_NAMESPACE_OK, () => { this.writer_.writeVarInt62(msg.requestId); if (shaka.msf.Utils.isDraft16(this.version_)) { // Draft-16 REQUEST_OK includes parameters this.writeDeltaKeyValuePairs_([]); } }); } /** * Marshals an PublishNamespaceError message to the buffer * @param {shaka.msf.Utils.PublishNamespaceError} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishNamespaceError(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_NAMESPACE_ERROR, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); }); } /** * Marshals an PublishNamespaceDone message to the buffer * @param {shaka.msf.Utils.PublishNamespaceDone} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishNamespaceDone(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_NAMESPACE_DONE, () => { this.writeTuple_(msg.namespace); }); } /** * Marshals an PublishNamespaceCancel message to the buffer * @param {shaka.msf.Utils.PublishNamespaceCancel} msg * @return {!shaka.msf.BufferControlWriter} */ marshalPublishNamespaceCancel(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.PUBLISH_NAMESPACE_CANCEL, () => { this.writeTuple_(msg.namespace); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); }); } /** * Marshals an SubscribeNamespace message to the buffer * @param {shaka.msf.Utils.SubscribeNamespace} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeNamespace(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_NAMESPACE, () => { this.writer_.writeVarInt62(msg.requestId); this.writeTuple_(msg.namespace); this.writeParams_(msg.params); }); } /** * Marshals an SubscribeNamespaceOk message to the buffer * @param {shaka.msf.Utils.SubscribeNamespaceOk} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeNamespaceOk(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_NAMESPACE_OK, () => { this.writer_.writeVarInt62(msg.requestId); }); } /** * Marshals an SubscribeNamespaceError message to the buffer * @param {shaka.msf.Utils.SubscribeNamespaceError} msg * @return {!shaka.msf.BufferControlWriter} */ marshalSubscribeNamespaceError(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SUBSCRIBE_NAMESPACE_ERROR, () => { this.writer_.writeVarInt62(msg.requestId); this.writer_.writeVarInt62(msg.code); this.writeString_(msg.reason); }); } /** * Marshals an UnsubscribeNamespace message to the buffer * @param {shaka.msf.Utils.UnsubscribeNamespace} msg * @return {!shaka.msf.BufferControlWriter} */ marshalUnsubscribeNamespace(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.UNSUBSCRIBE_NAMESPACE, () => { this.writeTuple_(msg.namespace); }); } /** * Marshals a Client setup message to the buffer * @param {shaka.msf.Utils.ClientSetup} msg * @return {!shaka.msf.BufferControlWriter} */ marshalClientSetup(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.CLIENT_SETUP, () => { if (!shaka.msf.Utils.isDraft16(this.version_)) { // Draft-14: include version list for in-band negotiation this.writeArray_(msg.versions || [], (version) => this.writer_.writeVarInt53(version)); } this.writeParams_(msg.params); }); } /** * Marshals a Server setup message to the buffer * @param {shaka.msf.Utils.ServerSetup} msg * @return {!shaka.msf.BufferControlWriter} */ marshalServerSetup(msg) { const MessageTypeId = shaka.msf.Utils.MessageTypeId; return this.marshal_(MessageTypeId.SERVER_SETUP, () => { if (!shaka.msf.Utils.isDraft16(this.version_)) { // Draft-14: include selected version this.writer_.writeVarInt53(msg.version); } // Draft-16 omits selected version (negotiated via protocol) this.writeParams_(msg.params); }); } };