管理通話

瞭解如何使用 Azure 通訊服務 SDKS 來管理呼叫。 我們將瞭解如何撥打電話、管理其參與者和屬性。

必要條件

安裝 SDK

npm install使用 命令來安裝適用于 JavaScript 的Azure 通訊服務呼叫和一般 SDK。

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

初始化必要的物件

大部分呼叫作業都需要 CallClient 實例。 讓我們建立新的 CallClient 實例。 您可以使用記錄器實例之類的自訂選項進行設定。

當您有 CallClient 實例時,可以在 實例上 CallClient 呼叫 createCallAgent 方法來建立 CallAgent 實例。 這個方法會以非同步方式傳 CallAgent 回實例物件。

方法會 createCallAgent 使用 CommunicationTokenCredential 做為引數。 它會接受 使用者存取權杖

您可以使用 getDeviceManager 實例上的 CallClient 方法來存取 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 wherever desired. To console, file, buffer, REST API, etc...
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()

撥打電話

若要建立並啟動呼叫,請使用 上的其中一個 API callAgent ,並提供您透過通訊服務身分識別 SDK 建立的使用者。

呼叫建立和啟動是同步的。 call實例可讓您訂閱呼叫事件。

對使用者或 PSTN 撥打 1:n 通話

若要呼叫另一個通訊服務使用者,請使用 startCall 上的 方法來 callAgent 傳遞您使用通訊服務管理程式庫建立CommunicationUserIdentifier 收件者。

針對對使用者的 1:1 呼叫,請使用下列程式碼:

const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const oneToOneCall = callAgent.startCall([userCallee]);

若要撥打公用交換電話網路 (PSTN) ,請使用 startCall 方法 callAgent ,並傳遞收件者的 PhoneNumberIdentifier 。 您的通訊服務資源必須設定為允許 PSTN 通話。

