注意:如果使用SDK源代码构建,
development
分支包含最新的更改,可能无法与公开可用的Chime媒体库一起构建,或者可能不如公开发布版本稳定。
Amazon Chime iOS SDK可以轻松地将协作式音频通话、视频通话和屏幕共享查看功能添加到iOS应用程序中,它使用与Amazon Chime服务上的会议相同的基础设施服务。
这个Amazon Chime iOS SDK通过连接到您在AWS账户中创建的会议会话资源来工作。SDK包含在iOS应用程序中构建自定义通话和协作体验所需的一切,包括以下方法:配置会议会话、列出和选择音频设备、切换视频设备、开始和停止屏幕共享查看、在发生媒体事件(如音量变化)时接收回调,以及管理会议功能,如音频静音和视频图块绑定。
我们还有一个Amazon Chime SDK项目看板,您可以在那里找到社区请求及其状态。
要开始使用,请参阅以下资源:
并查看以下指南:
您可以通过SPM、CocoaPods或GitHub发布的二进制文件将Amazon Chime SDK集成到您的项目中。
为了设置,您项目的根文件夹(可以找到.xcodeproj文件的地方)将被称为root
。
Amazon Chime SDK可通过CocoaPods获得。如果您尚未安装CocoaPods,请运行以下命令安装CocoaPods:
$ gem install cocoapods
$ pod setup
根据您的系统设置,您可能需要使用sudo来安装cocoapods,如下所示:
$ sudo gem install cocoapods
$ pod setup
在根目录(*.xcodeproj文件所在的目录)中,运行以下命令在项目中创建Podfile:
$ pod init
编辑Podfile
以将AmazonChimeSDK
包含到您的项目中:
target 'YourTarget' do
pod 'AmazonChimeSDK'
...
end
如果您不需要视频和内容共享功能,或软件视频编解码器支持,可以使用AmazonChimeSDKNoVideoCodecs
来减少大小:
target 'YourTarget' do
pod 'AmazonChimeSDKNoVideoCodecs'
...
end
(可选)如果您想使用背景模糊和替换功能,请添加:
target 'YourTarget' do
pod 'AmazonChimeSDKMachineLearning'
...
end
然后运行以下命令安装pods:
$ pod install --repo-update
要打开您的项目,请使用XCode打开根目录中新生成的*.xcworkspace
文件。您可以通过在项目文件夹中发出以下命令来执行此操作
$ xed .
注意:请不要使用*.xcodeproj打开项目。
如果您正在使用背景模糊和替换功能,在Build Settings
选项卡下,在Linking
部分,将-framework AmazonChimeSDKMachineLearning
添加到Other Linker Flags
中。
Amazon Chime SDK可通过SPM获得。如果您不需要视频和内容共享功能,或软件视频编解码器支持,您可以选择使用无视频编解码器SPM。
在Xcode中打开您的项目
转到File > Swift Packages > Add Package Dependency...
在Enter package repository URL字段中,输入"https://github.com/aws/amazon-chime-sdk-ios-spm"。要使用无视频编解码器媒体模块,请输入"https://github.com/aws/amazon-chime-sdk-ios-no-video-codecs-spm"。
输入最新版本(例如0.23.1
)并点击Next。
为您的项目选择软件包,然后点击Finish。AmazonChimeSDK
和AmazonChimeSDKMedia
是必需的。如果您想使用背景模糊和背景替换,请选中AmazonChimeSDKMachineLearning
。
AmazonChimeSDK
和AmazonChimeSDKMedia
二进制文件。
AmazonChimeSDKMachineLearning
二进制文件。否则,您可以忽略以下说明中所有关于AmazonChimeSDKMachineLearning
的引用。AmazonChimeSDKMediaNoVideoCodecs
二进制文件代替AmazonChimeSDKMedia
,并在以下说明中将所有对AmazonChimeSDKMedia
的引用视为AmazonChimeSDKMediaNoVideoCodecs
。注意:我们不支持混合使用来自不同发布版本的二进制文件。
.framework
或.xcframework
复制到root
,具体取决于您的项目使用哪种框架。对于Xcode12.3及更高版本,如果遇到编译问题,请使用.xcframework
。.xcframework
在Amazon Chime SDK iOS v0.15.0之后可用。在Xcode中打开您的.xcodeproj
文件,并点击您的构建目标。
在Build Settings
选项卡下,
将$(PROJECT_DIR)
添加到Framework Search Path
。
将@executable_path/Frameworks
添加到Runpath Search Paths
。
在Linking
部分,将以下两个标志添加到Other Linker Flags
中:
-lc++
-ObjC
在General
选项卡下,查找Frameworks, Libraries, and Embedded Content
部分。点击+,然后Add Others
,再点击Add Files
。
.framework
,请指定步骤1中AmazonChimeSDK.framework
、AmazonChimeSDKMedia.framework
和AmazonChimeSDKMachineLearning.framework
的位置。如果在使用传统的.framework
时遇到编译错误(在Xcode 12.3及更高版本中可能发生),请使用.xcframework
,它在Amazon Chime SDK iOS v0.15.0之后可用。.xcframework
,请指定步骤1中AmazonChimeSDK.xcframework
、AmazonChimeSDKMedia.xcframework
和AmazonChimeSDKMachineLearning.xcframework
的位置。AmazonChimeSDK.framework
和AmazonChimeSDKMedia.framework
框架,确认在Embed
选项下选择了Embed & Sign
。对于AmazonChimeSDKMachineLearning.framework
,选择Do Not Embed
。要运行演示应用程序,请按照以下步骤操作。
git clone git@github.com:aws/amazon-chime-sdk-ios.git
对于/AmazonChimeSDKDemo/Podfile
中的两个目标,将AMAZON_CHIME_SDK_VERSION
替换为特定的SDK版本,例如0.19.3
,或者如果使用最新版本的Amazon Chime SDK,则将其删除。
在/AmazonChimeSDKDemo
下,运行以下命令安装pods:
$ pod install --repo-update
从最新的发布版本下载AmazonChimeSDKMedia
和AmazonChimeSDKMachineLearning
二进制文件。
解压缩并将AmazonChimeSDKMedia.xcframework
复制到amazon-chime-sdk-ios/AmazonChimeSDK
文件夹,将AmazonChimeSDKMachineLearning.xcframework
复制到amazon-chime-sdk-ios/AmazonChimeSDKDemo
文件夹。
从 amazon-chime-sdk-js 部署无服务器演示
AmazonChimeDemoSDKBroadcast.appex
是 AmazonChimeSDKDemo 用于设备级屏幕共享的广播扩展,请确认在 Embed
选项下选择了 Embed without Signing
。如果您不想测试这项功能,可以将其从 Frameworks, Libraries, and Embedded Content
部分移除。对于每个目标,在 Signing & Capabilities
标签下,
Signing
部分,使用您自己的 Apple 开发者团队和 Bundle 标识符。App Groups
部分,如果您想测试共享设备级屏幕捕获,请选择您自己的应用组。详情请参阅 内容共享。更新服务器 URL 和区域:
AppConfiguration.swift
中更新无服务器演示的服务器 URL 和区域。ViewControllerObjC.h
中更新无服务器演示的服务器 URL 和区域。(可选) 如果您想测试共享设备级屏幕捕获,请在 AppConfiguration.swift
和 SampleHandler.swift
中同时更新 broadcastBundleId
和 appGroupId
,使用广播上传扩展包 ID 和 App Group ID。详情请参阅 内容共享。
使用 XCode 打开 AmazonChimeSDKDemo/
中的 AmazonChimeSDKDemo.xcworkspace
文件,从 Xcode IDE 顶部栏的方案下拉列表中选择 AmazonChimeSDKDemoPods
,选择构建设备并点击运行按钮。
使用 XCode 打开 AmazonChimeSDKDemo/
中的 AmazonChimeSDKDemo.xcworkspace
文件,从 Xcode IDE 顶部栏的方案下拉列表中选择 AmazonChimeSDKDemo
,选择构建设备 并点击运行按钮。
在加入界面上,选择不使用 CallKit
加入会议或通过 CallKit
拨入/拨出电话加入。由于演示应用没有推送通知,它会将通过拨入电话加入的时间延迟 10 秒,以给用户足够的时间将应用置于后台或锁定屏幕来模拟行为。
如果您在此项目中发现潜在的安全问题,我们请您通过我们的漏洞报告页面通知 AWS/Amazon 安全团队。请不要创建公开的 GitHub 问题。
您需要启动会议会话才能开始发送和接收音频。
meetingSession.audioVideo.start()
默认配置为:
.outputOnly
或 .none
可避免需要音频录制权限)您可以在 AudioVideoConfiguration
中指定非默认选项,然后启动会议会话。
var audioVideoConfig = AudioVideoConfiguration( audioMode: .mono48k, audioDeviceCapabilities: .outputOnly, callKitEnabled: true, enableAudioRedundancy: false, reconnectTimeoutMs: 180 * 1000) meetingSession.audioVideo.start(audioVideoConfiguration: audioVideoConfig)
注意:为避免错过任何事件,请在会话开始前添加观察者。您可以通过调用 meetingSession.audioVideo.removeAudioVideoObserver(observer) 来移除观察者。
class MyAudioVideoObserver: AudioVideoObserver { func audioSessionDidStartConnecting(reconnecting: Bool) { if (reconnecting) { // 例如,网络连接中断。 } } func audioSessionDidStart(reconnecting: Bool) { // 会议会话开始。 // 可以使用实时和设备 API。 } func audioSessionDidDrop() {} func audioSessionDidStopWithStatus(sessionStatus: MeetingSessionStatus) { // 详见"结束会话"部分。 } func audioSessionDidCancelReconnect() {} func connectionDidRecover() {} func connectionDidBecomePoor() {} func videoSessionDidStartConnecting() {} func videoSessionDidStartWithStatus(sessionStatus: MeetingSessionStatus) { // 视频会话开始。 // 可以使用视频 API。 } func videoSessionDidStopWithStatus(sessionStatus: MeetingSessionStatus) {} meetingSession.audioVideo.addAudioVideoObserver(observer: self) }
列出会议可用的音频设备。
// MediaDevice 对象的列表 let audioDevices = meetingSession.audioVideo.listAudioDevices() for device in audioDevices { logger.info(msg: "设备类型: \(device.type), 标签: \(device.label)") }
MediaDevice
对象选择音频设备。注意:您应该在会话开始后调用此方法,否则将不生效。您应该使用 listAudioDevices() 返回的设备之一调用 chooseAudioDevice。
let audioDevices = audioVideo.listAudioDevices() val device = /* audioDevices 中的一项 */ meetingSession.audioVideo.chooseAudioDevice(mediaDevice: device)
注意:如果您使用自定义摄像头捕获源,switchCamera() 将不生效。请参阅 自定义视频 获取更多详情。
切换使用设备的前置或后置摄像头(如果可用)。
meetingSession.audioVideo.switchCamera()
添加 DeviceChangeObserver
以在新的音频设备连接或音频设备断开连接时接收回调。audioDeviceDidChange
包含更新后的设备列表。
class MyDeviceChangeObserver: DeviceChangeObserver { func audioDeviceDidChange(freshAudioDeviceList: [MediaDevice]) { // 更新后的 MediaDevice 对象列表 for device in freshAudioDeviceList { logger.info(msg: "设备类型: \(device.type), 标签: \(device.label)") } } meetingSession.audioVideo.addDeviceChangeObserver(observer: self) }
let activeAudioDevice = meetingSession.audioVideo.getActiveAudioDevice()
加入会议时,支持 单声道/16KHz、单声道/48KHz 和 立体声/48KHz。如果在启动音频会话时未明确指定,立体声/48KHz 将被设置为默认音频模式。
meetingSession.audioVideo.start() // 以立体声/48KHz 音频、启用音频输入和输出设备、禁用 callkit 以及启用音频冗余的方式启动音视频会话 meetingSession.audioVideo.start(audioVideoConfiguration) // 使用指定的 [AudioVideoConfiguration] 启动音视频会话
注意:到目前为止,您已经添加了观察者来接收设备和会话生命周期事件。在以下用例中,您将使用实时 API 方法来发送和接收音量指示器并控制静音状态。
let muted = meetingSession.audioVideo.realtimeLocalMute() // 如果静音成功返回 true,失败返回 false let unmuted = meetingSession.audioVideo.realtimeLocalUnmute // 如果取消静音成 功返回 true,失败返回 false
您可以使用此功能构建实时指示器 UI,并通过数组传递的变化来更新它们。
注意:这些回调将只包含与前一次回调的差异。
class MyRealtimeObserver: RealtimeObserver { func volumeDidChange(volumeUpdates: [VolumeUpdate]) { for currentVolumeUpdate in volumeUpdates { // 静音、未说话、低音量、中音量、高音量 logger.info(msg: "\(currentVolumeUpdate.attendeeInfo.attendeeId) 的音量发生变化: \(currentVolumeUpdate.volumeLevel)") } } func signalStrengthDidChange(signalUpdates: [SignalUpdate]) { for currentSignalUpdate in signalUpdates { // 无信号、弱信号、强信号 logger.info(msg: "\(currentSignalUpdate.attendeeInfo.attendeeId) 的信号强度发生变化: \(currentSignalUpdate.signalStrength)") } } func attendeesDidJoin(attendeeInfo: [AttendeeInfo]) { for currentAttendeeInfo in attendeeInfo { logger.info(msg: "\(currentAttendeeInfo.attendeeId) 加入了会议") } } func attendeesDidLeave(attendeeInfo: [AttendeeInfo]) { for currentAttendeeInfo in attendeeInfo { logger.info(msg: "\(currentAttendeeInfo.attendeeId) 离开了会议") } } func attendeesDidDrop(attendeeInfo: [AttendeeInfo]) { for currentAttendeeInfo in attendeeInfo { logger.info(msg: "\(currentAttendeeInfo.attendeeId) 从会议中掉线") } } func attendeesDidMute(attendeeInfo: [AttendeeInfo]) { for currentAttendeeInfo in attendeeInfo { logger.info(msg: "\(currentAttendeeInfo.attendeeId) 已静音") } } func attendeesDidUnmute(attendeeInfo: [AttendeeInfo]) { for currentAttendeeInfo in attendeeInfo { logger.info(msg: "\(currentAttendeeInfo.attendeeId) 已取消静音") } } meetingSession.audioVideo.addRealtimeObserver(observer: self) }
您可以使用 activeSpeakerDidDetect
事件来放大或突出显示最活跃发言者的视频图块(如果可用)。通过设置 scoreCallbackIntervalMs
并实现 activeSpeakerScoreDidChange
,您可以定期接收活跃发言者的分数。
class MyActiveSpeakerObserver: ActiveSpeakerObserver { let activeSpeakerObserverId = UUID().uuidString var observerId: String { return activeSpeakerObserverId } func activeSpeakerDidDetect(attendeeInfo: [AttendeeInfo]) { if !attendeeInfo.isEmpty { logger.info(msg: "\(attendeeInfo[0].attendeeId) 是最活跃的发言者") } } var scoresCallbackIntervalMs: Int { return 1000 // 1秒 } func activeSpeakerScoreDidChange(scores: [AttendeeInfo: Double]) { let scoresInString = scores.map { (score) -> String in let (key, value) = score return "\(key.attendeeId): \(value)" }.joined(separator: ",") logger.info(msg: "活跃发言者的分数为: \(scoresInString)") } // 基于SDK提供的策略计算活跃发言者,您可以提供任何自定义算法 meetingSession.audioVideo.addActiveSpeakerObserver(policy: DefaultActiveSpeakerPolicy(), observer: self) }
注意:您需要将视频绑定到
VideoRenderView
才能显示视频。本地视频图块可以通过
isLocalTile
属性来识别。内容视频图块可以通过
isContent
属性来识别。参见屏幕和内容共享。当同一远程参与者重新启动视频时,会使用新的图块ID创建一个图块。
您可以在使用Amazon Chime SDK在iOS上构建会议应用程序中找到更多关于添加/移除/查看视频的详细信息。
您可以调用 startRemoteVideo
来开始接收远程视频,因为默认情况下不会自动接收。
meetingSession.audioVideo.startRemoteVideo()
stopRemoteVideo
停止接收远程视频,并为现有的远程视频触发 onVideoTileRemoved
。
meetingSession.audioVideo.stopRemoteVideo()
class MyVideoTileObserver: VideoTileObserver { func videoTileDidAdd(tileState: VideoTileState) { // 忽略本地视频(参见查看本地视频)和内容视频(参见屏幕和内容共享) if tileState.isLocalTile || tileState.isContent { return } let videoRenderView = /* 您应用程序中用于显示视频的VideoRenderView对象 */ meetingSession.audioVideo.bind(videoView: videoRenderView, tileId: tileState.tileId) } func videoTileDidRemove(tileState: VideoTileState) { // 解绑视频视图以停止查看图块 meetingSession.audioVideo.unbindVideoView(tileId: tileState.tileId) } meetingSession.audioVideo.addVideoTileObserver(observer: self) }
// 使用内部摄像头捕获本地视频 meetingSession.audioVideo.startLocalVideo() // 使用内部摄像头捕获并为视频设置配置,例如启用模拟广播和最大比特率 // 如果未设置maxBitRateKbps,它将根据会议中的用户数量和视频数量自动调整 // 可以多次调用此方法来启用/禁用模拟广播并动态调整视频最大比特率 let localVideoConfig = LocalVideoConfiguration(simulcastEnabled: true, maxBitRateKbps: 600) meetingSession.audioVideo.startLocalVideo(config: localVideoConfig) // 您可以切换摄像头以更改视频输入设备 meetingSession.audioVideo.switchCamera() // 或者,您可以为本地视频注入自定义视频源,请参阅自定义视频指南
meetingSession.audioVideo.stopLocalVideo()
注意:本地视频应该是镜像的。设置 VideoRenderView.mirror = true
class MyVideoTileObserver: VideoTileObserver { func videoTileDidAdd(tileState: VideoTileState) { if tileState.isLocalTile { let localVideoView = /* 您应用程序中用于显示视频的VideoRenderView对象 */ meetingSession.audioVideo.bind(videoView: localVideoView, tileId: tileState.tileId) } } } func videoTileDidRemove(tileState: VideoTileState) { // 解绑视频视图以停止查看图块 meetingSession.audioVideo.unbindVideoView(tileId: tileState.tileId) } meetingSession.audioVideo.addVideoTileObserver(observer: self) }
有关更高级的视频图块管理,请查看视频分页。
注意:当您或其他参与者共享内容(例如屏幕捕获或任何其他VideoSource对象)时,内容参与者(attendee-id#content)会加入会话,并像普通参与者共享视频一样共享内容。
例如,您的参与者ID是"my-id"。当您调用
meetingSession.audioVideo.startContentShare
时,内容参与者"my-id#content"将加入会话并共享您的内容。
class MyContentShareObserver: ContentShareObserver { func contentShareDidStart() { logger.info(msg: "内容共享已开始") } func contentShareDidStop(status: ContentShareStatus){ logger.info(msg: "内容共享已停止") } meetingSession.audioVideo.addContentShareObserver(observer: self) let contentShareSource = /* ContentShareSource对象,可以使用InAppScreenCaptureSource进行屏幕共享或任何带有自定义视频源的子类 */ // ContentShareSource对象不由SDK管理,开发者需要相应地启动、停止、释放 meetingSession.audioVideo.startContentShare(source: contentShareSource) }
您可以为内容共享设置配置,例如maxBitRateKbps。实际达到的质量可能会根据系统和网络 的情况在通话过程中有所变化。
let contentShareConfig = LocalVideoConfiguration(maxBitRateKbps: 200) meetingSession.audioVideo.startContentShare(source: contentShareSource, config: contentShareConfig)
更多详情请参见内容共享。
meetingSession.audioVideo.stopContentShare()
Chime SDK允许每个会议同时进行两个内容共享。远程内容共享将触发 onVideoTileAdded
,而本地共享则不会。要渲染预览视频,请将 VideoSink
添加到 ContentShareSource
中的 VideoSource