no commit message
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.hls.controller {
|
||||
import org.mangui.hls.playlist.AltAudioTrack;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.hls.model.AudioTrack;
|
||||
import org.mangui.hls.HLS;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
/*
|
||||
* class that handle audio tracks, consolidating tracks retrieved from Manifest and from Demux
|
||||
*/
|
||||
public class AudioTrackController {
|
||||
/** Reference to the HLS controller. **/
|
||||
private var _hls : HLS;
|
||||
/** list of audio tracks from demuxed fragments **/
|
||||
private var _audioTracksfromDemux : Vector.<AudioTrack>;
|
||||
/** list of audio tracks from Manifest, matching with current level **/
|
||||
private var _audioTracksfromManifest : Vector.<AudioTrack>;
|
||||
/** merged audio tracks list **/
|
||||
private var _audioTracks : Vector.<AudioTrack>;
|
||||
/** current audio track id **/
|
||||
private var _audioTrackId : int;
|
||||
|
||||
public function AudioTrackController(hls : HLS) {
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
|
||||
_hls.addEventListener(HLSEvent.LEVEL_LOADED, _levelLoadedHandler);
|
||||
|
||||
// Prevents crash when reading hls.audioTracks.length before audio tracks are initialized
|
||||
_audioTracks = new Vector.<AudioTrack>();
|
||||
}
|
||||
|
||||
public function dispose() : void {
|
||||
_hls.removeEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
|
||||
_hls.removeEventListener(HLSEvent.LEVEL_LOADED, _levelLoadedHandler);
|
||||
}
|
||||
|
||||
public function set audioTrack(num : int) : void {
|
||||
if (_audioTrackId != num) {
|
||||
_audioTrackId = num;
|
||||
var ev : HLSEvent = new HLSEvent(HLSEvent.AUDIO_TRACK_SWITCH);
|
||||
ev.audioTrack = _audioTrackId;
|
||||
_hls.dispatchEvent(ev);
|
||||
CONFIG::LOGGING {
|
||||
Log.info('Setting audio track to ' + num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get audioTrack() : int {
|
||||
return _audioTrackId;
|
||||
}
|
||||
|
||||
public function get audioTracks() : Vector.<AudioTrack> {
|
||||
return _audioTracks;
|
||||
}
|
||||
|
||||
private function _manifestLoadedHandler(event : HLSEvent) : void {
|
||||
// reset audio tracks
|
||||
_audioTrackId = -1;
|
||||
_audioTracksfromDemux = new Vector.<AudioTrack>();
|
||||
_audioTracksfromManifest = new Vector.<AudioTrack>();
|
||||
_updateAudioTrackforLevel(_hls.loadLevel);
|
||||
_audioTracksMerge();
|
||||
};
|
||||
|
||||
/** Store the manifest data. **/
|
||||
private function _levelLoadedHandler(event : HLSEvent) : void {
|
||||
var level : int = event.loadMetrics.level;
|
||||
if (level == _hls.loadLevel) {
|
||||
_updateAudioTrackforLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
private function _updateAudioTrackforLevel(level : uint) : void {
|
||||
var audioTrackList : Vector.<AudioTrack> = new Vector.<AudioTrack>();
|
||||
var streamId : String = _hls.levels[level].audio_stream_id;
|
||||
// check if audio stream id is set, and alternate audio tracks available
|
||||
if (streamId && _hls.altAudioTracks) {
|
||||
// try to find alternate audio streams matching with this ID
|
||||
for (var idx : int = 0; idx < _hls.altAudioTracks.length; idx++) {
|
||||
var altAudioTrack : AltAudioTrack = _hls.altAudioTracks[idx];
|
||||
if (altAudioTrack.group_id == streamId) {
|
||||
var isDefault : Boolean = (altAudioTrack.default_track == true || altAudioTrack.autoselect == true);
|
||||
CONFIG::LOGGING {
|
||||
Log.debug(" audio track[" + audioTrackList.length + "]:" + (isDefault ? "default:" : "alternate:") + altAudioTrack.name);
|
||||
}
|
||||
audioTrackList.push(new AudioTrack(altAudioTrack.name, AudioTrack.FROM_PLAYLIST, idx, isDefault, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if audio tracks matching with current level have changed since last time
|
||||
var audioTrackChanged : Boolean = false;
|
||||
if (_audioTracksfromManifest.length != audioTrackList.length) {
|
||||
audioTrackChanged = true;
|
||||
} else {
|
||||
for (idx = 0; idx < _audioTracksfromManifest.length; ++idx) {
|
||||
if (_audioTracksfromManifest[idx].id != audioTrackList[idx].id) {
|
||||
audioTrackChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// update audio list
|
||||
if (audioTrackChanged) {
|
||||
_audioTracksfromManifest = audioTrackList;
|
||||
_audioTracksMerge();
|
||||
}
|
||||
}
|
||||
|
||||
// merge audio track info from demux and from manifest into a unified list that will be exposed to upper layer
|
||||
private function _audioTracksMerge() : void {
|
||||
var i : int;
|
||||
var defaultDemux : int = -1;
|
||||
var defaultManifest : int = -1;
|
||||
var defaultFound : Boolean = false;
|
||||
var defaultTrackTitle : String;
|
||||
var audioTrack_ : AudioTrack;
|
||||
_audioTracks = new Vector.<AudioTrack>();
|
||||
|
||||
// first look for default audio track.
|
||||
for (i = 0; i < _audioTracksfromManifest.length; i++) {
|
||||
if (_audioTracksfromManifest[i].isDefault) {
|
||||
defaultManifest = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < _audioTracksfromDemux.length; i++) {
|
||||
if (_audioTracksfromDemux[i].isDefault) {
|
||||
defaultDemux = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* default audio track from manifest should take precedence */
|
||||
if (defaultManifest != -1) {
|
||||
audioTrack_ = _audioTracksfromManifest[defaultManifest];
|
||||
// if URL set, default audio track is not embedded into MPEG2-TS
|
||||
if (_hls.altAudioTracks[audioTrack_.id].url || defaultDemux == -1) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("default audio track found in Manifest");
|
||||
}
|
||||
defaultFound = true;
|
||||
_audioTracks.push(audioTrack_);
|
||||
} else {
|
||||
// empty URL, default audio track is embedded into MPEG2-TS. retrieve track title from manifest and override demux title
|
||||
defaultTrackTitle = audioTrack_.title;
|
||||
if (defaultDemux != -1) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("default audio track signaled in Manifest, will be retrieved from MPEG2-TS");
|
||||
}
|
||||
audioTrack_ = _audioTracksfromDemux[defaultDemux];
|
||||
audioTrack_.title = defaultTrackTitle;
|
||||
defaultFound = true;
|
||||
_audioTracks.push(audioTrack_);
|
||||
}
|
||||
}
|
||||
} else if (defaultDemux != -1 ) {
|
||||
audioTrack_ = _audioTracksfromDemux[defaultDemux];
|
||||
defaultFound = true;
|
||||
_audioTracks.push(audioTrack_);
|
||||
}
|
||||
// then append other audio tracks, start from manifest list, then continue with demux list
|
||||
for (i = 0; i < _audioTracksfromManifest.length; i++) {
|
||||
if (i != defaultManifest) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("alternate audio track found in Manifest");
|
||||
}
|
||||
audioTrack_ = _audioTracksfromManifest[i];
|
||||
_audioTracks.push(audioTrack_);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _audioTracksfromDemux.length; i++) {
|
||||
if (i != defaultDemux) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("alternate audio track retrieved from demux");
|
||||
}
|
||||
audioTrack_ = _audioTracksfromDemux[i];
|
||||
_audioTracks.push(audioTrack_);
|
||||
}
|
||||
}
|
||||
// notify audio track list update
|
||||
_hls.dispatchEvent(new HLSEvent(HLSEvent.AUDIO_TRACKS_LIST_CHANGE));
|
||||
|
||||
// switch track id to default audio track, if found
|
||||
if (defaultFound == true && _audioTrackId == -1) {
|
||||
audioTrack = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** triggered by demux, it should return the audio track to be parsed */
|
||||
public function audioTrackSelectionHandler(audioTrackList : Vector.<AudioTrack>) : AudioTrack {
|
||||
var audioTrackChanged : Boolean = false;
|
||||
audioTrackList = audioTrackList.sort(function(a : AudioTrack, b : AudioTrack) : int {
|
||||
return a.id - b.id;
|
||||
});
|
||||
if (_audioTracksfromDemux.length != audioTrackList.length) {
|
||||
audioTrackChanged = true;
|
||||
} else {
|
||||
for (var idx : int = 0; idx < _audioTracksfromDemux.length; ++idx) {
|
||||
if (_audioTracksfromDemux[idx].id != audioTrackList[idx].id) {
|
||||
audioTrackChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// update audio list if changed
|
||||
if (audioTrackChanged) {
|
||||
_audioTracksfromDemux = audioTrackList;
|
||||
_audioTracksMerge();
|
||||
}
|
||||
|
||||
/* if audio track not defined, or audio from external source (playlist)
|
||||
return null (demux audio not selected) */
|
||||
if (_audioTrackId == -1 || _audioTrackId >= _audioTracks.length || _audioTracks[_audioTrackId].source == AudioTrack.FROM_PLAYLIST) {
|
||||
return null;
|
||||
} else {
|
||||
// source is demux,return selected audio track
|
||||
return _audioTracks[_audioTrackId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user