當您撥打 PSTN 號碼時,請指定您的替代來電者識別碼。 替代的來電者識別碼是根據 E.164 標準) 來識別 PSTN 通話中的來電者的電話號碼 (。 這是來電收件者看到的來電電話號碼。

注意

PSTN 通話目前處於私人預覽狀態。 如需存取權, 請套用至早期採用者計畫

如需對 PSTN 號碼的 1:1 通話,請使用下列程式碼:

const pstnCallee = { phoneNumber: '<ACS_USER_ID>' }
const alternateCallerId = {phoneNumber: '<ALTERNATE_CALLER_ID>'};
const oneToOneCall = callAgent.startCall([pstnCallee], {alternateCallerId});

如需對使用者和 PSTN 號碼的 1:n 通話,請使用下列程式碼:

const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const pstnCallee = { phoneNumber: '<PHONE_NUMBER>'};
const alternateCallerId = {phoneNumber: '<ALTERNATE_CALLER_ID>'};
const groupCall = callAgent.startCall([userCallee, pstnCallee], {alternateCallerId});

加入群組通話

注意

參數 groupId 會被視為系統中繼資料,而且可由Microsoft用於執行系統所需的作業。 請勿在 groupId 值中包含個人資料。 Microsoft不會將此參數視為個人資料,而且其內容可能會Microsoft員工或長期儲存。

參數 groupId 需要資料以 GUID 格式表示。 建議您使用隨機產生的 GUID,這些 GUID 不會被視為您系統中的個人資料。

若要啟動新的群組呼叫或加入進行中的群組呼叫,請使用 join 方法並傳遞 具有 groupId 屬性的物件。 值 groupId 必須是 GUID。

const context = { groupId: '<GUID>'};
const call = callAgent.join(context);

接收來電

callAgent 登入的身分識別收到來電時,實例會發出 incomingCall 事件。 若要接聽此事件,請使用下列其中一個選項來訂閱:

const incomingCallHandler = async (args: { incomingCall: IncomingCall }) => {
    const incomingCall = args.incomingCall;	

    // Get incoming call ID
    var incomingCallId = incomingCall.id

    // Get information about this Call. This API is provided as a preview for developers
    // and may change based on feedback that we receive. Do not use this API in a production environment.
    // To use this api please use 'beta' release of Azure Communication Services Calling Web SDK
    var callInfo = incomingCall.info;

    // Get information about caller
    var callerInfo = incomingCall.callerInfo

    // Accept the call
    var call = await incomingCall.accept();

    // Reject the call
    incomingCall.reject();

    // Subscribe to callEnded event and get the call end reason
     incomingCall.on('callEnded', args => {
        console.log(args.callEndReason);
    });

    // callEndReason is also a property of IncomingCall
    var callEndReason = incomingCall.callEndReason;
};
callAgentInstance.on('incomingCall', incomingCallHandler);

事件 incomingCall 包含 incomingCall 您可以接受或拒絕的實例。

當啟動/加入/接受具有視訊的通話時,如果指定的視訊相機裝置正由另一個進程使用,或是在系統中停用,則通話會以視訊關閉開始,而且會引發 cameraStartFailed:true 通話診斷。

靜音和取消靜音

若要將本機端點設為靜音或取消靜音,您可以使用 muteunmute 非同步 API:

//mute local device (microphone / sent audio)
await call.mute();

//unmute local device (microphone / sent audio)
await call.unmute();

將傳入音訊靜音和取消靜音

將傳入音訊設為靜音會將通話音量設為 0。 若要將傳入音訊靜音或取消靜音,您可以使用 muteIncomingAudiounmuteIncomingAudio 非同步 API:

//mute local device (speaker)
await call.muteIncomingAudio();

//unmute local device (speaker)
await call.unmuteIncomingAudio();

當傳入音訊設為靜音時,參與者仍會收到通話音訊, (遠端參與者的音訊) 。 在呼叫 'call.unmuteIncomingAudio () ' 之前,通話音訊不會在說話者中暫停,參與者將無法接聽。 不過,我們可以在通話音訊上套用篩選,並播放篩選的音訊。

管理遠端參與者

所有遠端參與者都會以 RemoteParticipant 類型表示,並透過 remoteParticipants 呼叫實例上的集合來提供。

列出通話中的參與者

集合會 remoteParticipants 傳回通話中的遠端參與者清單:

call.remoteParticipants; // [remoteParticipant, remoteParticipant....]

將參與者新增至通話

若要將參與者 (使用者或電話號碼) 新增至通話,您可以使用 addParticipant 。 提供其中 Identifier 一種類型。 它會以同步方式傳 remoteParticipant 回 實例。 remoteParticipantsUpdated成功將參與者新增至通話時,就會引發來自 Call 的事件。

const userIdentifier = { communicationUserId: '<ACS_USER_ID>' };
const pstnIdentifier = { phoneNumber: '<PHONE_NUMBER>' }
const remoteParticipant = call.addParticipant(userIdentifier);
const remoteParticipant = call.addParticipant(pstnIdentifier, {alternateCallerId: '<ALTERNATE_CALLER_ID>'});

從通話中移除參與者

若要從通話中移除參與者 (使用者或電話號碼) ,您可以叫用 removeParticipant 。 您必須傳遞其中一種 Identifier 類型。 此方法會在從呼叫中移除參與者之後,以非同步方式解析。 參與者也會從 remoteParticipants 集合中移除。

const userIdentifier = { communicationUserId: '<ACS_USER_ID>' };
const pstnIdentifier = { phoneNumber: '<PHONE_NUMBER>' }
await call.removeParticipant(userIdentifier);
await call.removeParticipant(pstnIdentifier);

存取遠端參與者屬性

遠端參與者有一組相關聯的屬性和集合:

  • CommunicationIdentifier:取得遠端參與者的識別碼。 身分識別是其中 CommunicationIdentifier 一種類型:

    const identifier = remoteParticipant.identifier;
    

它可以是下列 CommunicationIdentifier 其中一種類型:

  • { communicationUserId: '<ACS_USER_ID'> }:代表Azure 通訊服務使用者的物件。

  • { phoneNumber: '<E.164>' }:物件,表示 E.164 格式的電話號碼。

  • { microsoftTeamsUserId: '<TEAMS_USER_ID>', isAnonymous?: boolean; cloud?: "public" | "dod" | "gcch" }:代表 Teams 使用者的物件。

  • { id: string }:物件,表示不符合任何其他識別碼類型的識別碼

  • state:取得遠端參與者的狀態。

    const state = remoteParticipant.state;
    

狀態可以是:

  • Idle:初始狀態。

  • Connecting:參與者連線到通話時的轉換狀態。

  • Ringing:參與者正在響鈴。

  • Connected:參與者已連線到通話。

  • Hold:參與者處於保留狀態。

  • EarlyMedia:參與者連線到通話之前播放的公告。

  • InLobby:表示遠端參與者位於大廳。

  • Disconnected:最終狀態。 參與者與通話中斷連線。 如果遠端參與者失去其網路連線能力,其狀態會在兩分鐘後變更 Disconnected

  • callEndReason:若要瞭解參與者為何離開通話,請檢查 callEndReason 屬性:

    const callEndReason = remoteParticipant.callEndReason;
    const callEndReasonCode = callEndReason.code // (number) code associated with the reason
    const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason
    

    注意:

    • 只有在透過 Call.addParticipant () API 新增遠端參與者時,才會設定這個屬性,而遠端參與者則例如拒絕。
    • 例如,在 UserB 從 UserA 的觀點開始 UserC 的情況下,UserA 不會看到此旗標設定為 UserC。 換句話說,UserA 不會看到 UserC 的 callEndReason 屬性完全設定。
  • isMuted status:若要找出遠端參與者是否靜音,請檢查 isMuted 屬性。 它會傳回 Boolean

    const isMuted = remoteParticipant.isMuted;
    
  • isSpeaking status:若要找出遠端參與者是否正在說話,請檢查 isSpeaking 屬性。 它會傳回 Boolean

    const isSpeaking = remoteParticipant.isSpeaking;
    
  • videoStreams:若要檢查指定參與者在此通話中傳送的所有視訊串流,請檢查 videoStreams 集合。 它包含 RemoteVideoStream 物件。

    const videoStreams = remoteParticipant.videoStreams; // [RemoteVideoStream, ...]
    
  • displayName:若要取得此遠端參與者的顯示名稱,請檢查 displayName 它傳回字串的屬性。

    const displayName = remoteParticipant.displayName;
    

檢查呼叫屬性

取得呼叫的唯一識別碼 (字串) :

const callId: string = call.id;

取得通話的相關資訊:

注意

此 API 僅供開發人員預覽,而且可能會根據收到的意見反應變更。 請勿將此 API 用於生產環境。 若要使用此 API,請使用 Azure 通訊服務呼叫 Web SDK 的 'Beta' 版本

const callInfo = call.info;

藉由檢查 remoteParticipants 'call' 實例上的集合,瞭解通話中的其他參與者:

const remoteParticipants = call.remoteParticipants;

識別來電的來電者:

const callerIdentity = call.callerInfo.identifier;

identifier 是其中一種 CommunicationIdentifier 類型。

取得呼叫的狀態:

const callState = call.state;

這會傳回字串,代表呼叫的目前狀態:

  • None:初始撥號狀態。
  • Connecting:在撥打或接受呼叫時的初始轉換狀態。
  • Ringing:針對撥出通話,表示遠端參與者的通話正在撥打。 Incoming其位於其端。
  • EarlyMedia:指出在呼叫連線之前播放公告的狀態。
  • Connected:指出呼叫已連線。
  • LocalHold:指出本機參與者會保留通話。 本機端點與遠端參與者之間沒有媒體流動。
  • RemoteHold:指出遠端參與者已保留通話。 本機端點與遠端參與者之間沒有媒體流動。
  • InLobby:表示使用者位於大廳。
  • Disconnecting:呼叫進入 Disconnected 狀態之前轉換狀態。
  • Disconnected:最終撥號狀態。 如果網路連線遺失,狀態會在兩分鐘後變更 Disconnected 為 。

檢查 屬性來找出通話結束 callEndReason 的原因:

const callEndReason = call.callEndReason;
const callEndReasonCode = callEndReason.code // (number) code associated with the reason
const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason

藉由檢查 direction 屬性,瞭解目前的呼叫是否傳入或傳出。 它會傳回 CallDirection

const isIncoming = call.direction == 'Incoming';
const isOutgoing = call.direction == 'Outgoing';

檢查目前的麥克風是否已靜音。 它會傳回 Boolean

const muted = call.isMuted;

檢查目前的傳入音訊 (喇叭) 是否靜音。 它會傳回 Boolean

const incomingAudioMuted = call._isIncomingAudioMuted;

檢查 屬性,以瞭解螢幕共用串流是否從指定的端點 isScreenSharingOn 傳送。 它會傳回 Boolean

const isScreenSharingOn = call.isScreenSharingOn;

檢查集合來檢查作用中的 localVideoStreams 視訊串流。 它會傳 LocalVideoStream 回 物件。

const localVideoStreams = call.localVideoStreams;

安裝 SDK

找出您的專案層級 build.gradle,並務必將 mavenCentral() 新增至 buildscriptallprojects 下的存放庫清單

buildscript {
    repositories {
    ...
        mavenCentral()
    ...
    }
}
allprojects {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

然後,在您的模組層級 build.gradle 中,將下列幾行新增至相依性區段

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();

撥打電話

若要建立並啟動呼叫,您需要呼叫 CallAgent.startCall() 方法,並提供 Identifier 被呼叫者 (的) 。 若要加入群組呼叫,您需要呼叫 CallAgent.join() 方法並提供 groupId。 群組識別碼必須是 GUID 或 UUID 格式。

呼叫建立和啟動是同步的。 呼叫實例可讓您訂閱呼叫上的所有事件。

對使用者撥打 1:1 通話

若要呼叫另一個通訊服務使用者,請在 上 callAgentcall 用 方法,並使用索引鍵傳遞 物件 communicationUserId

StartCallOptions startCallOptions = new StartCallOptions();
Context appContext = this.getApplicationContext();
CommunicationUserIdentifier acsUserId = new CommunicationUserIdentifier(<USER_ID>);
CommunicationUserIdentifier participants[] = new CommunicationUserIdentifier[]{ acsUserId };
call oneToOneCall = callAgent.startCall(appContext, participants, startCallOptions);

與使用者和 PSTN 撥打 1:n 通話

警告

目前無法使用 PSTN 通話

若要對使用者和 PSTN 號碼撥打 1:n 通話,您必須指定被呼叫者電話號碼。 您的通訊服務資源必須設定為允許 PSTN 通話:

CommunicationUserIdentifier acsUser1 = new CommunicationUserIdentifier(<USER_ID>);
PhoneNumberIdentifier acsUser2 = new PhoneNumberIdentifier("<PHONE_NUMBER>");
CommunicationIdentifier participants[] = new CommunicationIdentifier[]{ acsUser1, acsUser2 };
StartCallOptions startCallOptions = new StartCallOptions();
Context appContext = this.getApplicationContext();
Call groupCall = callAgent.startCall(participants, startCallOptions);

接受通話

若要接受呼叫,請在呼叫物件上呼叫 'accept' 方法。

Context appContext = this.getApplicationContext();
IncomingCall incomingCall = retrieveIncomingCall();
Call call = incomingCall.accept(context).get();

若要在上接受具有視訊相機的通話:

Context appContext = this.getApplicationContext();
IncomingCall incomingCall = retrieveIncomingCall();
AcceptCallOptions acceptCallOptions = new AcceptCallOptions();
VideoDeviceInfo desiredCamera = callClient.getDeviceManager().get().getCameraList().get(0);
acceptCallOptions.setVideoOptions(new VideoOptions(new LocalVideoStream(desiredCamera, appContext)));
Call call = incomingCall.accept(context, acceptCallOptions).get();

透過訂閱 onIncomingCall 物件上的 callAgent 事件,即可取得撥入電話:

// Assuming "callAgent" is an instance property obtained by calling the 'createCallAgent' method on CallClient instance 
public Call retrieveIncomingCall() {
    IncomingCall incomingCall;
    callAgent.addOnIncomingCallListener(new IncomingCallListener() {
        void onIncomingCall(IncomingCall inboundCall) {
            // Look for incoming call
            incomingCall = inboundCall;
        }
    });
    return incomingCall;
}

加入群組通話

若要啟動新的群組呼叫或加入進行中的群組呼叫,您必須呼叫 'join' 方法,並使用 屬性傳遞 物件 groupId 。 值必須是 GUID。

Context appContext = this.getApplicationContext();
GroupCallLocator groupCallLocator = new GroupCallLocator("<GUID>");
JoinCallOptions joinCallOptions = new JoinCallOptions();

call = callAgent.join(context, groupCallLocator, joinCallOptions);

呼叫屬性

取得此通話的唯一識別碼:

String callId = call.getId();

若要瞭解 實例上 call 呼叫檢查 remoteParticipant 集合中的其他參與者:

List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants();

如果呼叫是傳入的,則呼叫端的身分識別:

CommunicationIdentifier callerId = call.getCallerInfo().getIdentifier();

取得通話的狀態:

CallState callState = call.getState();

它會傳回字串,代表呼叫的目前狀態:

  • 'NONE' - 初始撥號狀態
  • 'EARLY_MEDIA' - 指出在呼叫連線之前播放公告的狀態
  • 'CONNECTING' - 一旦撥打或接受呼叫後的初始轉換狀態
  • 'RINGING' - 用於撥出通話 - 表示通話正在撥打遠端參與者
  • 'CONNECTED' - 通話已連線
  • 'LOCAL_HOLD' - 本機參與者會保留通話,本機端點與遠端參與者之間不會流動任何媒體 ()
  • 'REMOTE_HOLD' - 遠端參與者會保留通話,本機端點與遠端參與者之間不會流動任何媒體 ()
  • 'DISCONNECTING' - 呼叫前的轉換狀態進入 [已中斷連線] 狀態
  • 'DISCONNECTED' - 最終撥號狀態
  • 'IN_LOBBY' - Teams 會議互通性的大廳

若要瞭解通話結束的原因,請檢查 callEndReason 屬性。 它包含程式碼/副程式代碼:

CallEndReason callEndReason = call.getCallEndReason();
int code = callEndReason.getCode();
int subCode = callEndReason.getSubCode();

若要查看目前的呼叫是否為傳入或撥出電話,請檢查 callDirection 屬性:

CallDirection callDirection = call.getCallDirection(); 
// callDirection == CallDirection.INCOMING for incoming call
// callDirection == CallDirection.OUTGOING for outgoing call

若要查看目前的麥克風是否已靜音,請檢查 muted 屬性:

boolean muted = call.isMuted();

若要檢查使用中的 localVideoStreams 視訊串流,請檢查集合:

List<LocalVideoStream> localVideoStreams = call.getLocalVideoStreams();

靜音和取消靜音

若要將本機端點靜音或取消靜音,您可以使用 muteunmute 非同步 API:

Context appContext = this.getApplicationContext();
call.mute(appContext).get();
call.unmute(appContext).get();

變更呼叫的磁片區

當您在通話中時,電話上的硬體磁片區金鑰應該允許使用者變更通話音量。 做法是使用 方法 setVolumeControlStream 搭配要放置呼叫之 Activity 上的資料流程類型 AudioManager.STREAM_VOICE_CALL 。 這可讓硬體音量鍵變更電話 (由電話圖示或音量滑杆上的類似專案) ,防止變更其他聲音設定檔的音量,例如警示、媒體或全系統音量。 如需詳細資訊,您可以檢查 處理音訊輸出中的變更|Android 開發人員

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
}

遠端參與者管理

所有遠端參與者都是以 RemoteParticipant 類型表示, remoteParticipants 而且可透過呼叫實例上的集合取得。

列出通話中的參與者

集合會 remoteParticipants 傳回指定呼叫中的遠端參與者清單:

List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants(); // [remoteParticipant, remoteParticipant....]

將參與者新增至通話

若要將參與者新增至 (使用者或電話號碼,) 您可以叫用 addParticipant 。 這會同步傳回遠端參與者實例。

const acsUser = new CommunicationUserIdentifier("<acs user id>");
const acsPhone = new PhoneNumberIdentifier("<phone number>");
RemoteParticipant remoteParticipant1 = call.addParticipant(acsUser);
AddPhoneNumberOptions addPhoneNumberOptions = new AddPhoneNumberOptions(new PhoneNumberIdentifier("<alternate phone number>"));
RemoteParticipant remoteParticipant2 = call.addParticipant(acsPhone, addPhoneNumberOptions);

從通話中移除參與者

若要從通話中移除參與者, (使用者或電話號碼) 您可以叫用 removeParticipant 。 從呼叫中移除參與者之後,這會以非同步方式解析。 參與者也會從 remoteParticipants 集合中移除。

RemoteParticipant acsUserRemoteParticipant = call.getParticipants().get(0);
RemoteParticipant acsPhoneRemoteParticipant = call.getParticipants().get(1);
call.removeParticipant(acsUserRemoteParticipant).get();
call.removeParticipant(acsPhoneRemoteParticipant).get();

遠端參與者屬性

任何指定的遠端參與者都有一組與其相關聯的屬性和集合:

  • 取得此遠端參與者的識別碼。 身分識別是其中一種「識別碼」類型

    CommunicationIdentifier participantIdentifier = remoteParticipant.getIdentifier();
    
  • 取得此遠端參與者的狀態。

    ParticipantState state = remoteParticipant.getState();
    

狀態可以是下列其中一項

  • 'IDLE' - 初始狀態

  • 'EARLY_MEDIA' - 在參與者連線到通話之前播放公告

  • 'RINGING' - 參與者通話正在響鈴

  • 'CONNECTING' - 參與者連線到通話時的轉換狀態

  • 'CONNECTED' - 參與者已連線到通話

  • 'HOLD' - 參與者處於保留狀態

  • 'IN_LOBBY' - 參與者正在等候大廳接受。 目前僅適用于 Teams Interop 案例

  • 'DISCONNECTED' - 最終狀態 - 參與者與通話中斷連線

  • 若要瞭解參與者為何離開通話,請檢查 callEndReason 屬性:

    CallEndReason callEndReason = remoteParticipant.getCallEndReason();
    
  • 若要檢查此遠端參與者是否為靜音,請檢查 isMuted 屬性:

    boolean isParticipantMuted = remoteParticipant.isMuted();
    
  • 若要檢查此遠端參與者是否說話,請檢查 isSpeaking 屬性:

    boolean isParticipantSpeaking = remoteParticipant.isSpeaking();
    
  • 若要檢查指定參與者在此通話中傳送的所有視訊串流,請檢查 videoStreams 集合:

    List<RemoteVideoStream> videoStreams = remoteParticipant.getVideoStreams(); // [RemoteVideoStream, RemoteVideoStream, ...]
    

使用前景服務

如果您想要執行使用者可見的工作,即使應用程式處於背景,您也可以使用 前景服務

例如,使用前景服務,您可以在應用程式有作用中的呼叫時,讓使用者看見通知。 如此一來,即使使用者移至主畫面或從 最近畫面移除應用程式,呼叫仍會繼續作用中。

如果您在呼叫時未使用前景服務,巡覽至主畫面可能會讓呼叫保持作用中,但如果 Android OS 終止應用程式的程式,則從最近畫面移除應用程式可能會停止呼叫。

您應該在啟動/加入呼叫時啟動 Foreground 服務,例如:

call = callAgent.startCall(context, participants, options);
startService(yourForegroundServiceIntent);

當您停止呼叫或呼叫的狀態為 [已中斷連線] 時,請停止 Foreground 服務,例如:

call.hangUp(new HangUpOptions()).get();
stopService(yourForegroundServiceIntent);

使用前景服務的注意事項

請記住,從最近清單移除應用程式時停止已執行的 Foreground Service 等案例,將會移除使用者可見的通知,而 Android OS 可以讓應用程式程式保持運作一段時間,這表示此期間仍可作用中的呼叫。

例如,如果您的應用程式在服務 onTaskRemoved 方法上停止 Foreground Service,您的應用程式可以根據活動 生命週期 啟動/停止音訊和視訊,例如使用 方法覆寫終結 onDestroy 活動時停止音訊和視訊。

設定系統

建立 Xcode 專案

在 Xcode 中建立新的 iOS 專案,並選取 [單一檢視應用程式] 範本。 本快速入門使用SwiftUI 架構,因此您應該將[語言] 設定為 Swift,並將[使用者介面] 設定為SwiftUI

在本快速入門中,您不會建立單元測試或 UI 測試。 您可以清除 [ 包含單元測試 ] 和 [ 包含 UI 測試 ] 文字方塊。

此螢幕擷取畫面顯示用於在 Xcode 中建立專案的視窗。

使用 CocoaPods 安裝套件和相依性

  1. 為您的應用程式建立 Podfile,如下所示:

    platform :ios, '13.0'
    use_frameworks!
    target 'AzureCommunicationCallingSample' do
        pod 'AzureCommunicationCalling', '~> 1.0.0'
    end
    
  2. 執行 pod install

  3. 使用 Xcode 開啟 .xcworkspace

要求存取麥克風

若要存取裝置的麥克風,您必須使用 NSMicrophoneUsageDescription 更新應用程式的資訊屬性清單。 您會將相關聯的值設定為 string ,此值將會包含在系統用來要求使用者存取的對話方塊中。

以滑鼠右鍵按一下專案樹狀結構的 Info.plist 項目,然後選取 [開啟形式] > [原始程式碼]。 在最上層 <dict> 區段中新增下列幾行,然後儲存檔案。

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>

設定應用程式架構

開啟專案的 ContentView.swift 檔案,並將宣告新增 import 至檔案頂端以匯入連結 AzureCommunicationCalling 庫。 此外,匯入 AVFoundation 。 您將需要它,才能在程式碼中要求音訊許可權。

import AzureCommunicationCalling
import AVFoundation

初始化 CallAgent

若要從 建立 CallAgent 實例,您必須使用 callClient.createCallAgent 方法,以非同步方式在物件初始化之後傳回 CallAgent 物件。 CallClient

若要建立呼叫用戶端,您必須傳遞 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")
        }
})

