Amazon Chime SDK项目委员会
注意:如果使用SDK源代码进行构建,则
development
分支包含可能无法使用公开可用的Chime Media库构建的出血边缘更改,或者可能不像公共发行版那样稳定。
iOS的Amazon Chime SDK通过使用相同的基础架构服务来添加协作音频通话,视频呼叫和屏幕共享查看功能,从而轻松添加与Amazon Chime Service供电的基础架构服务。
这款Amazon Chime SDK适用于iOS,通过连接到您在AWS帐户中创建的会话资源。 SDK拥有在iOS应用程序中构建自定义呼叫和协作体验所需的一切随着音量的变化并管理会议功能,例如音频静音和视频瓷砖绑定。
我们还拥有一个Amazon Chime SDK项目委员会,您可以在其中找到社区请求及其状态。
首先,请参阅以下资源:
并查看以下指南:
您可以通过github释放将Amazon Chime SDK从SPM,Cocoapods或二进制文件中集成到您的项目中。
为了设置,您的项目的根文件夹(您可以找到.xcodeproj
文件)将被称为root
。
Amazon Chime SDK可通过Cocoapods获得。如果您尚未安装Cocoapods,请通过运行命令来安装Cocoapods:
$ gem install cocoapods
$ pod setup
根据您的系统设置,您可能必须使用sudo来安装可可脚架,如下所示:
$ sudo gem install cocoapods
$ pod setup
在root Directory(您的 *.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
然后运行以下命令以安装POD:
$ pod install --repo-update
要打开您的项目,请使用Xcode在根目录中打开新生成的*.xcworkspace
文件。您可以通过在项目文件夹中发出以下命令来执行此操作
$ xed .
注意:请勿使用 *.xcodeproj打开项目。
如果您使用的是背景模糊和替换功能,则在Linking
部分下方的Build Settings
选项卡下,将-framework AmazonChimeSDKMachineLearning
添加到Other Linker Flags
中。
Amazon Chime SDK可通过SPM获得。如果您不需要视频和内容共享功能或软件视频编解码器支持,则可以选择不使用视频编解码器SPM。
在Xcode中打开您的项目
转到文件> Swift软件包>添加软件包依赖关系...
在字段中,输入软件包存储库URL ,请输入“ https://github.com/aws/amazon-chime-sdk-ios-pm”。要使用不使用视频编解码器媒体模块,请输入“ https://github.com/aws/amazon-chime-sdk-ios-no-video-codecs-spm”。
输入最新版本(例如0.23.1
),然后单击下一步。
选择项目的软件包,然后单击完成。需要AmazonChimeSDK
和AmazonChimeSDKMedia
。如果您想使用背景模糊和背景更换,请检查AmazonChimeSDKMachineLearning
。
AmazonChimeSDK
和AmazonChimeSDKMedia
二进制文件。AmazonChimeSDKMachineLearning
二进制文件。否则,您可以在下面的说明中忽略对AmazonChimeSDKMachineLearning
的所有参考。AmazonChimeSDKMediaNoVideoCodecs
二进制代替AmazonChimeSDKMedia
,并将所有参考作为AmazonChimeSDKMedia
作为AmazonChimeSDKMediaNoVideoCodecs
在下面的说明中。注意:我们不支持来自不同版本的混合和匹配二进制文件。
.framework
s或.xcframework
s复制为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
,请指定AmazonChimeSDK.framework
, AmazonChimeSDKMedia.framework
和AmazonChimeSDKMachineLearning.framework
的位置。如果您在使用传统的.framework
时出现编译错误,则在Xcode 12.3中发生在XCode 12.3中,请使用.xcframework
,可以在Amazon Chime SDK IOS V0.15.0之后获得。.xcframework
,请指定AmazonChimeSDK.xcframework
, AmazonChimeSDKMedia.xcframework
和AmazonChimeSDKMachineLearning.xcframework
的位置。AmazonChimeSDK.framework
AmazonChimeSDKMedia.framework
和Frameworks,请在Embed
选项下验证Embed & Sign
。对于AmazonChimeSDKMachineLearning.framework
,选择Do Not Embed
。 要运行演示应用程序,请按照以下步骤操作。
git clone [email protected]:aws/amazon-chime-sdk-ios.git
对于/AmazonChimeSDKDemo/Podfile
中的两个目标,请用特定的SDK版本替换AMAZON_CHIME_SDK_VERSION
,例如0.19.3
,如果使用了最新版本的Amazon Chime SDK,则将其删除。
Unewer /AmazonChimeSDKDemo
,运行以下命令以安装POD:
$ pod install --repo-update
从最新版本中下载AmazonChimeSDKMedia
和AmazonChimeSDKMachineLearning
二进制文件。
unzip并将AmazonChimeSDKMedia.xcframework
复制到amazon-chime-sdk-ios/AmazonChimeSDK
文件夹和AmazonChimeSDKMachineLearning.xcframework
到amazon-chime-sdk-ios/AmazonChimeSDKDemo
folder。
从Amazon-Chime-SDK-JS部署无服务器演示
AmazonChimeDemoSDKBroadcast.appex
是AmazonChimesDkdeMo使用的设备级别屏幕共享的广播扩展,验证在Embed
选项下选择Embed without Signing
。如果您不希望对此进行测试,请将其从Frameworks, Libraries, and Embedded Content
部分中删除。 对于每个目标,在Signing & Capabilities
卡下,
Signing
部分,使用您自己的Apple开发人员团队和捆绑标识符。App Groups
部分,如果您想测试共享设备级别的屏幕捕获,请选择自己的应用程序组。有关更多详细信息,请参见内容共享。 更新服务器URL和区域:
AppConfiguration.swift
使用服务器URL和无服务器演示的区域。ViewControllerObjC.h
。 (可选)在AppConfiguration.swift
和SampleHandler.swift
中更新broadcastBundleId
和appGroupId
。有关更多详细信息,请参见内容共享。
在AmazonChimeSDKDemo/
使用Xcode中打开AmazonChimeSDKDemo.xcworkspace
文件,从Xcode IDE顶部的方案下拉列表中选择AmazonChimeSDKDemoPods
,选择构建设备,然后单击“跑步”按钮。
在AmazonChimeSDKDemo/
使用Xcode中打开AmazonChimeSDKDemo.xcworkspace
文件,从Xcode IDE顶部的方案下拉列表中选择AmazonChimeSDKDemo
,选择一个构建设备,然后单击“运行”按钮。
在加入屏幕上,选择无CallKit
加入会议或通过CallKit
传入/发出呼叫加入。由于演示应用程序没有推动通知,因此它通过传入呼叫加入10秒钟,以使用户有足够的时间背景应用程序或锁定屏幕以模仿行为。
如果您在此项目中发现潜在的安全问题,我们要求您通过我们的漏洞报告页面通知AWS/Amazon Security。请不要创建公共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 )
注意:要避免丢失任何事件,请在会话开始之前添加观察者。您可以通过致电会议来删除观察者。audiovideo.removeaudiovideoobserver(观察者)。
class MyAudioVideoObserver : AudioVideoObserver {
func audioSessionDidStartConnecting ( reconnecting : Bool ) {
if ( reconnecting ) {
// e.g. the network connection is dropped.
}
}
func audioSessionDidStart ( reconnecting : Bool ) {
// Meeting session starts.
// Can use realtime, devices APIs.
}
func audioSessionDidDrop ( ) { }
func audioSessionDidStopWithStatus ( sessionStatus : MeetingSessionStatus ) {
// See the "Stopping a session" section for details.
}
func audioSessionDidCancelReconnect ( ) { }
func connectionDidRecover ( ) { }
func connectionDidBecomePoor ( ) { }
func videoSessionDidStartConnecting ( ) { }
func videoSessionDidStartWithStatus ( sessionStatus : MeetingSessionStatus ) {
// Video session starts.
// Can use video APIs.
}
func videoSessionDidStopWithStatus ( sessionStatus : MeetingSessionStatus ) { }
meetingSession . audioVideo . addAudioVideoObserver ( observer : self )
}
列出会议的可用音频设备。
// An list of MediaDevice objects
let audioDevices = meetingSession . audioVideo . listAudioDevices ( )
for device in audioDevices {
logger . info ( msg : " Device type: ( device . type ) , label: ( device . label ) " )
}
MediaDevice
对象选择音频设备。注意:您应该在会话开始后打电话给这个,否则将是无效的。您应该使用从ListAudiodevices()返回的设备之一调用ChooSeaudiOdevice。
let audioDevices = audioVideo . listAudioDevices ( )
val device = /* An item from audioDevices */
meetingSession . audioVideo . chooseAudioDevice ( mediaDevice : device )
注意:如果您使用自定义摄像机捕获源,则switchCamera()是无效的。请参阅自定义视频以获取更多详细信息。
切换到设备上的前摄像头或后置摄像头(如果有)。
meetingSession . audioVideo . switchCamera ( )
添加DeviceChangeObserver
以接收新音频设备或音频设备断开连接时接收回调。 audioDeviceDidChange
包含更新的设备列表。
class MyDeviceChangeObserver : DeviceChangeObserver {
func audioDeviceDidChange ( freshAudioDeviceList : [ MediaDevice ] ) {
// A list of updated MediaDevice objects
for device in freshAudioDeviceList {
logger . info ( msg : " Device type: ( device . type ) , label: ( device . label ) " )
}
}
meetingSession . audioVideo . addDeviceChangeObserver ( observer : self )
}
let activeAudioDevice = meetingSession . audioVideo . getActiveAudioDevice ( )
加入会议时,支持Mono/16KHz , Mono/48kHz和立体声/48KHz 。立体声/48kHz如果在启动音频会话时未明确指定的话,将设置为默认音频模式。
meetingSession . audioVideo . start ( ) // starts the audio video session with Stereo/48KHz audio, audio input and output devices enabled, callkit disabled, and audio redundancy enabled
meetingSession . audioVideo . start ( audioVideoConfiguration ) // starts the audio video session with the specified [AudioVideoConfiguration]
注意:到目前为止,您已经添加了观察者来接收设备和会话生命周期事件。在以下用例中,您将使用实时API方法发送和接收卷指标并控制静音状态。
let muted = meetingSession . audioVideo . realtimeLocalMute ( ) // returns true if muted, false if failed
let unmuted = meetingSession . audioVideo . realtimeLocalUnmute // returns true if unmuted, false if failed
您可以使用它来构建实时指标UI并将其更新以进行数组提供的更改。
注意:这些回调仅包括上一个回调中的三角洲。
class MyRealtimeObserver : RealtimeObserver {
func volumeDidChange ( volumeUpdates : [ VolumeUpdate ] ) {
for currentVolumeUpdate in volumeUpdates {
// Muted, NotSpeaking, Low, Medium, High
logger . info ( msg : " ( currentVolumeUpdate . attendeeInfo . attendeeId ) 's volume changed: ( currentVolumeUpdate . volumeLevel ) " )
}
}
func signalStrengthDidChange ( signalUpdates : [ SignalUpdate ] ) {
for currentSignalUpdate in signalUpdates {
// None, Low, High
logger . info ( msg : " ( currentSignalUpdate . attendeeInfo . attendeeId ) 's signal strength changed: ( currentSignalUpdate . signalStrength ) " )
}
}
func attendeesDidJoin ( attendeeInfo : [ AttendeeInfo ] ) {
for currentAttendeeInfo in attendeeInfo {
logger . info ( msg : " ( currentAttendeeInfo . attendeeId ) joined the meeting " )
}
}
func attendeesDidLeave ( attendeeInfo : [ AttendeeInfo ] ) {
for currentAttendeeInfo in attendeeInfo {
logger . info ( msg : " ( currentAttendeeInfo . attendeeId ) left the meeting " )
}
}
func attendeesDidDrop ( attendeeInfo : [ AttendeeInfo ] ) {
for currentAttendeeInfo in attendeeInfo {
logger . info ( msg : " ( currentAttendeeInfo . attendeeId ) dropped from the meeting " )
}
}
func attendeesDidMute ( attendeeInfo : [ AttendeeInfo ] ) {
for currentAttendeeInfo in attendeeInfo {
logger . info ( msg : " ( currentAttendeeInfo . attendeeId ) muted " )
}
}
func attendeesDidUnmute ( attendeeInfo : [ AttendeeInfo ] ) {
for currentAttendeeInfo in attendeeInfo {
logger . info ( msg : " ( currentAttendeeInfo . attendeeId ) unmuted " )
}
}
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 ) is the most active speaker " )
}
}
var scoresCallbackIntervalMs : Int {
return 1000 // 1 second
}
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 : " Scores of active speakers are: ( scoresInString ) " )
}
// Calculating the active speaker base on the SDK provided policy, you can provide any custom algorithm
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 ) {
// Ignore local video (see View local video), content video (see Screen and content share)
if tileState . isLocalTile || tileState . isContent {
return
}
let videoRenderView = /* a VideoRenderView object in your application to show the video */
meetingSession . audioVideo . bind ( videoView : videoRenderView , tileId : tileState . tileId )
}
func videoTileDidRemove ( tileState : VideoTileState ) {
// unbind video view to stop viewing the tile
meetingSession . audioVideo . unbindVideoView ( tileId : tileState . tileId )
}
meetingSession . audioVideo . addVideoTileObserver ( observer : self )
}
// Use internal camera capture for the local video
meetingSession . audioVideo . startLocalVideo ( )
// Use internal camera capture and set configuration for the video, e.g. simulcastEnabled, maxBitRateKbps
// If maxBitRateKbps is not set, it will be self adjusted depending on number of users and videos in the meeting
// This can be called multiple times to enable/disable simulcast and adjust video max bit rate on the fly
let localVideoConfig = LocalVideoConfiguration ( simulcastEnabled : true, maxBitRateKbps : 600 )
meetingSession . audioVideo . startLocalVideo ( config : localVideoConfig )
// You can switch camera to change the video input device
meetingSession . audioVideo . switchCamera ( )
// Or you can inject custom video source for local video, see custom video guide
meetingSession . audioVideo . stopLocalVideo ( )
注意:应该镜像本地视频。设置videorenderview.mirror = true
class MyVideoTileObserver : VideoTileObserver {
func videoTileDidAdd ( tileState : VideoTileState ) {
if tileState . isLocalTile {
let localVideoView = /* a VideoRenderView object in your application to show the video */
meetingSession . audioVideo . bind ( videoView : localVideoView , tileId : tileState . tileId )
}
}
}
func videoTileDidRemove ( tileState : VideoTileState ) {
// unbind video view to stop viewing the tile
meetingSession . audioVideo . unbindVideoView ( tileId : tileState . tileId )
}
meetingSession . audioVideo . addVideoTileObserver ( observer : self )
}
有关更高级的视频瓷砖管理,请查看视频分页。
注意:当您或其他参与者共享内容(例如屏幕截图或任何其他视频程序对象)时,内容参与者(与会者ID#内容)会加入会话并共享内容,就好像常规参与者共享视频一样。
例如,您的与会者ID是“ my-id”。当您致电
meetingSession.audioVideo.startContentShare
时,内容与会者“ my-id#content”将加入会议并共享您的内容。
class MyContentShareObserver : ContentShareObserver {
func contentShareDidStart ( ) {
logger . info ( msg : " Content Share has started " )
}
func contentShareDidStop ( status : ContentShareStatus ) {
logger . info ( msg : " Content Share has stopped " )
}
meetingSession . audioVideo . addContentShareObserver ( observer : self )
let contentShareSource = /* a ContentShareSource object, can use InAppScreenCaptureSource for screen share or any subclass with custom video source */
// ContentShareSource object is not managed by SDK, builders need to start, stop, release accordingly
meetingSession . audioVideo . startContentShare ( source : contentShareSource )
}
您可以为内容共享设置配置,例如maxbitratekbps。在整个呼叫中,取决于系统和网络可以提供的实际质量可能会有所不同。
let contentShareConfig = LocalVideoConfiguration ( maxBitRateKbps : 200 )
meetingSession . audioVideo . startContentShare ( source : contentShareSource , config : contentShareConfig )
有关更多详细信息,请参见内容共享。
meetingSession . audioVideo . stopContentShare ( )
Chime SDK允许每次会议同时共享两份内容。远程内容共享将触发onVideoTileAdded
,而本地股份不会。要渲染视频进行预览,请在ContentShareSource
中的VideoSource
中添加一个VideoSink
。
class MyVideoTileObserver : VideoTileObserver {
func videoTileDidAdd ( tileState : VideoTileState ) {
if ( tileState . isContent ) {
// tileState.attendeeId is formatted as "attendee-id#content"
let attendeeId = tileState . attendeeId
// Get the attendee ID from "attendee-id#content"
let baseAttendeeId = DefaultModality ( attendeeId ) . base ( )
logger . info ( msg : " $baseAttendeeId is sharing screen " )
let screenVideoView = /* a VideoRenderView object in your application to show the video */
meetingSession . audioVideo . bindVideoView ( videoView : screenVideoView , tileId : tileState . tileId )
}
}
func videoTileDidRemove ( tileState : VideoTileState ) {
meetingSession . audioVideo . unbindVideoView ( tileId : tileState . tileId )
}
meetingSession . audioVideo . addVideoTileObserver ( observer : self )
}
有关更多可用的指标,请参见ObservableMetric
,并监视音频,视频和内容共享质量。
class MyMetricsObserver : MetricsObserver {
func metricsDidReceive ( metrics : [ AnyHashable : Any ] ) {
logger . info ( msg : " Media metrics have been received: ( metrics ) " )
}
meetingSession . audioVideo . addMetricsObserver ( observer : self )
}
开始会议后,您可以从多个主题中接收实时消息。
class MyDataMessageObserver : DataMessageObserver {
let dataMessageTopic = " chat "
// A throttled message is returned by backend from local sender
func dataMessageDidReceived ( dataMessage : DataMessage ) {
logger . info ( msg : " ( dataMessage . timestampMs ) ( dataMessage . text ( ) ) ( dataMessage . senderAttendeeId ) " )
}
// You can also subscribe to multiple topics.
meetingSession . audioVideo . addRealtimeDataMessageObserver ( topic : dataMessageTopic , observer : self )
}
您可以将实时消息发送到任何主题,将通知已订阅的观察者。
注意:主题必须是alpha-numeric,它可以包括连字符和下划线。数据不能超过2KB,寿命是可选的,但整数为正。
let dataMessageTopic = " chat "
let dataMessageLifetimeMs = 1000
do {
// Send "Hello Chime" to any subscribers who are listening to "chat" topic with 1 seconds of lifetime
try meetingSession
. audioVideo
. realtimeSendDataMessage ( topic : dataMessageTopic ,
data : " Hello Chime " ,
lifetimeMs : dataMessageLifetimeMs )
} catch let err as SendDataMessageError {
logger . error ( msg : " Failed to send message! ( err ) " )
} catch {
logger . error ( msg : " Unknown error ( error . localizedDescription ) " )
}
注意:确保删除所有观察者并发布您添加的资源,以避免任何内存泄漏。
class MyAudioVideoObserver : AudioVideoObserver {
func audioSessionDidStopWithStatus ( sessionStatus : MeetingSessionStatus ) {
// This is where meeting ended.
// You can do some clean up work here.
}
func videoSessionDidStopWithStatus ( sessionStatus : MeetingSessionStatus ) {
// This will be invoked as well.
}
meetingSession . audioVideo . addAudioVideoObserver ( observer : self )
meetingSession . audioVideo . stop ( )
}
亚马逊语音焦点减少了会议中的背景噪音,以获得更好的会议体验。有关更多详细信息,请参见Amazon语音焦点。
let enabled = audioVideo . realtimeSetVoiceFocusEnabled ( enabled : true ) // enabling Amazon Voice Focus successful
let disabled = audioVideo . realtimeSetVoiceFocusEnabled ( enabled : false ) // disabling Amazon Voice Focus successful
自定义视频源允许您控制视频,例如应用视频过滤器。有关更多详细信息,请参见自定义视频。
从0.23.3版本开始,SDK开始向我们的服务器发送冗余音频数据,以检测数据包丢失,以帮助降低其对音频质量的影响。冗余音频数据包仅用于包含活动音频,IE语音或音乐的数据包。根据检测到的数据包损耗的数量,这可能会增加音频消耗的带宽最高正常量的3倍。如果SDK在5分钟内未检测到任何数据包丢失,则将自动停止发送冗余数据。
如果需要禁用此功能,则可以在开始会话之前通过AudiovideOconfiguration进行。
meetingSession . audioVideo . start ( AudioVideoConfiguration ( enableAudioRedundancy : false ) )
虽然可以选择禁用该功能,但我们建议将其启用以提高音频质量。禁用您的客户有非常严格的带宽限制的可能原因。
请参阅Amazon Chime SDK将军。
应用程序在创建会议时可以通过记录器实例从chime SDK获取日志。 Amazon Chime SDK具有您的应用程序可以使用的Logger的一些默认实现,例如将登录到控制台的ConsoleLogger。默认情况下, ConsoleLogger
设置为INFO
级别。因此,为了获取所有日志,包括媒体日志,请通过以下方式创建记录器:
logger = ConsoleLogger ( name : " logger " , level : . DEFAULT )
您和您的最终用户负责上传的所有内容(包括任何图像),并必须确保该内容不会违反法律,侵犯或滥用任何第三方的权利,或者以其他方式违反了物质术语您与亚马逊的协议(包括文档,AWS服务条款或可接受的使用政策)。
版权所有Amazon.com,Inc。或其分支机构。版权所有。