Implementare la gestione delle sospensioni attività

TVSDK fornisce API e codice di esempio per la gestione dei periodi di sospensione attività.

Per implementare la gestione delle sospensioni attività, inclusa la fornitura di contenuto alternativo durante la sospensione attività:

  1. Configura l'app per rilevare i tag di sospensione attività in un manifesto live stream.

    public void createMediaPlayer {
        ...
        String[] blackoutTags = {BLACKOUTTAG};
        PSDKConfig.setSubscribedTags(blackoutTags);
        // For example: PTSDKConfig.setSubscribedTags({"#EXT-OATCLS-SCTE35"});
    }
    
  2. Creare listener di eventi per eventi di metadati temporizzati nei flussi in primo piano e in background.

    private MediaPlayer createMediaPlayer() {
        mediaPlayer.addEventListener(MediaPlayer.Event.PLAYBACK, _playbackEventListener);
        mediaPlayer.addEventListener(MediaPlayer.Event.BLACKOUTS, _blackoutsEventListener);
    }
    
  3. Implementa gestori eventi metadati temporizzati per flussi in primo piano e in background.

    Primo piano:

    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() {
            ...
        }
    };
    
  4. Maniglia TimedMetadata oggetti quando MediaPlayer il tempo scorre.

    _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);
                        }
                    }
                }
            });
        }
    };
    
  5. Creare metodi per cambiare il contenuto all'inizio e alla fine del periodo di sospensione attività.

    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;
                }
            }
        }
    }
    
  6. Aggiornare gli intervalli non ricercabili se l'intervallo di sospensione attività è in DVR nel flusso di riproduzione.

    // 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];
                }
            }
        }
    }
    
    NOTA

    Attualmente, per flussi live con velocità di trasmissione multipla, occasionalmente i profili ABR (bit-rate regolabile) possono non essere sincronizzati. Questo causa la duplicazione timedMetadata per lo stesso tag sottoscritto. Per evitare calcoli non ricercabili errati, si consiglia vivamente di verificare la presenza di intervalli non ricercabili sovrapposti dopo i calcoli, ad esempio nell’esempio seguente:

    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);
    }
    

In questa pagina