注意

當應用程式實作事件委派時,它必須保存需要事件訂閱之物件的強式參考。 例如,在 RemoteParticipant 叫用 方法時傳回 物件, call.addParticipant 而應用程式設定要接 RemoteParticipantDelegate 聽的 RemoteParticipant 委派時,應用程式必須保存物件的強式參考。 否則,如果收集這個物件,當呼叫 SDK 嘗試叫用物件時,委派將會擲回嚴重例外狀況。

撥打撥出電話

若要建立並啟動呼叫,您必須在 上 CallAgent 呼叫其中一個 API,並提供您已使用通訊服務管理 SDK 布建之使用者的通訊服務身分識別。

呼叫建立和啟動是同步的。 您會收到呼叫實例,可讓您訂閱呼叫上的所有事件。

對使用者撥打 1:1 通話,或使用使用者和 PSTN 撥打 1:n 通話

let callees = [CommunicationUser(identifier: 'UserId')]
self.callAgent?.startCall(participants: callees, options: StartCallOptions()) { (call, error) in
     if error == nil {
         print("Successfully started outgoing call")
         self.call = call
     } else {
         print("Failed to start outgoing call")
     }
}

與使用者和 PSTN 撥打 1:n 通話

若要撥打 PSTN 電話,您必須指定使用通訊服務取得的電話號碼。

