共用方式為


訂閱 SDK 事件

建議您訂閱呼叫 SDK 事件。 Azure 通訊服務 SDK 是動態的,且包含可能會隨著時間變更的屬性。 您可以訂閱這些事件,以事先收到任何變更的通知。 請遵循本文中的指示來訂閱 Azure 通訊服務 SDK 事件。

Azure 通訊通話 SDK 上的事件

本節說明您的應用程式可以訂閱的事件和屬性變更。 訂閱這些事件可讓您的應用程式得知呼叫 SDK 中的狀態變更,並據此做出反應。

追蹤事件非常重要,因為它可讓應用程式的狀態與 Azure 通訊服務呼叫架構的狀態保持同步。 追蹤事件可協助您在不需要在 SDK 物件上實作提取機制的情況下,追蹤變更。

本節假設您已完成快速入門,或您已實作能夠撥打和接聽呼叫的應用程式。 如果您未完成入門指南,請參閱 將語音通話新增至您的應用程式

JavaScript 呼叫 SDK 中的每個物件都有 propertiescollections。 其值會在物件的存留期內變更。

使用on()方法來訂閱物件事件。 使用 off() 方法來取消訂閱物件事件。

屬性

您可以訂閱 '<property>Changed' 事件,以接聽 屬性上的值變更。

屬性上的訂用帳戶範例

在此範例中,我們會訂閱 屬性值的 isLocalVideoStarted 變更。

call.on('isLocalVideoStartedChanged', () => {
    // At that point the value call.isLocalVideoStarted is updated
    console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
});

集合

您可以訂閱 \<collection>Updated 事件,以接收物件集合中變更的相關通知。 每當您監視的集合中新增或移除元素時,就會觸發\<collection>Updated事件。

  • '<collection>Updated' 事件的裝載具有 added 陣列,其中包含已新增至集合的值。
  • '<collection>Updated' 事件的裝載也有 removed 陣列,其中包含從集合中移除的值。

集合上的範例訂用帳戶

在此範例中,我們會訂閱 Call 物件的 LocalVideoStream值變更。

call.on('localVideoStreamsUpdated', updateEvent => {
    updateEvent.added.forEach(async (localVideoStream) => {
        // Contains an array of LocalVideoStream that were added to the call
        // Add a preview and start any processing if needed
        handleAddedLocalVideoStream(localVideoStream )
    });
    updateEvent.removed.forEach(localVideoStream => {
        // Contains an array of LocalVideoStream that were removed from the call
        // Remove the preview and stop any processing if needed
        handleRemovedLocalVideoStream(localVideoStream ) 
    });
});

物件上的 CallAgent 事件

事件名稱: incomingCall

當用戶端收到來電時,就會引發 incomingCall 事件。

您的應用程式對事件有何反應?

您的應用程式必須通知收件者來電。 通知提示必須讓收件者接受或拒絕通話。

程式代碼範例:

