Поделиться через


Подписка на события SDK

Мы рекомендуем подписываться на события звонков SDK. Пакеты SDK служб коммуникации Azure являются динамическими и содержат свойства, которые могут меняться со временем. Вы можете подписаться на эти события, чтобы получать уведомления заранее о любых изменениях. Следуйте инструкциям из этой статьи, чтобы подписаться на события пакета SDK служб коммуникации Azure.

События в пакете SDK для вызовов связи Azure

В этом разделе описаны события и изменения свойств приложения, на которые можно подписаться. Подписка на эти события позволяет приложению получать сведения об изменении состояния в вызывающем пакете SDK и реагировать соответствующим образом.

Отслеживание событий имеет решающее значение, так как это позволяет приложению оставаться синхронизированным с состоянием платформы вызовов Служб коммуникации Azure. Отслеживание событий помогает следить за изменениями без реализации механизма опроса для объектов SDK.

В этом разделе предполагается, что вы прошли краткое руководство QuickStart или реализовали приложение, которое может совершать и принимать звонки. Если вы не завершили руководство по началу работы с платформой, см. статью Добавить голосовой вызов в ваше приложение.

Каждый объект в пакете SDK для вызовов JavaScript имеет 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, содержащий значения, которые были удалены из коллекции.

Пример подписки в коллекции

В этом примере мы подписываемся на изменения значений объекта LocalVideoStreamCall.

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.

Имя события: connectionStateChanged

Событие connectionStateChanged срабатывает, когда обновляется сигнальное состояние CallAgent.

Как приложение реагирует на событие?

Приложение должно обновить пользовательский интерфейс на основе нового состояния приложения. Возможные значения состояния подключения: 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.

Как приложение реагирует на событие?

Приложение должно соответствующим образом обновить пользовательский интерфейс. Отключение или включение соответствующих кнопок и других элементов пользовательского интерфейса на основе нового состояния вызова.

Пример кода:

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 срабатывает при изменении количества участников в вызове.

Как приложение реагирует на событие?

Если ваше приложение отображает счетчик участников, оно может обновить его при получении события.

Пример кода:

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.

Пример кода:

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

Событие: isSpeakingChanged

Когда происходит изменение доминирующего динамика в вызове.

Как приложение реагирует на событие?

Пользовательский интерфейс вашего приложения должен иметь приоритет в отображении того, кто стал доминирующим оратором.

Пример кода:

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

Событие: videoStreamsUpdated

Когда 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();

Теперь, когда вы установили пакет SDK для Android, вы можете подписаться на большинство свойств и коллекций, которые будут получать уведомления при изменении значений.

Свойства

Для того чтобы подписаться на 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 и выберите шаблон Single View App. В этой статье используется платформа SwiftUI, поэтому необходимо задать для языка значение Swift и задать для интерфейсазначение 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. Откройте .xcworkspace с помощью Xcode.

Запросить доступ к микрофону

Чтобы получить доступ к микрофону устройства, необходимо обновить список свойств приложения с помощью 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")
        }
})

Теперь, когда вы установили пакет SDK для iOS, вы можете подписаться на большинство свойств и коллекций, которые будут получать уведомления при изменении значений.

Свойства

Чтобы подписаться на 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

Дальнейшие шаги