let pstnCallee = PhoneNumberIdentifier(phoneNumber: '+1999999999')
let callee = CommunicationUserIdentifier('UserId')
self.callAgent?.startCall(participants: [pstnCallee, callee], options: StartCallOptions()) { (groupCall, error) in
     if error == nil {
         print("Successfully started outgoing call to multiple participants")
         self.call = groupCall
     } else {
         print("Failed to start outgoing call to multiple participants")
     }
}

加入群組通話

若要加入呼叫,您必須在 上 CallAgent 呼叫其中一個 API。

let groupCallLocator = GroupCallLocator(groupId: UUID(uuidString: "uuid_string")!)
self.callAgent?.join(with: groupCallLocator, joinCallOptions: JoinCallOptions()) { (call, error) in
    if error == nil {
        print("Successfully joined group call")
        self.call = call
    } else {
        print("Failed to join group call")
    }
}

訂閱來電

訂閱連入呼叫事件。

final class IncomingCallHandler: NSObject, CallAgentDelegate, IncomingCallDelegate
{
    // Event raised when there is an incoming call
    public func callAgent(_ callAgent: CallAgent, didReceiveIncomingCall incomingcall: IncomingCall) {
        self.incomingCall = incomingcall
        // Subscribe to get OnCallEnded event
        self.incomingCall?.delegate = self
    }

