TVSDK提供API以及處理中斷期間的範常式式碼。
若要實施中斷處理,包括在中斷期間提供替代內容:
設定應用程式以偵測即時資料流資訊清單中的中斷標籤。
public void createMediaPlayer {
...
String[] blackoutTags = {BLACKOUTTAG};
PSDKConfig.setSubscribedTags(blackoutTags);
// For example: PTSDKConfig.setSubscribedTags({"#EXT-OATCLS-SCTE35"});
}
為前景和背景資料流中的定時中繼資料事件建立事件接聽程式。
private MediaPlayer createMediaPlayer() {
mediaPlayer.addEventListener(MediaPlayer.Event.PLAYBACK, _playbackEventListener);
mediaPlayer.addEventListener(MediaPlayer.Event.BLACKOUTS, _blackoutsEventListener);
}
針對前景和背景資料流,實作計時中繼資料事件處理常式。
前景:
private final MediaPlayer.PlaybackEventListener _playbackEventListener =
new MediaPlayer.PlaybackEventListener() {
...
@override
public void onTimedMetadata(TimedMetadata timedMetadata) {
if (timedMetadata.getName().equal(BLACKOUTTAG) &&
!_timedMetadataList.contains(timedMetadata)) {
_timedMetadataList.add(timedMetadata);
}
}
...
}
private final MediaPlayer.BlackoutsEventListener _blackoutsEventListener =
new MediaPlayer.BlackoutsEventListener() {
@Override
public void onTimedMetadataInBackgroundItem(TimedMetadata timedMetadata) {
TimedMetadata.Type type = timedMetadata.getType();
if (type.equals(TimedMetadata.Type.TAG) && _mediaPlayer.getPlaybackRange() != null
&& _mediaPlayer.getPlaybackRange().getDuration() > 0) {
if (!_timedMetadataList.contains(timedMetadata) && isBlackoutMetadata(timedMetadata)) {
_timedMetadataList.add(timedMetadata);
}
}
}
@Override
public void onBackgroundManifestFailed() {
...
}
};
控點 TimedMetadata
物件,當 MediaPlayer
時間執行。
_playbackClockEventListener = new Clock.ClockEventListener() {
@Override
public void onTick(String name) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
/* handle timedmetadata object list */
if (_mediaPlayer != null && _timedMetadataList != null
&& _timedMetadataList.size() > 0) {
if (_lastKnownStatus == MediaPlayer.PlayerState.PLAYING) {
long localTime = _mediaPlayer.getLocalTime();
handleTimedMetadataList(localTime);
}
}
}
});
}
};
建立用於在中斷期間開始和結束時切換內容的方法。
private void handleTimedMetadataList(long currentTime) {
for (int i = 0; i < _timedMetadataList.size(); i++) {
TimedMetadata timedMetadata = _timedMetadataList.get(i);
long diff = localTime - timedMetadata.getTime();
if (!_timedMetadataDispatchedList.contains(timedMetadata)
&& diff >= 0
&& diff <= PLAYBACK_CLOCK_INTERVAL
&& _mediaPlayer.shouldTriggerSubscribedTagEvent()) {
// switch to blackout content
if (!_inBlackout && isBlackoutStartTimedMetadata(timedMetadata)) {
MediaResource blackoutMediaResource = createBlackoutMediaResource(timedMetadata);
//1. register current item as background item
_mediaPlayer.registerCurrentItemAsBackgroundItem();
//2. replace current item with blackout item
_mediaPlayer.replaceCurrentItem(blackoutMediaResource);
//3. update qos metrics
_mediaQosProvider.updateMetrics(_mediaPlayer);
//4. maintain state
_inBlackout = true;
resetTimedMetada();
break;
}
// switch back to main content
else if (_inBlackout && isBlackoutEndTimedMetadata(timedMetadata)) {
//1. register current item as background item
_mediaPlayer.unregisterCurrentBackgroundItem();
//2. replace current item with blackout item
_mediaPlayer.replaceCurrentItem(_oldMediaResource);
//3. update qos metrics
_mediaQosProvider.updateMetrics(_mediaPlayer);
//4. maintain state
_inBlackout = false;
resetTimedMetada();
break;
}
}
}
}
如果中斷範圍在播放資料流的DVR中,請更新不可搜尋的範圍。
// prepare and update blackout nonSeekable ranges
List<TimeRange> blackoutRanges = prepareBlackoutRanges(_timedMetadataList);
if (blackoutRanges != null && blackoutRanges.size() > 0) {
int size = blackoutRanges.size();
TimeRange[] blackoutRangesArray = blackoutRanges.toArray(new TimeRange[size]);
BlackoutMetadata blackoutMetadata = new BlackoutMetadata(blackoutRangesArray);
updateBlackoutMetadata(blackoutMetadata);
}
// function to update blackout metadata
private void updateBlackoutMetadata(BlackoutMetadata blackoutMetadata) {
MediaPlayerItem currentItem = _mediaPlayer.getCurrentItem();
if (currentItem != null) {
Metadata metadata = currentItem.getResource().getMetadata();
if (metadata != null) {
MetadataNode metadataNode = ((MetadataNode) metadata);
metadataNode.setNode(DefaultMetadataKeys.BLACKOUT_METADATA_KEY.getValue(),
blackoutMetadata);
for (int i = 0; i < blackoutMetadata.getNonSeekableRanges().length; i++) {
TimeRange timeRange = blackoutMetadata.getNonSeekableRanges()[i];
}
}
}
}
目前對於多個位元速率即時資料流,有時可調整位元速率(ABR)設定檔可能會不同步。 這會導致重複 timedMetadata
相同訂閱標籤的物件。 為了避免不正確的不可搜尋計算,強烈建議您在計算之後檢查是否有重疊的不可搜尋範圍,例如以下範例中:
List<TimeRange> rangesToRemove = new ArrayList<TimeRange>();
for (int i = 0; i < nonSeekableRanges.size() - 1; i++) {
TimeRange range1 = nonSeekableRanges.get(i);
TimeRange range2 = nonSeekableRanges.get(i + 1);
if (range1.contains(range2.getBegin()) && !rangesToRemove.contains(range2)) {
rangesToRemove.add(range2);
} else if (range2.contains(range1.getBegin()) && !rangesToRemove.contains(range1)) {
rangesToRemove.add(range1);
}
}
if (nonSeekableRanges.size() > 0 && rangesToRemove.size() > 0) {
nonSeekableRanges.removeAll(rangesToRemove);
for (int i = 0; i < rangesToRemove.size(); i++) {
TimeRange range = rangesToRemove.get(i);
}
}
if (nonSeekableRanges.size() > 0 && rangesToRemove.size() > 0) {
nonSeekableRanges.removeAll(rangesToRemove);
}