diff --git a/doc/api/Miscellaneous/Local_Contents.md b/doc/api/Miscellaneous/Local_Contents.md index f6bb5f4705..bf83b573ba 100644 --- a/doc/api/Miscellaneous/Local_Contents.md +++ b/doc/api/Miscellaneous/Local_Contents.md @@ -419,6 +419,7 @@ For audio tracks, it can looks like: bitrate: 200000, mimeType: "audio/mp4", codecs: "mp4a.40.5", + isSpatialAudio: false, index: { loadInitSegment(callbacks) { /* ... */ }, loadSegment(segment, callbacks) { /* ... */, @@ -470,6 +471,16 @@ We'll now explain what each property is for, before going deeper into the - height (`number|undefined`): When relevant (mostly video contents), the height of the media, in pixels +- isSpatialAudio (`boolean|undefined`): When relevant (mostly audio contents), + it can be set to `true` if the corresponding media is linked to a spatial + audio technology, for example a content relying on Dolby Atmos technology. + + If set to `false`, it means that it is known that this media does not contain + any spatial audio. + + For cases where you don't know and for cases where no audio is contained, this + can just be left undefined. + - index (`object`): Object allowing the RxPlayer to know the list of segments as well as to fetch them. Described in the next chapter. diff --git a/doc/api/Player_Errors.md b/doc/api/Player_Errors.md index c405903b0c..e380a80f08 100644 --- a/doc/api/Player_Errors.md +++ b/doc/api/Player_Errors.md @@ -352,6 +352,9 @@ contains the following properties: - `codec` (`string|undefined`): The audio codec the Representation is in, as announced in the corresponding Manifest. + - `isSpatialAudio` (`Boolean|undefined`): If set to `true`, this Representation + has spatial audio. + ##### For text tracks When `trackInfo.type` is set to `"text"`, `track` describes a text track. It diff --git a/doc/api/Track_Selection/getAudioTrack.md b/doc/api/Track_Selection/getAudioTrack.md index 3ceb90a34e..347cb1b043 100644 --- a/doc/api/Track_Selection/getAudioTrack.md +++ b/doc/api/Track_Selection/getAudioTrack.md @@ -51,6 +51,9 @@ return an object with the following properties: - `codec` (`string|undefined`): The audio codec the Representation is in, as announced in the corresponding Manifest. + - `isSpatialAudio` (`Boolean|undefined`): If set to `true`, this Representation + has spatial audio. + `undefined` if no audio content has been loaded yet or if its information is unknown. diff --git a/doc/api/Track_Selection/getAvailableAudioTracks.md b/doc/api/Track_Selection/getAvailableAudioTracks.md index 0a439c512d..ab3b7dda0f 100644 --- a/doc/api/Track_Selection/getAvailableAudioTracks.md +++ b/doc/api/Track_Selection/getAvailableAudioTracks.md @@ -47,6 +47,9 @@ Each of the objects in the returned array have the following properties: - `codec` (`string|undefined`): The audio codec the Representation is in, as announced in the corresponding Manifest. + - `isSpatialAudio` (`Boolean|undefined`): If set to `true`, this Representation + has spatial audio. +
Note for multi-Period contents:
diff --git a/src/manifest/representation.ts b/src/manifest/representation.ts index bb371353e5..5c2aae8f2f 100644 --- a/src/manifest/representation.ts +++ b/src/manifest/representation.ts @@ -92,6 +92,19 @@ class Representation { */ public frameRate? : string; + /** + * `true` if this `Representation` is linked to a spatial audio technology. + * For example, it may be set to `true` if the Representation relies on the + * "Dolby Atmos". technology. + * + * `false` if it is known that this `Representation` does not contain any + * spatial audio. + * + * `undefined` if we do not know whether this `Representation` contains + * spatial audio or not. + */ + public isSpatialAudio? : boolean | undefined; + /** * A string describing the codec used for this Representation. * undefined if we do not know. @@ -148,6 +161,10 @@ class Representation { this.bitrate = args.bitrate; this.codec = args.codecs; + if (args.isSpatialAudio !== undefined) { + this.isSpatialAudio = args.isSpatialAudio; + } + if (args.height !== undefined) { this.height = args.height; } @@ -370,8 +387,8 @@ class Representation { * @returns {Object} */ public toAudioRepresentation(): IAudioRepresentation { - const { id, bitrate, codec } = this; - return { id, bitrate, codec }; + const { id, isSpatialAudio, bitrate, codec } = this; + return { id, isSpatialAudio, bitrate, codec }; } /** diff --git a/src/parsers/manifest/dash/common/parse_representations.ts b/src/parsers/manifest/dash/common/parse_representations.ts index 40ca70ca39..8379a7a3f2 100644 --- a/src/parsers/manifest/dash/common/parse_representations.ts +++ b/src/parsers/manifest/dash/common/parse_representations.ts @@ -192,6 +192,16 @@ export default function parseRepresentations( index: representationIndex, id: representationID }; + if ( + representation.children.supplementalProperties !== undefined && + arrayFind(representation.children.supplementalProperties, r => + r.schemeIdUri === "tag:dolby.com,2018:dash:EC3_ExtensionType:2018" && + r.value === "JOC" + ) + ) { + parsedRepresentation.isSpatialAudio = true; + } + // Add optional attributes let codecs : string|undefined; if (representation.attributes.codecs != null) { diff --git a/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts b/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts index 2e642db0d2..2f74e98586 100644 --- a/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts +++ b/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts @@ -93,6 +93,13 @@ function parseRepresentationChildren( contentProtections.push(contentProtection); } break; + case "SupplementalProperty": + if (children.supplementalProperties == null) { + children.supplementalProperties = [parseScheme(currentElement)]; + } else { + children.supplementalProperties.push(parseScheme(currentElement)); + } + break; } } } diff --git a/src/parsers/manifest/dash/node_parser_types.ts b/src/parsers/manifest/dash/node_parser_types.ts index dec2ec3cb7..dc24b076dd 100644 --- a/src/parsers/manifest/dash/node_parser_types.ts +++ b/src/parsers/manifest/dash/node_parser_types.ts @@ -253,6 +253,7 @@ export interface IRepresentationChildren { segmentBase? : ISegmentBaseIntermediateRepresentation; segmentList? : ISegmentListIntermediateRepresentation; segmentTemplate? : ISegmentTemplateIntermediateRepresentation; + supplementalProperties? : IScheme[] | undefined; } /* Intermediate representation for A Representation node's attributes. */ diff --git a/src/parsers/manifest/dash/wasm-parser/ts/generators/Representation.ts b/src/parsers/manifest/dash/wasm-parser/ts/generators/Representation.ts index d7b35707ed..266a16b630 100644 --- a/src/parsers/manifest/dash/wasm-parser/ts/generators/Representation.ts +++ b/src/parsers/manifest/dash/wasm-parser/ts/generators/Representation.ts @@ -84,6 +84,18 @@ export function generateRepresentationChildrenParser( break; } + case TagName.SupplementalProperty: { + const supplementalProperty = {}; + if (childrenObj.supplementalProperties === undefined) { + childrenObj.supplementalProperties = []; + } + childrenObj.supplementalProperties.push(supplementalProperty); + const attributeParser = generateSchemeAttrParser(supplementalProperty, + linearMemory); + parsersStack.pushParsers(nodeId, noop, attributeParser); + break; + } + case TagName.SegmentBase: { const segmentBaseObj = {}; childrenObj.segmentBase = segmentBaseObj; diff --git a/src/parsers/manifest/local/parse_local_manifest.ts b/src/parsers/manifest/local/parse_local_manifest.ts index d2fdf3e76a..488498741a 100644 --- a/src/parsers/manifest/local/parse_local_manifest.ts +++ b/src/parsers/manifest/local/parse_local_manifest.ts @@ -138,6 +138,7 @@ function parseRepresentation( height: representation.height, width: representation.width, codecs: representation.codecs, + isSpatialAudio: representation.isSpatialAudio, mimeType: representation.mimeType, index: new LocalRepresentationIndex(representation.index, id), contentProtections }; diff --git a/src/parsers/manifest/local/types.ts b/src/parsers/manifest/local/types.ts index c76ef4dbe4..32d3b10511 100644 --- a/src/parsers/manifest/local/types.ts +++ b/src/parsers/manifest/local/types.ts @@ -193,6 +193,8 @@ export interface ILocalRepresentation { height? : number; /** Interface allowing to retrieve media segments for this quality. */ index : ILocalIndex; + /** `true` if audio has Dolby Atmos. */ + isSpatialAudio? : boolean; } /** A "track"" of a "local" Manifest. */ diff --git a/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts b/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts index ddc9726644..26894e14e8 100644 --- a/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +++ b/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts @@ -221,6 +221,7 @@ function createManifest( mimeType: currentRepresentation.mimeType, frameRate: currentRepresentation.frameRate, codecs: currentRepresentation.codec, + isSpatialAudio: currentRepresentation.isSpatialAudio, contentProtections: currentRepresentation.contentProtections, }); } diff --git a/src/parsers/manifest/types.ts b/src/parsers/manifest/types.ts index 73332dd8bf..28b8caa0f4 100644 --- a/src/parsers/manifest/types.ts +++ b/src/parsers/manifest/types.ts @@ -158,6 +158,8 @@ export interface IParsedRepresentation { * Information about the HDR characteristic of a content. */ hdrInfo?: IHDRInformation | undefined; + /** `true` if audio has Dolby Atmos. */ + isSpatialAudio?: boolean | undefined; } /** Every possible types an Adaptation can have. */ diff --git a/src/public_types.ts b/src/public_types.ts index c1cd6a919f..60359211d4 100644 --- a/src/public_types.ts +++ b/src/public_types.ts @@ -759,6 +759,7 @@ export interface IBifObject { fileFormat : string; * RxPlayer. */ export interface IAudioRepresentation { id : string|number; + isSpatialAudio? : boolean | undefined; bitrate : number; codec? : string | undefined; }