    // Event raised when incoming call was not answered
    public func incomingCall(_ incomingCall: IncomingCall, didEnd args: PropertyChangedEventArgs) {
        print("Incoming call was not answered")
        self.incomingCall = nil
    }
}

接受來電

若要接受呼叫,請在 物件上 IncomingCall 呼叫 accept 方法。

self.incomingCall!.accept(options: AcceptCallOptions()) { (call, error) in
   if (error == nil) {
       print("Successfully accepted incoming call")
       self.call = call
   } else {
       print("Failed to accept incoming call")
   }
}

let firstCamera: VideoDeviceInfo? = self.deviceManager!.cameras.first
localVideoStreams = [LocalVideoStream]()
localVideoStreams!.append(LocalVideoStream(camera: firstCamera!))
let acceptCallOptions = AcceptCallOptions()
acceptCallOptions.videoOptions = VideoOptions(localVideoStreams: localVideoStreams!)
if let incomingCall = self.incomingCall {
    incomingCall.accept(options: acceptCallOptions) { (call, error) in
        if error == nil {
            print("Incoming call accepted")
        } else {
            print("Failed to accept incoming call")
        }
    }
} else {
  print("No incoming call found to accept")
}

執行中呼叫作業

您可以在呼叫期間執行各種作業,以管理與視訊和音訊相關的設定。

