Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add audio codec to selectAudioLanguage() #6723

Merged
merged 7 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion lib/media/adaptation_set_criteria.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ shaka.media.PreferenceBasedCriteria = class {
* @param {string=} videoLabel
* @param {shaka.config.CodecSwitchingStrategy=} codecSwitchingStrategy
* @param {boolean=} enableAudioGroups
* @param {string=} audioCodec
*/
constructor(language, role, channelCount, hdrLevel, spatialAudio,
videoLayout, audioLabel = '', videoLabel = '',
codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD,
enableAudioGroups = false) {
enableAudioGroups = false, audioCodec = '') {
/** @private {string} */
this.language_ = language;
/** @private {string} */
Expand All @@ -140,6 +141,8 @@ shaka.media.PreferenceBasedCriteria = class {
this.codecSwitchingStrategy_ = codecSwitchingStrategy;
/** @private {boolean} */
this.enableAudioGroups_ = enableAudioGroups;
/** @private {string} */
this.audioCodec_ = audioCodec;
}

/** @override */
Expand Down Expand Up @@ -229,6 +232,16 @@ shaka.media.PreferenceBasedCriteria = class {
shaka.log.warning('No exact match for spatial audio could be found.');
}

if (this.audioCodec_) {
const byAudioCodec = Class.filterVariantsByAudioCodec_(
current, this.audioCodec_);
if (byAudioCodec.length) {
current = byAudioCodec;
} else {
shaka.log.warning('No exact match for audio codec could be found.');
}
}

const supportsSmoothCodecTransitions = this.codecSwitchingStrategy_ ==
shaka.config.CodecSwitchingStrategy.SMOOTH &&
shaka.media.Capabilities.isChangeTypeSupported();
Expand Down Expand Up @@ -403,4 +416,21 @@ shaka.media.PreferenceBasedCriteria = class {
return true;
});
}


/**
* Filters variants according to the given audio codec.
*
* @param {!Array<shaka.extern.Variant>} variants
* @param {string} audioCodec
* @private
*/
static filterVariantsByAudioCodec_(variants, audioCodec) {
return variants.filter((variant) => {
if (variant.audio && variant.audio.codecs != audioCodec) {
return false;
}
return true;
});
}
};
7 changes: 5 additions & 2 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -4702,9 +4702,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
* @param {string=} role
* @param {number=} channelsCount
* @param {number=} safeMargin
* @param {string=} codec
* @export
*/
selectAudioLanguage(language, role, channelsCount = 0, safeMargin = 0) {
selectAudioLanguage(language, role, channelsCount = 0, safeMargin = 0,
codec = '') {
if (this.manifest_ && this.playhead_) {
this.currentAdaptationSetCriteria_ =
new shaka.media.PreferenceBasedCriteria(
Expand All @@ -4717,7 +4719,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
/* audioLabel= */ '',
/* videoLabel= */ '',
this.config_.mediaSource.codecSwitchingStrategy,
this.config_.manifest.dash.enableAudioGroups);
this.config_.manifest.dash.enableAudioGroups,
codec);

const diff = (a, b) => {
if (!a.video && !b.video) {
Expand Down
33 changes: 33 additions & 0 deletions test/media/adaptation_set_criteria_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,39 @@ describe('AdaptationSetCriteria', () => {
manifest.variants[2],
]);
});

it('chooses variants with preferred audio codec', () => {
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(1, (variant) => {
variant.addAudio(10, (stream) => {
stream.codecs = 'mp4a.40.2';
});
});
manifest.addVariant(2, (variant) => {
variant.addAudio(20, (stream) => {
stream.codecs = 'ec-3';
});
});
});

const builder = new shaka.media.PreferenceBasedCriteria(
/* language= */ 'en',
/* role= */ '',
/* channelCount= */ 0,
/* hdrLevel= */ '',
/* spatialAudio= */ false,
/* videoLayout= */ '',
/* audioLabel= */ '',
/* videoLabel= */ '',
shaka.config.CodecSwitchingStrategy.RELOAD,
/* enableAudioGroups= */ false,
/* audioCodec= */ 'ec-3');
const set = builder.create(manifest.variants);

checkSet(set, [
manifest.variants[1],
]);
});
});

