你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
管理客户端上的通话记录
重要
本文中所述的功能目前以公共预览版提供。 此预览版在提供时没有附带服务级别协议,我们不建议将其用于生产工作负荷。 某些功能可能不受支持或者受限。 有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款。
通过通话录制,用户可记录他们使用 Azure 通信服务进行的通话。 在本文中,了解如何管理客户端上的录制。 在开始之前,需要在服务器端设置录制。
先决条件
- 具有活动订阅的 Azure 帐户。 免费创建帐户。
- 已部署的通信服务资源。 创建通信服务资源。
- 用于启用通话客户端的用户访问令牌。 有关详细信息,请参阅创建和管理访问令牌。
- 可选:完成向应用程序添加语音呼叫的快速入门。
支持
下表定义了 Azure 通信服务的录制功能支持。
标识和通话类型
下表显示了特定通话类型和标识的录制功能支持。
标识 | Teams 会议 | 房间 | 1 对 1 通话 | 组呼叫 | 1:1 Teams 互操作通话 | 小组 Teams 互操作通话 |
---|---|---|---|---|---|---|
通信服务用户 | ✔️[1] | ✔️[2] | ✔️[2] | ✔️[2] | ✔️[1] | ✔️[1][2] |
Microsoft 365 用户 | ✔️[1] | ✔️[2] | ✔️[1] | ✔️[1][2] |
[1] 这些通话类型支持 Teams 云和合规性录制。
[2] 这些通话类型支持 Azure 通信服务录制。
Operations
下表显示了通话 SDK 中各个 API 对各种标识类型的支持。
Operations | 通信服务用户 | Microsoft 365 用户 |
---|---|---|
获取录制开始或停止的通知 | ✔️ | ✔️ |
获取录制状态 | ✔️ | ✔️ |
获取录制功能可供使用的通知 | ✔️[1] | ✔️[1] |
了解是否需要显式同意 | ✔️[2] | ✔️[2] |
提供录制显式同意 | ✔️[2] | ✔️[2] |
[1] 用户未收到录制功能可供使用的通知。 你可以通过 Microsoft Graph API 获取 Teams 云录制功能。 录制功能可供使用后,你可以在 Azure 通信服务中订阅通知。
[2] 此功能仅在 Teams 会议和 Teams 互操作性群组通话中可用。
SDK
下表显示了各个 Azure 通信服务 SDK 的录制功能支持。
平台 | Web | Web UI | iOS | iOS UI | Android | Android UI | Windows |
---|---|---|---|---|---|---|---|
支持 | ✔️ | ✔️[1] | ✔️[1] | ✔️[1] | ✔️[1] | ✔️[1] | ✔️[1] |
[1] 这些 SDK 不支持显式同意。
安装 SDK
使用 npm install
命令安装适用于 JavaScript 的 Azure 通信服务通用 SDK 和通话 SDK:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
初始化所需的对象
大多数通话操作需要 CallClient
实例。 创建新的 CallClient
实例时,可以使用自定义选项(如 Logger
实例)对其进行配置。
有了 CallClient
实例后,可以通过调用 createCallAgent
创建 CallAgent
实例。 此方法将异步返回 CallAgent
实例对象。
createCallAgent
方法使用 CommunicationTokenCredential
作为参数。 它接受用户访问令牌。
可在 CallClient
实例上使用 getDeviceManager
方法来访问 deviceManager
。
const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the logger's log level
setLogLevel('verbose');
// Redirect log output to console, file, buffer, REST API, or whatever location you want
AzureLogger.log = (...args) => {
console.log(...args); // Redirect log output to console
};
const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()
如何最好地管理 SDK 与 Microsoft 基础结构的连接性
Call Agent
实例可帮助你管理通话(以加入或启动通话)。 通话 SDK 需要连接到 Microsoft 基础结构以获取传入通话通知并协调其他通话详细信息,否则无法工作。 你的 Call Agent
有两种可能的状态:
已连接 - Call Agent
connectionStatue 值为 Connected
表示客户端 SDK 已连接,能够接收来自 Microsoft 基础结构的通知。
已断开连接 - Call Agent
connectionStatue 值为 Disconnected
表示存在阻止 SDK 正确连接的问题。 应重新创建 Call Agent
。
invalidToken
:如果令牌已过期或无效,Call Agent
实例会断开连接并出现此错误。connectionIssue
:如果客户端连接到 Microsoft 基础结构时出现问题,则在多次重试后,Call Agent
会显示connectionIssue
错误。
可以通过检查 connectionState
属性的当前值来检查本地 Call Agent
是否已连接到 Microsoft 基础结构。 在通话过程中,可以侦听 connectionStateChanged
事件,以确定 Call Agent
是否从“已连接”状态更改为“已断开连接”状态。
const connectionState = callAgentInstance.connectionState;
console.log(connectionState); // it may return either of 'Connected' | 'Disconnected'
const connectionStateCallback = (args) => {
console.log(args); // it will return an object with oldState and newState, each of having a value of either of 'Connected' | 'Disconnected'
// it will also return reason, either of 'invalidToken' | 'connectionIssue'
}
callAgentInstance.on('connectionStateChanged', connectionStateCallback);
注意
此 API 以预览状态提供给开发者,可能根据我们收到的反馈更改。 请勿在生产环境中使用此 API。 若要使用此 API,使用 Azure 通信服务通话 Web SDK 的 beta 版本。
云录制
通话记录是核心呼叫 API 的扩展功能。 首先,需要从通话 SDK 导入通话功能:
import { Features} from "@azure/communication-calling";
然后,可从通话实例获取录制功能的 API 对象:
const callRecordingApi = call.feature(Features.Recording);
若要检查是否正在录制通话,请检查 callRecordingApi
的 isRecordingActive
属性。 它将返回 Boolean
。
const isRecordingActive = callRecordingApi.isRecordingActive;
还可以订阅录制更改:
const isRecordingActiveChangedHandler = () => {
console.log(callRecordingApi.isRecordingActive);
};
callRecordingApi.on('isRecordingActiveChanged', isRecordingActiveChangedHandler);
可使用 callRecordingApi
的 recordings
属性获取录制列表。 它将返回 RecordingInfo[]
,其中包含云录制的当前状态。
const recordings = callRecordingApi.recordings;
recordings.forEach(r => {
console.log("State: ${r.state}");
还可订阅 recordingsUpdated
并获取更新的录制的集合。 每当有录制更新时,就会触发此事件。
const cloudRecordingsUpdatedHandler = (args: { added: SDK.RecordingInfo[], removed: SDK.RecordingInfo[]}) => {
console.log('Recording started by: ');
args.added?.forEach(a => {
console.log('State: ${a.state}');
});
console.log('Recording stopped by: ');
args.removed?.forEach(r => {
console.log('State: ${r.state}');
});
};
callRecordingApi.on('recordingsUpdated', cloudRecordingsUpdatedHandler );
显式同意
当 Teams 会议或通话配置为需要显式同意才能进行录制和听录时,你需要先获得所有通话参与者的同意,然后才能录制对方通话内容。 参与者可以在加入会议时主动提供同意,也可以在录制开始时被动地提供同意。 在参与者提供显式同意之前,系统会在录制期间禁用参与者的音频、视频和屏幕共享功能。
参与者可以查看属性 isTeamsConsentRequired
,检查会议录制是否需要显式同意。 如果该值设置为 true
,则 call
需要显式同意。
const isConsentRequired = callRecordingApi.isTeamsConsentRequired;
如果已获得用户的录制同意,可以调用 grantTeamsConsent()
方法来指示对服务的显式同意。 此同意仅对一个 call
会话有效,如果用户重新加入会议,则需要再次提供同意。
callRecordingApi.grantTeamsConsent();
当录制功能可供使用且需用户显式同意时,如果用户没有提供显式同意,则其尝试启用音频、视频或屏幕共享时会失败。 用户可以检查 turnVideoOn
、unmuteMic
和 shareScreen
功能的 ParticipantCapabilities
类属性 reason
,以识别这种情况。 可以在函数 call.feature(Features.Capabilities)
中找到这些功能。 这些功能会在用户需要提供显式同意时返回原因 ExplicitConsentRequired
。
安装 SDK
找到项目级 build.gradle
文件,并将 mavenCentral()
添加到 buildscript
和 allprojects
下的存储库列表中:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
然后,在模块级 build.gradle
文件中,将以下行添加到 dependencies
部分:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
初始化所需的对象
若要创建 CallAgent
实例,必须对 CallClient
实例调用 createCallAgent
方法。 此调用将异步返回 CallAgent
实例对象。
createCallAgent
方法采用 CommunicationUserCredential
作为参数来封装访问令牌。
若要访问 DeviceManager
,必须先创建 callAgent
实例。 然后,可以使用 CallClient.getDeviceManager
方法获取 DeviceManager
。
String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an activity, for instance
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential).get();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
若要为主叫方设置显示名称,请使用以下替代方法:
String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an activity, for instance
CallAgentOptions callAgentOptions = new CallAgentOptions();
callAgentOptions.setDisplayName("Alice Bob");
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential, callAgentOptions).get();
录制通话
注意
此 API 以预览状态提供给开发者,可能根据我们收到的反馈更改。 请勿在生产环境中使用此 API。 若要使用此 API,使用 Azure 通信服务通话 Android SDK 的 beta 版本。
通话录制是核心 Call
对象的扩展功能。
警告
在 Azure 通信服务通话 Android SDK 的 1.1.0 版和 beta 版 1.1.0-beta.1 之前,isRecordingActive
和 addOnIsRecordingActiveChangedListener
是 Call
对象的一部分。 对于新的 beta 版本,这些 API 已作为 Call
的扩展功能移动。
首先需要获取录制功能对象:
RecordingCallFeature callRecordingFeature = call.feature(Features.RECORDING);
然后,若要检查是否正在录制通话,请检查 callRecordingFeature
的 isRecordingActive
属性。 它将返回 boolean
。
boolean isRecordingActive = callRecordingFeature.isRecordingActive();
还可以订阅录制更改:
private void handleCallOnIsRecordingChanged(PropertyChangedEvent args) {
boolean isRecordingActive = callRecordingFeature.isRecordingActive();
}
callRecordingFeature.addOnIsRecordingActiveChangedListener(handleCallOnIsRecordingChanged);
若要从应用程序开始录制,先按照通话录制概述中的步骤来设置通话录制。
在服务器上设置通话录制后,需要从 Android 应用程序中获取来自通话的 ServerCallId
值,然后将其发送到服务器以开始录制过程。 可使用 CallInfo
类中的 getServerCallId()
查找 ServerCallId
值。 可使用 getInfo()
在类对象中查找 CallInfo
类。
try {
String serverCallId = call.getInfo().getServerCallId().get();
// Send serverCallId to your recording server to start the call recording.
} catch (ExecutionException | InterruptedException e) {
} catch (UnsupportedOperationException unsupportedOperationException) {
}
从服务器开始录制时,事件 handleCallOnIsRecordingChanged
将触发,并且 callRecordingFeature.isRecordingActive()
的值为 true
。
就像开始通话录制一样,如果要停止通话录制,需要获取 ServerCallId
并将其发送到录制服务器,使其可停止录制:
try {
String serverCallId = call.getInfo().getServerCallId().get();
// Send serverCallId to your recording server to stop the call recording.
} catch (ExecutionException | InterruptedException e) {
} catch (UnsupportedOperationException unsupportedOperationException) {
}
从服务器停止录制时,事件 handleCallOnIsRecordingChanged
将触发,并且 callRecordingFeature.isRecordingActive()
的值为 false
。
设置系统
按照以下步骤设置系统。
创建 Xcode 项目
在 Xcode 中,创建新的 iOS 项目,并选择“单视图应用”模板。 本文使用 SwiftUI 框架,因此应将“语言”设置为“Swift”,并将“界面”设置为“SwiftUI”。
在本文中,无需创建测试。 请随意清除“包括测试”复选框。
使用 CocoaPods 安装包和依赖项
为应用程序创建 Podfile,如此示例所示:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
运行
pod install
。使用 Xcode 打开
.xcworkspace
。
请求访问麦克风
若要访问设备的麦克风,需要使用 NSMicrophoneUsageDescription
更新应用的信息属性列表。 将关联的值设置为一个字符串,该字符串将包含在系统用于向用户请求访问权限的对话框中。
右键单击项目树的 Info.plist 条目,然后选择“打开为...”>“源代码”。 将以下代码行添加到顶层 <dict>
节,然后保存文件。
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
设置应用框架
打开项目的 ContentView.swift
文件。 将 import
声明添加到文件顶部以导入 AzureCommunicationCalling
库。 此外,导入 AVFoundation
。 你需要用它来处理代码中的音频权限请求。
import AzureCommunicationCalling
import AVFoundation
初始化 CallAgent
若要从 CallClient
创建 CallAgent
实例,必须使用 callClient.createCallAgent
方法,该方法在初始化后异步返回 CallAgent
对象。
若要创建通话客户端,请传递 CommunicationTokenCredential
对象:
import AzureCommunication
let tokenString = "token_string"
var userCredential: CommunicationTokenCredential?
do {
let options = CommunicationTokenRefreshOptions(initialToken: token, refreshProactively: true, tokenRefresher: self.fetchTokenSync)
userCredential = try CommunicationTokenCredential(withOptions: options)
} catch {
updates("Couldn't created Credential object", false)
initializationDispatchGroup!.leave()
return
}
// tokenProvider needs to be implemented by Contoso, which fetches a new token
public func fetchTokenSync(then onCompletion: TokenRefreshOnCompletion) {
let newToken = self.tokenProvider!.fetchNewToken()
onCompletion(newToken, nil)
}
将创建的 CommunicationTokenCredential
对象传递给 CallClient
并设置显示名称:
self.callClient = CallClient()
let callAgentOptions = CallAgentOptions()
options.displayName = " iOS Azure Communication Services User"
self.callClient!.createCallAgent(userCredential: userCredential!,
options: callAgentOptions) { (callAgent, error) in
if error == nil {
print("Create agent succeeded")
self.callAgent = callAgent
} else {
print("Create agent failed")
}
})
录制通话
注意
此 API 以预览状态提供给开发者,可能根据我们收到的反馈更改。 请勿在生产环境中使用此 API。 若要使用此 API,使用 Azure 通信服务通话 iOS SDK 的 beta 版本。
通话录制是核心 Call
对象的扩展功能。
警告
在 Azure 通信服务通话 iOS SDK 的 1.1.0 版和 beta 版 1.1.0-beta.1 之前,isRecordingActive
是 Call
对象的一部分,并且 didChangeRecordingState
是 CallDelegate
委托的一部分。 对于新的 beta 版本,这些 API 已作为 Call
的扩展功能移动。
首先需要获取录制功能对象:
let callRecordingFeature = call.feature(Features.recording)
然后,若要检查是否正在录制通话,请检查 callRecordingFeature
的 isRecordingActive
属性。 它将返回 Bool
。
let isRecordingActive = callRecordingFeature.isRecordingActive;
还可以通过使用事件 RecordingCallFeatureDelegate
在类层级实现 didChangeRecordingState
委托,以订阅录制更改:
callRecordingFeature.delegate = self
// didChangeRecordingState is a member of RecordingCallFeatureDelegate
public func recordingCallFeature(_ recordingCallFeature: RecordingCallFeature, didChangeRecordingState args: PropertyChangedEventArgs) {
let isRecordingActive = recordingFeature.isRecordingActive
}
若要从应用程序开始录制,先按照通话录制概述中的步骤来设置通话录制。
在服务器上设置通话录制后,需要从 iOS 应用程序中获取来自通话的 ServerCallId
值,然后将其发送到服务器以开始录制过程。 可使用 CallInfo
类中的 getServerCallId()
查找 ServerCallId
值。 可使用 getInfo()
在类对象中查找 CallInfo
类。
// Send serverCallId to your recording server to start the call recording.
let serverCallId = call.info.getServerCallId(){ (serverId, error) in }
从服务器开始录制时,事件 didChangeRecordingState
将触发,并且 recordingFeature.isRecordingActive
的值为 true
。
就像开始通话录制一样,如果要停止通话录制,需要获取 ServerCallId
并将其发送到录制服务器,使其可停止录制:
// Send serverCallId to your recording server to stop the call recording.
let serverCallId = call.info.getServerCallId(){ (serverId, error) in }
从服务器停止录制时,事件 didChangeRecordingState
将触发,并且 recordingFeature.isRecordingActive
的值为 false
。
设置系统
按照以下步骤设置系统。
创建 Visual Studio 项目
对于通用 Windows 平台应用,请在 Visual Studio 2022 中创建新的“空白应用(通用 Windows)”项目。 输入项目名称后,可随意选择任何版本高于 10.0.17763.0 的 Windows SDK。
对于 WinUI 3 应用,请使用“已打包空白应用(桌面中的 WinUI 3)”模板创建新项目,以设置单页 WinUI 3 应用。 需要 Windows App SDK 版本 1.3 或更高版本。
使用 NuGet 包管理器安装包和依赖项
可通过 NuGet 包公开提供通话 SDK API 和库。
要查找、下载和安装通话 SDK NuGet 包,请执行以下操作:
- 选择“工具”>“NuGet 包管理器”>“管理解决方案的 NuGet 包”,以打开 NuGet 包管理器。
- 选择“浏览”,然后在搜索框中输入 Azure.Communication.Calling.WindowsClient。
- 确保已选中“包括预发行版”复选框。
- 选择 Azure.Communication.Calling.WindowsClient 包,然后选择 Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 或更新版本。
- 在右侧窗格中选中与 Azure 通信服务项目对应的复选框。
- 选择“安装” 。
录制通话
通话录制是核心 Call
对象的扩展功能。 首先需要获取录制功能对象:
RecordingCallFeature recordingFeature = call.Features.Recording;
然后,若要检查是否正在录制通话,请检查 recordingFeature
的 IsRecordingActive
属性。 它将返回 boolean
。
boolean isRecordingActive = recordingFeature.IsRecordingActive;
还可以订阅录制更改:
private async void Call__OnIsRecordingActiveChanged(object sender, PropertyChangedEventArgs args)
boolean isRecordingActive = recordingFeature.IsRecordingActive;
}
recordingFeature.IsRecordingActiveChanged += Call__OnIsRecordingActiveChanged;
合规录制
合规录制是基于 Microsoft Teams 策略的录制。 可使用本教程启用此功能:Teams 基于策略的通话录制简介。
当拥有策略的用户加入通话时,基于策略的录制会自动开始。 若要从 Azure 通信服务获取有关录制的通知,请使用以下代码:
const callRecordingApi = call.feature(Features.Recording);
const isComplianceRecordingActive = callRecordingApi.isRecordingActive;
const isComplianceRecordingActiveChangedHandler = () => {
console.log(callRecordingApi.isRecordingActive);
};
callRecordingApi.on('isRecordingActiveChanged', isComplianceRecordingActiveChangedHandler);
还可使用自定义录制机器人实现合规录制。 请参阅 GitHub 示例。