靜音和取消靜音

若要將本機端點設為靜音或取消靜音,您可以使用 muteunmute 非同步 API。

call!.mute { (error) in
    if error == nil {
        print("Successfully muted")
    } else {
        print("Failed to mute")
    }
}

使用下列程式碼以非同步方式取消本機端點的靜音。

call!.unmute { (error) in
    if error == nil {
        print("Successfully un-muted")
    } else {
        print("Failed to unmute")
    }
}

管理遠端參與者

所有遠端參與者都是以 型別表示, RemoteParticipant 而且可透過 remoteParticipants 呼叫實例上的集合取得。

列出通話中的參與者

call.remoteParticipants

將參與者新增至通話

若要將參與者新增至 (使用者或電話號碼) 的通話,您可以叫用 addParticipant 。 此命令會同步傳回遠端參與者實例。

let remoteParticipantAdded: RemoteParticipant = call.add(participant: CommunicationUserIdentifier(identifier: "userId"))

從通話中移除參與者

若要從使用者或電話號碼) (來移除參與者,您可以叫用 removeParticipant API。 這會以非同步方式解析。

call!.remove(participant: remoteParticipantAdded) { (error) in
    if (error == nil) {
        print("Successfully removed participant")
    } else {
        print("Failed to remove participant")
    }
}

取得遠端參與者屬性

// [RemoteParticipantDelegate] delegate - an object you provide to receive events from this RemoteParticipant instance
var remoteParticipantDelegate = remoteParticipant.delegate

// [CommunicationIdentifier] identity - same as the one used to provision a token for another user
var identity = remoteParticipant.identifier

// ParticipantStateIdle = 0, ParticipantStateEarlyMedia = 1, ParticipantStateConnecting = 2, ParticipantStateConnected = 3, ParticipantStateOnHold = 4, ParticipantStateInLobby = 5, ParticipantStateDisconnected = 6
var state = remoteParticipant.state

// [Error] callEndReason - reason why participant left the call, contains code/subcode/message
var callEndReason = remoteParticipant.callEndReason

// [Bool] isMuted - indicating if participant is muted
var isMuted = remoteParticipant.isMuted

// [Bool] isSpeaking - indicating if participant is currently speaking
var isSpeaking = remoteParticipant.isSpeaking

// RemoteVideoStream[] - collection of video streams this participants has
var videoStreams = remoteParticipant.videoStreams // [RemoteVideoStream, RemoteVideoStream, ...]

設定

建立 Visual Studio 專案

針對 UWP 應用程式,在 Visual Studio 2019 中建立新的 Blank App (Universal Windows) 專案。 輸入專案名稱之後,您可以隨意挑選大於 10.0.17134 的任何 Windows SDK。

針對 WinUI 3 應用程式,使用 Blank App, Packaged (WinUI 3 in Desktop) 範本建立新的專案,以設定單頁 WinUI 3 應用程式。 Windows 應用程式 SDK 1.2 版 Preview 2和更新版本是必要的。

使用 NuGet 套件管理員安裝套件和相依性

呼叫 SDK API 和程式庫可透過 NuGet 套件公開取得。 下列步驟示範如何尋找、下載及安裝呼叫 SDK NuGet 套件。

  1. 開啟 NuGet 套件管理員 Tools (-) >Manage NuGet Packages for Solution>NuGet Package Manager
  2. 按一下 Browse ,然後在搜尋方塊中輸入 Azure.Communication.Calling
  3. 請確定 Include prerelease 已選取核取方塊。
  4. Azure.Communication.Calling按一下套件,選取 Azure.Communication.Calling1.0.0-Beta.33或更新版本。
  5. 選取對應至右側索引標籤上 CS 專案的核取方塊。
  6. 按一下 []Install 按鈕。

要求存取麥克風

應用程式需要存取麥克風才能正常執行。 在 UWP 應用程式中,麥克風功能應該在應用程式資訊清單檔案中宣告。 他遵循下列步驟會示範如何達成該目標。

  1. Solution Explorer在面板中,按兩下副檔名為的 .appxmanifest 檔案。
  2. 按一下索引 Capabilities 標籤。
  3. Microphone從功能清單中選取核取方塊。

建立 UI 按鈕來放置和停止呼叫

這個簡單的範例應用程式將包含兩個按鈕。 一個用於撥打電話,另一個用來掛接通話。 下列步驟示範如何將這些按鈕新增至應用程式。

  1. Solution Explorer在面板中,按兩下名為 MainPage.xaml UWP 的檔案,或 MainWindows.xaml 針對 WinUI 3。
  2. 在中央面板中,尋找 UI 預覽下的 XAML 程式碼。
  3. 依照下列摘錄修改 XAML 程式碼:
<TextBox x:Name="CalleeTextBox" Text="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Row="0" Height="40" Margin="10,10,10,10" />
<StackPanel Orientation="Horizontal">
    <Button x:Name="CallButton" Content="Start Call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="200"/>
    <Button x:Name="HangupButton" Content="Hang Up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="200"/>
</StackPanel>

使用呼叫 SDK API 設定應用程式

呼叫 SDK API 位於兩個不同的命名空間中。 下列步驟會通知 C# 編譯器有關這些命名空間,讓 Visual Studio 的 Intellisense 可協助程式碼開發。

  1. Solution Explorer在面板中,按一下名為 MainPage.xaml UWP MainWindows.xaml 或 WinUI 3 之檔案左側的箭號。
  2. 按兩下名為 或 的 MainPage.xaml.csMainWindows.xaml.cs 檔案。
  3. 在目前 using 語句底部新增下列命令。
using Azure.Communication;
using Azure.Communication.Calling;

請保留 MainPage.xaml.csMainWindows.xaml.cs 開啟。 後續步驟會將更多程式碼新增至其中。

允許應用程式互動

先前新增的 UI 按鈕需要在放置 Call 的 頂端操作。 這表示 Call 應該將資料成員新增至 MainPageMainWindow 類別。 此外,若要允許建立 CallAgent 非同步作業成功, CallAgent 資料成員也應該新增至相同的類別。

請將下列資料成員新增至 MainPage pr MainWindow 類別:

CallAgent callAgent;
Call call;

建立按鈕處理常式

先前已將兩個 UI 按鈕新增至 XAML 程式碼。 下列程式碼會在使用者選取按鈕時新增要執行的處理常式。 在上一節的資料成員之後,應該加入下列程式碼。

private async void CallButton_Click(object sender, RoutedEventArgs e)
{
    // Start call
}

private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
    // End the current call
}

