訂閱 SDK 事件

Azure 通訊服務 SDK 是動態的,而且包含許多屬性。 當這些變更時,身為開發人員,您可能會想要知道何時和更重要的是有哪些變更。 方法如下!

Azure 通訊通話 SDK 上的事件

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

追蹤事件很重要,因為它可讓應用程式的狀態與 ACSCalling 架構的狀態保持同步,而不需要您在 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' 事件的裝載具有 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 (incomimgCallEvent) => {
    try {
        // Store a reference to the call object
        incomingCall = incomimgCallEvent.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', () => {
    showdDisableCameraButton(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
        //   - unsubcribe 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";
});

物件上的 RemoteParticipant 事件

事件:roleChanged

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

您的應用程式對事件的反應如何? 您的應用程式應該根據 RemoteParticipant 新角色來更新其UI。

程式代碼範例:

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

事件:isMutedChanged

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

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

您的應用程式可能會在顯示參與者的檢視附近顯示圖示。

程式代碼範例:

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

事件:displayNameChanged

displayNameChanged更新的名稱RemoteParticipant時。

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

如果您的應用程式顯示在UI中,則應用程式應該更新參與者名稱。

程式代碼範例:

remoteParticipant.on('displayNameChanged', () => {
    remoteParticipant.nameLabel.innerText = remoteParticipant.displayName;
});

事件:isSpeakingChanged

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

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

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

程式代碼範例:

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() 新增至 buildscriptallprojects 下的存放庫清單:

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

透過我們的 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 架構,因此您應將 [語言] 設定為 [Swift],並將 [使用者介面] 設定為 [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

若要從 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")
        }
})

透過我們的 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

下一步