實施封鎖處理

TVSDK提供API和范常式式碼,以處理封鎖期。

要實施封鎖期處理並在封鎖期間提供替代內容,請執行以下操作:

  1. 設定您的應用程式以訂閱即時串流資訊清單中的封鎖標籤。
 - (void) createMediaPlayer:(PTMediaPlayerItem *)item
 {
     [PTSDKConfig setSubscribedTags:[NSArray arrayWithObject:<INSERT-BLACKOUT-TAG>]];
     // For example:
     // [PTSDKConfig setSubscribedTags:[NSArray arrayWithObject:@"#EXT-OATCLS-SCTE35"]];
 }
  1. PTTimedMetadataChangedNotification添加通知偵聽程式。

    - (void)addobservers
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaPlayerSubscribedTagIdentified:)
          name:PTTimedMetadataChangedNotification object:self.player.currentItem];
    }
    
  2. 在前景中實現PTTimedMetadata對象的監聽器方法。

    例如:

    - (void)onMediaPlayerSubscribedTagIdentified:(NSNotification *)notification
    {
        NSDictionary *userInfo = [notification userInfo];
        PTTimedMetadata *timedMetadata = [(PTTimedMetadata *)[userInfo objectForKey:PTTimedMetadataKey]
          retain];
    
     if ([timedMetadata.name isEqualToString:<INSERT-BLACKOUT-TAG>])
        {
         // handle tag. For example: store it in a dictionary keyed by time to be handled when
         //   playback time = timedMetadata time.
            NSNumber *timedMetadataStartTime =
              [NSNumber numberWithInt:(int)CMTimeGetSeconds(timedMetadata.time)];
            [timedMetadataCollection setObject:timedMetadata forKey:timedMetadataStartTime];
        }
    
        [timedMetadata release];
    }
    
  3. 在播放期間使用持續更新來處理TimedMetadata物件。

    - (void)onMediaPlayerTimeChange:(NSNotification *)notification
    {
        @synchronized(self)
        {
            CMTimeRange seekableRange = self.player.seekableRange;
            if (CMTIMERANGE_IS_VALID(seekableRange))
            {
                _currentTime = (int) CMTimeGetSeconds(self.player.currentTime);
                if (isnan(_currentTime))
                {
                    _currentTime = 0;
                }
                [self handleCollectionAtTime:_currentTime];
            }
        }
    }
    
  4. 新增PTTimedMetadata處理常式,以切換至替代內容,並返回主要內容,如PTTimedMetadata物件及其播放時間所示。

    - (void)handleCollectionAtTime:(int)currentTime
    {
        NSArray *allKeys = nil;
        NSMutableArray * timedMetadatasToDelete = [[[NSMutableArray alloc]init]autorelease];
    
        if (!_inBlackout && timedMetadataCollection)
        {
            allKeys = [timedMetadataCollection allKeys];
            int count = [allKeys count];
            for (int i=count-1; i>-1; i--)
            {
                NSNumber *currTimedMetadataTime = allKeys[i];
                PTTimedMetadata *currTimedMetadata =
                  [timedMetadataCollection objectForKey:currTimedMetadataTime];
    
                if (currentTime == [currTimedMetadataTime integerValue] &&
                                   currTimedMetadata.name == <INSERT-BLACKOUT-TAG> &&
                                   [self isBlackoutStart: currTimedMetadata])
                {
                                    PTAdMetadata *newItemAdMetadata =
                                      [self createAlternateMediaMetadata];
    
                // 1. Turn off preroll on the alternate media item.
                    newItemAdMetadata.enableLivePreroll = NO;
    
                                PTMediaPlayerItem *newItem =
                                  [[PTMediaPlayerItem alloc]initWithUrl:
                                    <INSERT-ALTERNATE-STREAM-URL mediaId:<INSERT-ALTERNATE-STREAM-
                                     MEDIA-ID> metadata:newItemAdMetadata];
    
               // 2. Register the current (original playback item) in background.
                    [self.player registerCurrentItemAsBackgroundItem];
    
               // 3. Replace the current playback item with the alternate stream.
                     [self.player replaceCurrentItemWithPlayerItem:newItem];
    
               // 4. Reset observers.
                    [self removeObservers];
                    [self addobservers];
    
               // 5. Register listener on the subscribed tags in background item.
                    [[NSNotificationCenter defaultCenter] addObserver:self
                       selector:@selector(onSubscribedTagInBackground:)
                        name:PTTimedMetadataChangedInBackgroundNotification
                          object:self.player.currentItem];
    
               // 6. Register listener on the error in background item.
                             [[NSNotificationCenter defaultCenter]
                                addObserver:self selector:@selector(onBackgroundManifestError:)
                                name:PTBackgroundManifestErrorNotification
                                  object:self.player.currentItem];
    
               // 7. Resume playback
                         [self.player play];
    
                        // 8. Set boolean to true to handle blackout end.
                      _inBlackout = YES;
                      break;
                }
            }
        }
        else if (_inBlackout && backgroundTimedMetadataCollection)
        {
            allKeys = [backgroundTimedMetadataCollection allKeys];
            int count = [allKeys count];
            for (int i=count-1; i>-1; i--)
            {
                NSNumber *currTimedMetadataTime = allKeys[i];
                PTTimedMetadata *currTimedMetadata =
                  [backgroundTimedMetadataCollection objectForKey:allKeys[i]];
    
                if (currentTime == ([currTimedMetadataTime integerValue] &&
                  currTimedMetadata.name == <INSERT-BLACKOUT-TAG>  &&
                  [self isBlackoutEnd:currTimedMetadata] )
                {
                                   // 1. Come out of blackout. Unregister background item.
                               [self.player unregisterCurrenBackgroundItem];
    
                        PTMetadata *metadata = [self createMetadata];
                        PTAdMetadata *adMetadata =
                          (PTAdMetadata *)[currMetadata metadataForKey:PTAdResolvingMetadataKey];
                              adMetadata.enableLivePreroll = NO;
    
                                PTMediaPlayerItem *item =
                                  [[[PTMediaPlayerItem alloc] initWithUrl:<INSERT-ORIGINAL-URL>
                                    mediaId:<INSERT-ORIGINAL-MEDIAID> metadata:metadata autorelease];
    
                                    // 2. Switch back to original item.
                        [self.player replaceCurrentItemWithPlayerItem:item];
                        self.player.autoPlay = YES;
                        [self removeObservers];
    
                        // 3. Remove background item listener.
                        [[NSNotificationCenter defaultCenter] removeObserver:self
                           name:PTTimedMetadataChangedInBackgroundNotification
                        object:self.player.currentItem];
    
                                   [[NSNotificationCenter defaultCenter] removeObserver:self
                                      name:PTBackgroundManifestErrorNotification
                        object:self.player.currentItem];
                        [self addobservers];
                        [self.player play];
    
                                // 4. Update boolean to correctly maintain the current state.
                        _inBlackout = NO;
                        break;
                }
            }
        }
    }
    
  5. 在後台為PTTimedMetadata對象實施偵聽器方法。

    - (void)onSubscribedTagInBackground:(NSNotification *)notification
    {
        NSDictionary *userInfo = [notification userInfo];
        PTTimedMetadata *timedMetadata = [(PTTimedMetadata *)
          [userInfo objectForKey:PTTimedMetadataKey] retain];
    
        if ([timedMetadata.name isEqualToString:<INSERT-BLACKOUT-TAG>])
        {
            NSNumber *timedMetadataStartTime =
              [NSNumber numberWithInt:(int)CMTimeGetSeconds(timedMetadata.time)];
            [backgroundTimedMetadataCollection
               setObject:timedMetadata forKey:timedMetadataStartTime];
        }
    
        [timedMetadata release];
    }
    
  6. 實作背景錯誤的監聽器方法。

    - (void) onBackgroundManifestError:(NSNotification *)notification
    {
        NSLog (@"onBackgroundManifestError");
    }
    
  7. 如果封鎖範圍位於播放串流的DVR上,請更新不可見的範圍。

    // This sample assumes that blackoutStartTimedMetadata is the PTTimedMetadata
    // object that indicated "blackout start", and assuming blackoutEndTimedMetadata is the
    // PTTimedMetadataObject that indicated "blackout end". Since in this case they are both
    // in DVR, both are notified to the application before playback starts. This is the right
    // time for the application to set this range in DVR as non-seekable range.
    
    CMTime ignoreRangeStart = blackoutStartTimedMetadata.time;
    CMTime ignoreRangeDuration = CMTimeMakeWithSeconds(CMTimeMakeWithSeconds
      (CMTimeGetSeconds(blackoutEndTimedMetadata.time) -
         CMTimeGetSeconds(blackoutStartTimedMetadata.time)),
           blackoutEndTimedMetadata.time.timescale);
    
    CMTimeRange ignoreRange = CMTimeRangeMake(ignoreRangeStart, ignoreRangeDuration);
    NSArray *ignoreRangeArray = [NSArray arrayWithObject:[NSValue valueWithCMTimeRange:ignoreRange]];
    PTBlackoutMetadata *blackoutMetadata =
      [[PTBlackoutMetadata alloc]initWithNonSeekableRanges:ignoreRangeArray];
    PTMetadata *currMetadata = self.item.metadata;
    
    if (currMetadata)
    {
        [currMetadata setMetadata:blackoutMetadata forKey:PTBlackoutMetadataKey]
    }
    

本頁內容