UNPKG

shaka-player

Version:
156 lines (144 loc) • 5.51 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.msf.draft20.MessageWriter'); goog.require('shaka.msf.draft18.MessageTypeId'); goog.require('shaka.msf.draft18.MessageWriter'); /** * Serializes draft-20 control messages. * * Draft-20 is draft-18 with one message body changed, so this extends the * draft-18 writer and overrides marshalFetch() alone. Everything else -- * the var int type and 16-bit length framing, SETUP, SUBSCRIBE, the parameter * and namespace encodings -- is byte for byte what draft-18 writes. * * The message type IDs this player sends and reads are unchanged too, so there * is no draft-20 copy of the enum. Draft-20 does rename PUBLISH_BLOCKED to * PUBLISH_SKIPPED and reserve PUBLISH_OK (0x1E), but this player sends * neither, so the draft-18 names are the ones in use and renaming them here * would leave two enums to keep in step for no gain. * * Draft-22 changed the LOCATION_FILTER value alone, so it extends this class * and overrides locationFilterValue() and createNestedWriter(). */ shaka.msf.draft20.MessageWriter = class extends shaka.msf.draft18.MessageWriter { /** * Draft-20 removed the Fetch Type field along with the Joining variants, and * moved the range out of the message and into the LOCATION_FILTER parameter, * leaving a body shaped exactly like SUBSCRIBE. * * The range asked for is the same one draft-18 puts in the message, so it * goes out as a filter rather than being dropped: an absent LOCATION_FILTER * means an unfiltered fetch of the whole track (draft-20 section 10.2.9), * which is a different request. * * @override */ marshalFetch(msg) { const range = shaka.msf.draft18.MessageWriter.fetchRange(msg); if (range.end.group < range.start.group) { // Delta encoding cannot express it, and the range is invalid in every // draft of this family anyway. throw new Error( `FETCH end group ${range.end.group} precedes start group ` + `${range.start.group}`); } const params = (msg.params || []).concat([{ type: BigInt(shaka.msf.draft18.MessageWriter.Parameter.LOCATION_FILTER), // With all four fields present the filter is absolute, and EndGroupDelta // is measured from StartGroup rather than from the Largest Object. A // shorter field list would be read as a filter relative to the live edge // instead (draft-20 section 5.1.2). value: this.locationFilterValue([ range.start.group, range.start.object, range.end.group - range.start.group, range.end.object, ]), }]); return this.marshal(shaka.msf.draft18.MessageTypeId.FETCH, () => { this.writeVarInt(msg.requestId); this.writeNamespace(msg.namespace); this.writeString(msg.trackName); this.writeParameters(params); }); } /** * Draft-20 removed the Joining FETCH. A subscriber joins at the current * Group with FILL_PARAMETERS instead: its LOCATION_FILTER, evaluated like a * FETCH's, selects the Groups to fill, and StartGroup alone is relative to * the Next Group, so 1 is the current one (draft-20 section 5.1.6). The * publisher delivers them on a fill fetch stream whose FETCH_HEADER carries * the SUBSCRIBE's Request ID. * * The value is a Parameter list of its own, counted and delta encoded like * the one around it. * * @override */ fillCurrentGroupParam() { const inner = this.createNestedWriter(); inner.writeParameters([{ type: BigInt(shaka.msf.draft18.MessageWriter.Parameter.LOCATION_FILTER), value: this.locationFilterValue([BigInt(1)]), }]); return { type: BigInt(shaka.msf.draft18.MessageWriter.Parameter.FILL_PARAMETERS), value: inner.getBytes(), }; } /** * Draft-20 has no Joining FETCH; fillCurrentGroupParam() is what joins. * * @override */ marshalJoiningFetch(msg) { throw new Error('Draft-20 has no Joining FETCH'); } /** * Draft-20 replaced the Filter Type with a field count: the number of var * ints in the LOCATION_FILTER value is what says which fields are present, * and two of them are a Start Group and a Start Object, absolute and * open-ended (draft-20 section 9.20.10). That is the same request draft-18 * spells as AbsoluteStart, so only the encoding changes here. * * The one reading that is not absolute is two zeroed fields, which mean the * Next Object instead; callers ask for {0, 0} by sending no filter at all, * so it cannot arrive here. * * @override */ locationFilterParam(startLocation) { return { type: BigInt(shaka.msf.draft18.MessageWriter.Parameter.LOCATION_FILTER), value: this.locationFilterValue([ startLocation.group, startLocation.object, ]), }; } /** * The value of a LOCATION_FILTER holding these fields. In draft-20 that is * the fields alone: the parameter's length says how many there are. * * @param {!Array<bigint>} fields * @return {!Uint8Array} * @protected */ locationFilterValue(fields) { return this.encodeVarIntField(fields); } /** * A writer of this draft for a parameter list nested inside another, as * FILL_PARAMETERS carries. * * @return {!shaka.msf.draft20.MessageWriter} * @protected */ createNestedWriter() { return new shaka.msf.draft20.MessageWriter(this.getCodec()); } };