/**
Expand Down
107 changes: 107 additions & 0 deletions test/player_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,25 @@ describe('Player', () => {
variant.addExistingStream(2); // video
variant.addExistingStream(6); // audio
});
manifest.addVariant(108, (variant) => { // spanish ec-3, low res
variant.language = 'es';
variant.bandwidth = 1100;
variant.addExistingStream(1); // video
variant.addAudio(7, (stream) => {
stream.mime('audio/mp4', 'ec-3');
stream.originalId = 'audio-es-ec3';
stream.bandwidth = 100;
stream.channelsCount = 2;
stream.audioSamplingRate = 48000;
// stream.codecs = 'ec-3';
});
});
manifest.addVariant(109, (variant) => { // spanish ec-3, high res
variant.language = 'es';
variant.bandwidth = 2100;
variant.addExistingStream(2); // video
variant.addExistingStream(7); // audio
});

// All text tracks should remain, even with different MIME types.
manifest.addTextStream(50, (stream) => {
Expand Down Expand Up @@ -1884,6 +1903,86 @@ describe('Player', () => {
originalImageId: null,
accessibilityPurpose: undefined,
},
{
id: 108,
active: false,
type: 'variant',
bandwidth: 1100,
language: 'es',
originalLanguage: 'es',
label: null,
kind: null,
width: 100,
height: 200,
frameRate: 1000000 / 42000,
pixelAspectRatio: '59:54',
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: 'video/mp4',
audioMimeType: 'audio/mp4',
videoMimeType: 'video/mp4',
codecs: 'avc1.4d401f, ec-3',
audioCodec: 'ec-3',
videoCodec: 'avc1.4d401f',
primary: false,
roles: ['main'],
audioRoles: [],
forced: false,
videoId: 1,
audioId: 7,
channelsCount: 2,
audioSamplingRate: 48000,
spatialAudio: false,
tilesLayout: null,
audioBandwidth: 100,
videoBandwidth: 1000,
originalAudioId: 'audio-es-ec3',
originalVideoId: 'video-1kbps',
originalTextId: null,
originalImageId: null,
accessibilityPurpose: undefined,
},
{
id: 109,
active: false,
type: 'variant',
bandwidth: 2100,
language: 'es',
originalLanguage: 'es',
label: null,
kind: null,
width: 200,
height: 400,
frameRate: 24,
pixelAspectRatio: '59:54',
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: 'video/mp4',
audioMimeType: 'audio/mp4',
videoMimeType: 'video/mp4',
codecs: 'avc1.4d401f, ec-3',
audioCodec: 'ec-3',
videoCodec: 'avc1.4d401f',
primary: false,
roles: [],
audioRoles: [],
forced: false,
videoId: 2,
audioId: 7,
channelsCount: 2,
audioSamplingRate: 48000,
spatialAudio: false,
tilesLayout: null,
audioBandwidth: 100,
videoBandwidth: 2000,
originalAudioId: 'audio-es-ec3',
originalVideoId: 'video-2kbps',
originalTextId: null,
originalImageId: null,
accessibilityPurpose: undefined,
},
];

textTracks = [
Expand Down Expand Up @@ -2174,6 +2273,14 @@ describe('Player', () => {
expect(getActiveVariantTrack().roles).toContain('commentary');
});

it('selectAudioLanguage() respects selected audio codec', () => {
player.selectAudioLanguage('es', '', 0, 0, 'mp4a.40.2');
expect(getActiveVariantTrack().audioCodec).toBe('mp4a.40.2');

player.selectAudioLanguage('es', '', 0, 0, 'ec-3');
expect(getActiveVariantTrack().audioCodec).toBe('ec-3');
});

it('selectAudioLanguage() applies role only to audio', () => {
expect(getActiveVariantTrack().roles).not.toContain('commentary');
player.selectAudioLanguage('en', 'commentary');
Expand Down
15 changes: 10 additions & 5 deletions ui/audio_language_selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
(track) => this.onAudioTrackSelected_(track),
/* updateChosen= */ true, this.currentSelection, this.localization,
this.controls.getConfig().trackLabelFormat,
this.controls.getConfig().showAudioChannelCountVariants);
this.controls.getConfig().showAudioChannelCountVariants,
this.controls.getConfig().showAudioCodecs);
shaka.ui.Utils.focusOnTheChosenItem(this.menu);

this.controls.dispatchEvent(
Expand All @@ -93,13 +94,17 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
* @private
*/
onAudioTrackSelected_(track) {
let channelsCount = undefined;
if (track.channelsCount &&
this.controls.getConfig().showAudioChannelCountVariants) {
this.player.selectAudioLanguage(
track.language, track.roles[0], track.channelsCount);
} else {
this.player.selectAudioLanguage(track.language, track.roles[0]);
channelsCount = track.channelsCount;
}
let codec = undefined;
if (track.audioCodec && this.controls.getConfig().showAudioCodecs) {
codec = track.audioCodec;
}
this.player.selectAudioLanguage(track.language, track.roles[0],
channelsCount, /* safeMargin= */ 0, codec);
}


Expand Down
6 changes: 6 additions & 0 deletions ui/externs/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ shaka.extern.UIVolumeBarColors;
* fullScreenElement: HTMLElement,
* preferDocumentPictureInPicture: boolean,
* showAudioChannelCountVariants: boolean,
* showAudioCodecs: boolean,
* seekOnTaps: boolean,
* tapSeekDistance: number,
* refreshTickInSeconds: number,
Expand Down Expand Up @@ -223,6 +224,11 @@ shaka.extern.UIVolumeBarColors;
* displayed or if, on the contrary, only the language should be displayed
* regardless of the channel count.
* Defaults to true.
* @property {boolean} showAudioCodecs
* Indicates whether the combination of language and audio codec should be
* displayed or if, on the contrary, only the language should be displayed
* regardless of the audio codec.
* Defaults to false.
* @property {boolean} seekOnTaps
* Indicates whether or not a fast-forward and rewind tap button that seeks
* video some seconds.
Expand Down
Loading
Loading