物件模型

下列類別和介面會處理適用于 UWP 的Azure 通訊服務呼叫用戶端程式庫的一些主要功能。

名稱 描述
CallClient CallClient 是通話用戶端程式庫的主要進入點。
CallAgent CallAgent 可用來啟動和聯結通話。
呼叫 通話是用來管理已撥打或加入的通話。
CommunicationTokenCredential CommunicationTokenCredential 會作為權杖認證來具現化 CallAgent。
CallAgentOptions CallAgentOptions 包含識別呼叫端的資訊。
HangupOptions HangupOptions 會通知是否應該終止所有參與者的通話。

初始化 CallAgent

若要從 CallClient 建立 CallAgent 實例,您必須使用 CallClient.CreateCallAgent 方法,在物件初始化後以非同步方式傳回 CallAgent 物件。

若要建立 CallAgent ,您必須傳遞 CommunicationTokenCredential 物件和 CallAgentOptions 物件。 請記住, CommunicationTokenCredential 如果傳遞格式不正確的權杖,則會擲回 。

下列程式碼應該新增在 內部,並在應用程式初始化中呼叫協助程式函式。

var callClient = new CallClient();
this.deviceManager = await callClient.GetDeviceManager();

var tokenCredential = new CommunicationTokenCredential("<AUTHENTICATION_TOKEN>");
var callAgentOptions = new CallAgentOptions()
{
    DisplayName = "<DISPLAY_NAME>"
};

