Calling SDK イベントをサブスクライブすることをお勧めします。 Azure Communication Services SDK は動的であり、時間の経過と伴って変化する可能性のあるプロパティが含まれています。 これらのイベントをサブスクライブして、変更の前に通知を受け取ることができます。 この記事の手順に従って、Azure Communication Services SDK イベントをサブスクライブします。
Azure Communication Calling SDK でのイベント
このセクションでは、アプリがサブスクライブできるイベントとプロパティの変更について説明します。 これらのイベントをサブスクライブすると、呼び出し元 SDK の状態変化についてアプリに通知され、それに応じて対応できるようになります。
イベントの追跡は、アプリケーションの状態を Azure Communication Services Calling フレームワークの状態と同期し続けるので非常に重要です。 イベントの追跡は、SDK オブジェクトにプル メカニズムを実装せずに変更を取り込むのに役立ちます。
このセクションでは、クイック スタートを実行した場合、または呼び出しを行って受信できるアプリケーションを実装していることを前提としています。 ファースト ステップ ガイドを完了していない場合は、「 音声通話をアプリに追加する」を参照してください。
JavaScript Calling SDK の各オブジェクトには、 properties
と collections
があります。 これらの値は、オブジェクトの有効期間を通じて変化します。
オブジェクト イベントをサブスクライブするには、 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 を更新する必要があります。 使用可能な接続状態の値は、 Connected
と Disconnected
です。
コード サンプル:
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
イベントは、呼び出し状態が変化したときに発生します。 たとえば、呼び出しが connected
から disconnected
になるときです。
アプリケーションはイベントにどのように反応しますか?
アプリケーションでは、それに応じて 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
イベントは、呼び出しの ID が変更されたときに発生します。 呼び出しの ID は、呼び出しが connecting
状態から connected
に移行すると変更されます。 呼び出しが接続されると、呼び出しの ID は同じままになります。
アプリケーションはイベントにどのように反応しますか?
アプリケーションは、新しい呼び出し ID を保存することも、必要に応じて後で呼び出しオブジェクトから取得することもできます。
コード サンプル:
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
ロールが変更されたときに発生します。 たとえば、リモート参加者が通話の発表者 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
。
アプリケーションはイベントにどのように反応しますか?
アプリケーションが UI に表示されている場合は、参加者の名前を更新する必要があります。
コード サンプル:
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
。
アプリケーションはイベントにどのように反応しますか?
主要な話者になった RemoteParticipant
を表示するには、アプリケーション UI が優先される必要があります。
コード サンプル:
remoteParticipant.on('isSpeakingChanged', () => {
showAsRemoteSpeaker(remoteParticipant) // Display a speaking icon near the participant
});
イベント: videoStreamsUpdated
リモート参加者が呼び出しに対して VideoStream を追加または削除したときの videoStreamsUpdated
。
アプリケーションはイベントにどのように反応しますか?
アプリケーションが削除されたストリームを処理していた場合、アプリケーションは処理を停止する必要があります。 新しいストリームが追加されたら、アプリケーションでストリームのレンダリングまたは処理を開始することをお勧めします。
コード サンプル:
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 フレームワークを使うので、[言語] を [Swift] に、[インターフェイス] を [SwiftUI] に設定する必要があります。
この記事では、テストは作成しません。 [Include Tests] チェック ボックスはオフにしてもかまいません。
CocoaPods を使用してパッケージと依存関係をインストールする
この例のように、アプリケーション用の Podfile を作成します。
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
pod install
を実行します。Xcode を使用して
.xcworkspace
を開きます。
マイクへのアクセスを要求する
デバイスのマイクにアクセスするには、NSMicrophoneUsageDescription
を使用してアプリの情報プロパティ一覧を更新する必要があります。 関連付けられる値には、システムがユーザーにアクセスを要求するために使うダイアログに含まれる文字列を設定します。
プロジェクト ツリーの [Info.plist] エントリを右クリックし、[Open As]> を選択します。 最上位の <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