次の方法で共有


SDK イベントをサブスクライブする

Azure Communication Services SDK は動的であり、多数のプロパティが含まれています。 これらの変更が発生した場合、開発者は、変更が発生した時点と、変更内容が何であるかを知る必要があります。 ご覧ください。

Azure Communication Calling 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' イベントは、監視対象のコレクションに要素が追加または削除されるたびにトリガーされます。

  • '<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 イベントは、呼び出しの状態が変化したときに発生します。 たとえば、呼び出しが 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', () => {
    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

roleChanged イベントは、呼び出しの中で RemotePartipant ロールが変更されたときに発生します。 たとえば、リモート参加者が通話の発表者 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

RemoteParticipant の名前が更新されたときの displayNameChanged

このイベントのアプリケーションでの対処方法

アプリケーションの 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

リモート参加者が呼び出しに対して 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 ファイルを見つけて、buildscriptallprojects の下のリポジトリの一覧に mavenCentral() を追加します。

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 フレームワークを使用するので、[Language][Swift] に、[Interface][SwiftUI] に設定する必要があります。

この記事では、テストは作成しません。 [Include Tests] チェック ボックスはオフにしてもかまいません。

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] エントリを右クリックし、[Open As]>[Source Code] を選択します。 最上位の <dict> セクションに以下の行を追加してから、ファイルを保存します。

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

アプリのフレームワークを設定する

プロジェクトの ContentView.swift ファイルを開きます。 ファイルの先頭に import 宣言を追加して、AzureCommunicationCalling ライブラリをインポートします。 さらに、AVFoundation をインポートします。 これは、コードでのオーディオ アクセス許可の要求に必要です。

import AzureCommunicationCalling
import AVFoundation

CallAgent を初期化する

CallClient から CallAgent インスタンスを作成するには、初期化された後に CallAgent オブジェクトを非同期に返す callClient.createCallAgent メソッドを使用する必要があります。

通話クライアントを作成するには、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

次のステップ