广告插播时间点
iOS 发送方 SDK 支持在给定媒体串流中投放广告插播和随播广告。
如需详细了解广告插播的运作方式,请参阅网站接收器广告插播概览。
虽然您可以在发送器和接收器上指定广告插播时间点,但建议您在 Web 接收器和 Android TV 接收器上指定这些时间点,以便在各个平台上保持一致的行为。
在 iOS 上,使用 GCKAdBreakClipInfo
和 GCKAdBreakInfo
在加载命令中指定广告插播时间点:
let breakClip1Builder = GCKAdBreakClipInfoBuilder(adBreakClipID: "bc0") breakClip1Builder.title = "Clip title" if let posterUrl = URL(string: "https://www.some.url") { breakClip1Builder.posterURL = posterUrl } breakClip1Builder.duration = 60 breakClip1Builder.whenSkippable = 5 // Set this field so that the ad is skippable let breakClip1 = breakClip1Builder.build() let breakClip2 = ... let breakClip3 = ... let break1 = GCKAdBreakInfoBuilder(adBreakID: "b0", adBreakClipIds: ["bc0", "bc1", "bc2"]).build() let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "entity") ... mediaInfoBuilder.adBreaks = [break1] mediaInfoBuilder.adBreakClips = [breakClip1, breakClip2, breakClip3] ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation sessionManager.currentSession?.remoteMediaClient?.loadMedia(with: mediaLoadRequestDataBuilder.build())
GCKAdBreakClipInfoBuilder *breakClipInfoBuilder = [[GCKAdBreakClipInfoBuilder alloc] initWithAdBreakClipID:@"bc0"]; breakClipInfoBuilder.title = @"Clip title"; breakClipInfoBuilder.posterURL = [[NSURL alloc] initWithString:@"https://www.some.url"]; breakClipInfoBuilder.duration = 60; breakClipInfoBuilder.whenSkippable = 5; GCKAdBreakClipInfo *breakClip1 = breakClipInfoBuilder.build; GCKAdBreakClipInfo *breakClip2 = ... GCKAdBreakClipInfo *breakClip3 = ... GCKAdBreakInfo *break1 = [[GCKAdBreakInfoBuilder alloc] initWithAdBreakID:@"b0" adBreakClipIds:@[@"bc0", @"bc1", @"bc2"]].build; GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc] initWithEntity:@"entity"]; ... mediaInfoBuilder.adBreaks = @[break1]; mediaInfoBuilder.adBreakClips = @[breakClip1, breakClip2, breakClip3]; ... self.mediaInformation = [mediaInfoBuilder build]; GCKMediaLoadRequestDataBuilder *mediaLoadRequestDataBuilder = [[GCKMediaLoadRequestDataBuilder alloc] init]; mediaLoadRequestDataBuilder.mediaInformation = self.mediaInformation; // Send a load request to the remote media client. GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMediaWithLoadRequestData:[mediaLoadRequestDataBuilder build]];
可变播放速率
您的应用可以显示和更改当前媒体项的播放速率。您可以使用 GCKRemoteMediaClient
的 -[setPlaybackRate:]
或 -[setPlaybackRate:customData:]
设置速率,使用 GCKUIMediaController
的 playbackRateController
访问 GCKUIPlaybackRateController
,并使用 GCKUIPlaybackRateController
的 playbackRate
显示当前播放速率。
示例代码
以下两个文件实现了 GCKUIPlaybackRateController
,它使用包含“正常”“半速”和“双速”按钮的分段控件来控制播放速度:
import GoogleCast /** * An implementation of GCKUIPlaybackRateController that controls playback rate * using a segmented control that has "normal", "half speed", and "double speed" * buttons. */ class SegmentedButtonPlaybackRateController: GCKUIPlaybackRateController { static let kSegmentNormal = 0; static let kSegmentHalfSpeed = 1; static let kSegmentDoubleSpeed = 2; var segmentedControl: UISegmentedControl! override var playbackRate: Float { didSet { var buttonIndex = 0 // Map the playback rate to one of our three supported speeds. if playbackRate == 1.0 { buttonIndex = SegmentedButtonPlaybackRateController.kSegmentNormal } else if playbackRate < 1.0 { buttonIndex = SegmentedButtonPlaybackRateController.kSegmentHalfSpeed } else { buttonIndex = SegmentedButtonPlaybackRateController.kSegmentDoubleSpeed } segmentedControl?.selectedSegmentIndex = buttonIndex } } override var inputEnabled: Bool { didSet { segmentedControl?.isEnabled = inputEnabled } } /** * Designated initializer. * * @param segmentedControl The segmented control for changing/displaying the * playback rate. */ convenience init(_ segmentedControl: UISegmentedControl) { self.init() self.segmentedControl = segmentedControl; segmentedControl.addTarget(self, action: #selector(segmentedControlTapped(sender:)), for: UIControl.Event.valueChanged) } @objc func segmentedControlTapped(sender: UISegmentedControl) { var playbackRate: Float = 1.0 switch segmentedControl?.selectedSegmentIndex { case SegmentedButtonPlaybackRateController.kSegmentHalfSpeed: playbackRate = 0.5; case SegmentedButtonPlaybackRateController.kSegmentDoubleSpeed: playbackRate = 2.0; case SegmentedButtonPlaybackRateController.kSegmentNormal: fallthrough default: playbackRate = 1.0; } self.playbackRate = playbackRate } }
SegmentedButtonPlaybackRateController.h
#import <GoogleCast/GoogleCast.h> #import <UIKit/UIKit.h> /** * An implementation of GCKUIPlaybackRateController that controls playback rate * using a segmented control that has "normal", "half speed", and "double speed" * buttons. */ @interface SegmentedButtonPlaybackRateController : GCKUIPlaybackRateController /** * Designated initializer. * * @param segmentedControl The segmented control for changing/displaying the * playback rate. */ - (instancetype)initWithSegmentedControl:(UISegmentedControl *)segmentedControl; @end
SegmentedButtonPlaybackRateController.m
#import "SegmentedButtonPlaybackRateController.h" @interface SegmentedButtonPlaybackRateController () { UISegmentedControl *_segmentedControl; } @end static const NSInteger kSegmentNormal = 0; static const NSInteger kSegmentHalfSpeed = 1; static const NSInteger kSegmentDoubleSpeed = 2; @implementation SegmentedButtonPlaybackRateController - (instancetype)initWithSegmentedControl:(UISegmentedControl *)segmentedControl { if (self = [super init]) { _segmentedControl = segmentedControl; [_segmentedControl addTarget:self action:@selector(segmentedControlTapped:) forControlEvents:UIControlEventValueChanged]; } return self; } - (void)setPlaybackRate:(float)playbackRate { [super setPlaybackRate:playbackRate]; NSInteger buttonIndex = 0; // Map the playback rate to one of our three supported speeds. if (playbackRate == 1.0) { buttonIndex = kSegmentNormal; } else if (playbackRate < 1.0) { buttonIndex = kSegmentHalfSpeed; } else { buttonIndex = kSegmentDoubleSpeed; } _segmentedControl.selectedSegmentIndex = buttonIndex; } - (void)setInputEnabled:(BOOL)inputEnabled { _segmentedControl.enabled = inputEnabled; [super setInputEnabled:inputEnabled]; } - (void)segmentedControlTapped:(id)sender { float playbackRate; switch (_segmentedControl.selectedSegmentIndex) { case kSegmentHalfSpeed: playbackRate = 0.5; break; case kSegmentDoubleSpeed: playbackRate = 2.0; break; case kSegmentNormal: default: playbackRate = 1.0; break; } self.playbackRate = playbackRate; } @end
添加自定义渠道
Cast 框架提供了两种创建用于向 Web 接收器发送自定义消息的通道的方法:
GCKCastChannel
旨在作为子类来实现具有关联状态的非琐碎通道。GCKGenericChannel
作为子类化方法的替代方案提供;它会将收到的消息传递给代理,以便在其他位置进行处理。
下面是一个 GCKCastChannel
实现示例:
class HGCTextChannel: GCKCastChannel { override func didReceiveTextMessage(_ message: String) { print("received message: \(message)") } }
HGCTextChannel.h
#import <GoogleCast/GCKCastChannel.h> @interface HGCTextChannel : GCKCastChannel @end
HGCTextChannel.m
#import "HGCTextChannel.h" @implementation HGCTextChannel - (void)didReceiveTextMessage:(NSString*)message { NSLog(@"received message: %@", message); } @end
您可以随时注册渠道;如果会话目前处于未连接状态,则当会话本身连接时,渠道会自动连接,前提是渠道的命名空间位于 Web Receiver 应用元数据的支持的命名空间列表中。
每个自定义渠道都由一个唯一的命名空间定义,并且必须以前缀 urn:x-cast:
开头,例如 urn:x-cast:com.example.custom
。您可以有多个自定义渠道,每个渠道都有一个唯一的命名空间。Web 接收器应用也可以使用相同的命名空间发送和接收消息。
var error: GCKError? let textChannel = HGCTextChannel.init(namespace: "urn:x-cast:com.google.cast.sample.helloworld") sessionManager.currentCastSession?.add(textChannel) textChannel.sendTextMessage("Hello World", error: &error) if error != nil { print("Error sending text message \(error.debugDescription)") }
NSError *error; HGCTextChannel *textChannel = [[HGCTextChannel alloc] initWithNamespace:@"urn:x-cast:com.google.cast.sample.helloworld"]; [sessionManager.currentCastSession addChannel:textChannel]; [textChannel sendTextMessage:@"Hello World" error:&error]; if (error != nil) { NSLog(@"Error sending text message: %@", error); }
如需提供在特定通道连接或断开连接时需要执行的逻辑,请替换 -[didConnect]
和 -[didDisconnect]
方法(如果使用 GCKCastChannel
),或者为 GCKGenericChannelDelegate
的 -[castChannelDidConnect:]
和 -[castChannelDidDisconnect:]
方法提供实现(如果使用 GCKGenericChannel
)。
支持自动播放
请参阅自动播放和队列 API。
替换图片选择和缓存
框架的各种组件(即 Cast 对话框、迷你控制器、展开式控制器和 GCKUIMediaController
,如果已配置)将显示当前投放的媒体的海报图片。图片海报图片的网址通常包含在媒体的 GCKMediaMetadata
中,但发件人应用可能有其他网址来源。
GCKUIImagePicker
协议定义了一种方法,用于根据给定的用途和所需大小选择合适的图片。它只有一个方法,即 -[getImageWithHints:fromMetadata:]
,该方法会接受 GCKUIImageHints
对象和 GCKMediaMetadata
对象作为参数,并返回 GCKImage
对象作为结果。该框架提供了 GCKUIImagePicker
的默认实现,该实现始终会选择 GCKMediaMetadata
对象中的图片列表中的第一个图片,但应用可以通过设置 GCKCastContext
单例的 imagePicker
属性来提供其他实现。
GCKUIImageCache
协议还定义了一种缓存框架使用 HTTPS 下载的图片的方法。该框架提供了 GCKUIImageCache
的默认实现,该实现会将下载的图片文件存储在应用的缓存目录中,但应用可以通过设置 GCKCastContext
单例的 imageCache
属性来提供其他实现。
后续步骤
至此,您可以向 iOS 发件人应用添加的功能已全部介绍完毕。现在,您可以为其他平台(Android 或 Web)构建发件人应用,也可以构建网站接收器。