callClient.on('incomingCall', (async (incomingCallEvent) => {
    try {
        // Store a reference to the call object
        incomingCall = incomingCallEvent.incomingCall; 
        // Update your UI to allow
        acceptCallButton.disabled = false; 
        callButton.disabled = true;
    } catch (error) {
        console.error(error);
    }
});

事件名稱: callsUpdated

當通話遭到移除或新增至通話代理程式時,就會引發 callsUpdated 更新的事件。 當用戶進行、接收或終止呼叫時,就會發生此事件。

您的應用程式對事件有何反應?

您的應用程式必須根據 CallAgent 實例的作用中呼叫數目來更新其 UI。

事件名稱: connectionStateChanged

更新 connectionStateChanged 的訊號狀態 CallAgent 時引發的事件。

您的應用程式對事件有何反應?

您的應用程式必須根據新狀態更新其UI。 可能的連線狀態值為 ConnectedDisconnected

程式代碼範例:

callClient.on('connectionStateChanged', (async (connectionStateChangedEvent) => {
    if (connectionStateChangedEvent.newState === "Connected") {
        enableCallControls() // Enable all UI element that allow user to make a call
    }

    if (connectionStateChangedEvent.newState === 'Disconnected') {
        if (typeof connectionStateChangedEvent.reason !== 'undefined') {
            alert(`Disconnected reason: ${connectionStateChangedEvent.reason}`)
        } 
        disableCallControls() // Disable all the UI element that allows the user to make a call
    }
});

物件上的 Call 事件

事件名稱: stateChanged

當呼叫狀態變更時,就會引發 stateChanged 事件。 例如,當呼叫從 connecteddisconnected時。

您的應用程式對事件有何反應?

您的應用程式必須據以更新其UI。 根據新的呼叫狀態停用或啟用適當的按鈕和其他UI元素。

程式代碼範例:

call.on('stateChanged', (async (connectionStateChangedEvent) => {
  if(call.state === 'Connected') {
      connectedLabel.hidden = false;
      acceptCallButton.disabled = true;
      startCallButton.disabled = true;
      startVideoButton.disabled = false;
      stopVideoButton.disabled = false
  } else if (call.state === 'Disconnected') {
      connectedLabel.hidden = true;
      startCallButton.disabled = false;
      console.log(`Call ended, call end reason={code=${call.callEndReason.code}, subCode=${call.callEndReason.subCode}}`);
  }
});

事件:idChanged

當呼叫的標識碼變更時,就會引發 idChanged 事件。 當呼叫從connecting狀態移至 時,呼叫的標識符會變更。connected 聯機呼叫之後,呼叫的標識符會維持不變。

您的應用程式對事件有何反應?

您的應用程式可以儲存新的呼叫標識碼,或在需要時從呼叫物件擷取它。

程式代碼範例:

let callId = "";
call.on('idChanged', (async (callIdChangedEvent) => {
  callId = call.id; // You can log it as the call ID is useful for debugging call issues
});

事件:isMutedChanged

當本機音訊被靜音或取消靜音時,就會觸發isMutedChanged事件。

您的應用程式對事件有何反應?

您的應用程式必須將靜音/取消靜音按鈕更新為適當的狀態。

程式代碼範例:

call.on('isMutedChanged', (async (isMutedChangedEvent) => {
    microphoneButton.disabled = call.isMuted;       
});

事件:isScreenSharingOnChanged

啟用或停用本機使用者的螢幕畫面分享時,就會引發 isScreenSharingOnChanged 事件。

您的應用程式對事件有何反應?

如果螢幕共享開啟,您的應用程式必須向用戶顯示預覽和/或警告。

如果螢幕共用關閉,應用程式必須移除預覽和警告。

程式代碼範例:

call.on('isScreenSharingOnChanged', () => {
  if (!this.call.isScreenSharing) {
      displayStartScreenSharingButton();
      hideScreenSharingWarning()
      removeScreenSharingPreview();    
  } else {
      displayScreenSharingWarning()
      displayStopScreenSharingButton();
      renderScreenSharingPreview(); 
  }
});

事件:isLocalVideoStartedChanged

當使用者啟用我們停用的其本機視訊時,就會引發 isLocalVideoStartedChanged 事件。

您的應用程式對事件有何反應?

您的應用程式必須顯示本機視訊的預覽,並啟用或停用相機啟用按鈕。

程式代碼範例:

call.on('isLocalVideoStartedChanged', () => {
    showDisableCameraButton(call.isLocalVideoStarted);
});

事件:remoteParticipantsUpdated

您的應用程式必須訂閱每個新增 RemoteParticipants 的事件,並取消訂閱離開通話的參與者的事件。

您的應用程式對事件有何反應?

您的應用程式必須顯示本機視訊的預覽,並啟用或停用相機啟用按鈕。

程式代碼範例:

call.on('remoteParticipantsUpdated', (remoteParticipantsUpdatedEvent) => {
    remoteParticipantsUpdatedEvent.added.forEach(participant => {
        // handleParticipant should
        //   - subscribe to the remote participants events 
        //   - update the UI 
        handleParticipant(participant);
    });
    
    remoteParticipantsUpdatedEvent.removed.forEach(participant => {
        // removeParticipant should
        //   - unsubscribe from the remote participants events 
        //   - update the UI  
        removeParticipant(participant);
    });
});

事件:localVideoStreamsUpdated

當本機視訊串流清單變更時,就會引發 localVideoStreamsUpdated 事件。 當用戶啟動或移除視訊串流時,就會發生這些變更。

您的應用程式對事件有何反應?

您的應用程式必須針對每個 LocalVideoStream 新增項目顯示預覽。 您的應用程式必須移除預覽,並在每個 LocalVideoStream 被移除時停止處理。

程式代碼範例:

call.on('localVideoStreamsUpdated', (localVideoStreamUpdatedEvent) => {
    localVideoStreamUpdatedEvent.added.forEach(addedLocalVideoStream => { 
        // Add a preview and start any processing if needed
        handleAddedLocalVideoStream(addedLocalVideoStream) 
    });

    localVideoStreamUpdatedEvent.removed.forEach(removedLocalVideoStream => {
         // Remove the preview and stop any processing if needed
        this.handleRemovedLocalVideoStream(removedLocalVideoStream) 
    });
});

事件:remoteAudioStreamsUpdated

當遠端音訊串流清單變更時,就會引發 remoteAudioStreamsUpdated 事件。 當遠端參與者將音訊串流新增或移除至通話時,就會發生這些變更。

您的應用程式對事件有何反應?

如果正在處理數據流且現在已移除,則必須停止處理。 另一方面,如果新增數據流,則事件接收是開始處理新音訊數據流的好位置。

事件:totalParticipantCountChanged

totalParticipantCountChanged 呼叫中變更 totalParticipant 數目時引發。

您的應用程式對事件有何反應?

如果您的應用程式顯示參與者計數器,您的應用程式可以在收到事件時更新其參與者計數器。

程式代碼範例:

call.on('totalParticipantCountChanged', () => {
    participantCounterElement.innerText = call.totalParticipantCount;
});

事件:roleChanged

參與者 roleChanged 會在呼叫中localParticipant角色變更時引發。 例如,當本機參與者在通話中成為演示者 ACSCallParticipantRolePresenter 時。

您的應用程式對事件有何反應?

您的應用程式必須根據使用者的新角色來啟用或停用按鈕。

程式代碼範例:

call.on('roleChanged', () => {
    this.roleElement = call.role;
});

事件:mutedByOthers

當本機參與者將通話中的其他參與者設為靜音時,就會發生 mutedByOthers 事件。

您的應用程式對事件有何反應?

您的應用程式必須向使用者顯示訊息,通知他們已靜音。

程式代碼範例:

call.on('mutedByOthers', () => {
    messageBanner.innerText = "You have been muted by other participant in this call";
});

事件:callerInfoChanged

當呼叫端資訊更新時,就會 callerInfoChanged 發生此事件。 當呼叫端變更其顯示名稱時,就會發生這種情況。

您的應用程式對事件有何反應? 應用程式可以更新呼叫端資訊。

程式代碼範例:

call.on('callerInfoChanged', () => {
    showCallerInfo(call.callerInfo)
});

事件:transferorInfoChanged

更新傳送者資訊時,就會 transferorInfoChanged 發生此事件。 當傳送器變更其顯示名稱時,就會發生這種情況。

您的應用程式對事件有何反應? 應用程式可以更新傳送者資訊。

程式代碼範例:

call.on('transferorInfoChanged', () => {
    showTransferorInfo(call.transferorInfo)
});

物件上的 RemoteParticipant 事件

事件:roleChanged

當角色在呼叫中變更時roleChanged,就會RemoteParticipant引發 事件。 例如,當 RemoteParticipant 在呼叫中成為演示者 ACSCallParticipantRolePresenter 時。

您的應用程式對事件有何反應?

您的應用程式必須根據 RemoteParticipant 新角色更新其UI。

程式代碼範例:

remoteParticipant.on('roleChanged', () => {
    updateRole(remoteParticipant);
});

事件:isMutedChanged

當其中一isMutedChanged個靜音或取消靜音其麥克風時,就會RemoteParticipant引發事件。

您的應用程式對事件有何反應?

您的應用程式可以在顯示參與者的檢視畫面旁邊顯示圖示。

程式代碼範例:

remoteParticipant.on('isMutedChanged', () => {
    updateMuteStatus(remoteParticipant); // Update the UI based on the mute state of the participant
});

事件:displayNameChanged

displayNameChanged更新的名稱RemoteParticipant時。

您的應用程式對事件有何反應?

如果參與者的姓名顯示在用戶界面中,您的應用程式必須進行更新。

程式代碼範例:

remoteParticipant.on('displayNameChanged', () => {
    remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
});
remoteParticipant.on('displayNameChanged', (args: {newValue?: string, oldValue?: string, reason?: DisplayNameChangedReason}) => {
    remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
    console.log(`Display name changed from ${oldValue} to ${newValue} due to ${reason}`);
});

事件:isSpeakingChanged

isSpeakingChanged 通話中佔主導地位的說話者變更時。

您的應用程式對事件有何反應?

您的應用程式 UI 必須優先顯示 RemoteParticipant 成為主要說話者的人員。

程式代碼範例:

remoteParticipant.on('isSpeakingChanged', () => {
    showAsRemoteSpeaker(remoteParticipant) // Display a speaking icon near the participant
});

事件:videoStreamsUpdated

videoStreamsUpdated 遠端參與者在通話中新增或移除 VideoStream 時。

您的應用程式對事件有何反應?

如果您的應用程式正在處理已移除的數據流,您的應用程式必須停止處理。 新增數據流時,我們建議您的應用程式開始轉譯或處理它。

程式代碼範例:

remoteParticipant.on('videoStreamsUpdated', (videoStreamsUpdatedEvent) => {

     videoStreamsUpdatedEvent.added.forEach(addedRemoteVideoStream => { 
       // Remove a renderer and start processing the stream if any processing is needed
        handleAddedRemoteVideoStream(addedRemoteVideoStream) 
    });

    videoStreamsUpdatedEvent.removed.forEach(removedRemoteVideoStream => {
        // Remove the renderer and stop processing the stream if any processing is ongoing
        this.handleRemovedRemoteVideoStream(removedRemoteVideoStream) 
    });
});

物件上的 AudioEffectsFeature 事件

事件:effectsStarted

當選取的音訊效果套用至音訊數據流時,就會發生這個事件。 例如,當某人開啟噪音抑制時,就會引發 effectsStarted

您的應用程式對事件有何反應?

您的應用程式可以顯示或啟用按鈕,讓使用者停用音訊效果。

程式代碼範例:

audioEffectsFeature.on('effectsStarted', (effects) => {
    stopEffectButton.style.visibility = "visible"; 
});

事件:effectsStopped

當選取的音訊效果套用至音訊數據流時,就會發生這個事件。 例如,當某人關閉噪音抑制時,就會引發 effectsStopped

您的應用程式對事件有何反應?

您的應用程式可以顯示或啟用按鈕,讓使用者啟用音訊效果。

程式代碼範例:

audioEffectsFeature.on('effectsStopped', (effects) => {
    startEffectButton.style.visibility = "visible"; 
});

事件:effectsError

當音訊效果啟動或套用時發生錯誤時,就會發生這個事件。

您的應用程式對事件有何反應?

您的應用程式必須顯示警示或錯誤訊息,指出音訊效果未如預期般運作。

程式代碼範例:

audioEffectsFeature.on('effectsError', (error) => {
    console.log(`Error with the audio effect ${error}`);
    alert(`Error with the audio effect`);
});

安裝 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 執行個體,您必須在 createCallAgent 執行個體上呼叫 CallClient 方法。 此呼叫會以非同步方式傳回 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();

現在您已安裝 Android SDK,您可以訂閱大部分的屬性和集合,以在值變更時收到通知。

屬性

若要訂閱 property changed 事件:

// subscribe
PropertyChangedListener callStateChangeListener = new PropertyChangedListener()
{
    @Override
    public void onPropertyChanged(PropertyChangedEvent args)
    {
        Log.d("The call state has changed.");
    }
}
call.addOnStateChangedListener(callStateChangeListener);

//unsubscribe
call.removeOnStateChangedListener(callStateChangeListener);

使用在相同類別內定義的事件接聽程式時,請將接聽程式繫結至變數。 若要新增和移除接聽程式方法,請將變數當做自變數傳入。

如果您嘗試以引數形式直接傳入接聽程式,則您會失去對該接聽程式的參考。 Java 正在建立這些接聽程式的新執行個體,而不是參考先前建立的接聽程式。 其仍會正常觸引,但無法移除,因為您不再有其參考。

集合

若要訂閱 collection updated 事件:

LocalVideoStreamsChangedListener localVideoStreamsChangedListener = new LocalVideoStreamsChangedListener()
{
    @Override
    public void onLocalVideoStreamsUpdated(LocalVideoStreamsEvent localVideoStreamsEventArgs) {
        Log.d(localVideoStreamsEventArgs.getAddedStreams().size());
        Log.d(localVideoStreamsEventArgs.getRemovedStreams().size());
    }
}
call.addOnLocalVideoStreamsChangedListener(localVideoStreamsChangedListener);
// To unsubscribe
call.removeOnLocalVideoStreamsChangedListener(localVideoStreamsChangedListener);

設定系統

請遵循下列步驟來設定系統。

建立 Xcode 專案

在 Xcode 中建立新的 iOS 專案,並選取 [單一檢視應用程式] 範本。 本文使用 SwiftUI 架構,因此您應該將 Language 設定Swift,並將 Interface 設定SwiftUI

您不會在本文中建立測試。 您可以隨意清除 [包含測試] 核取方塊。

螢幕擷取畫面:顯示用於在 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 更新應用程式的資訊屬性清單。 將相關聯的值設定為對話框中所包含的字串,系統用來要求使用者存取權。

以滑鼠右鍵按一下專案樹狀結構的 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 執行個體,您必須使用 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")
        }
})

現在您已安裝 iOS SDK,您可以訂閱大部分的屬性和集合,以在值變更時收到通知。

屬性

若要訂閱 property changed 事件,請使用下列程式碼。

call.delegate = self
// Get the property of the call state by getting on the call's state member
public func call(_ call: Call, didChangeState args: PropertyChangedEventArgs) {
{
    print("Callback from SDK when the call state changes, current state: " + call.state.rawValue)
}

// to unsubscribe
self.call.delegate = nil

集合

若要訂閱 collection updated 事件,請使用下列程式碼。

call.delegate = self
// Collection contains the streams that were added or removed only
public func call(_ call: Call, didUpdateLocalVideoStreams args: LocalVideoStreamsUpdatedEventArgs) {
{
    print(args.addedStreams.count)
    print(args.removedStreams.count)
}
// to unsubscribe
self.call.delegate = nil

下一步