this.callAgent = await callClient.CreateCallAgent(tokenCredential, callAgentOptions);

<AUTHENTICATION_TOKEN> 必須以您資源的有效認證權杖取代。 如果認證權杖必須取得來源,請參閱 使用者存取權杖 檔。

建立 CallAgent 並撥打電話

建立 CallAgent 所需的物件現在已就緒。 是時候以非同步方式建立 CallAgent 和撥打呼叫。

處理上一個步驟中的例外狀況之後,應該加入下列程式碼。

var startCallOptions = new StartCallOptions();

var callees = new ICommunicationIdentifier[1] { new CommunicationUserIdentifier(CalleeTextBox.Text.Trim()) };

this.call = await this.callAgent.StartCallAsync(callees, startCallOptions);
this.call.OnStateChanged += Call_OnStateChangedAsync;

歡迎使用 8:echo123 來與Azure 通訊服務回應 Bot 交談。

結束通話

呼叫之後, HangupAsync 應該使用 物件的 方法 Call 來停止呼叫。

的實例 HangupOptions 也應該用來通知呼叫是否必須終止給其所有參與者。

下列程式碼應該在 內 HangupButton_Click 新增。

this.call.OnStateChanged -= Call_OnStateChangedAsync;
await this.call.HangUpAsync(new HangUpOptions());

執行程式碼

請確定 Visual Studio 會建置 、 x86ARM64 的應用程式 x64 ,然後按 F5 以開始執行應用程式。 之後,按一下 Call 按鈕以呼叫已定義的被呼叫者。

請記住,第一次執行應用程式時,系統會提示使用者授與麥克風的存取權。

下一步