Управление вызовами

Узнайте, как управлять вызовами с помощью пакетов SDK Службы коммуникации Azure. Мы научимся размещать вызовы, управлять своими участниками и свойствами.

Необходимые компоненты

Установка пакета SDK

npm install Используйте команду для установки Службы коммуникации Azure общих и вызывающих пакетов SDK для JavaScript:

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

Инициализация обязательных объектов

Экземпляр CallClient требуется для большинства операций вызова. При создании нового CallClient экземпляра его можно настроить с помощью пользовательских параметров, таких как Logger экземпляр.

С помощью экземпляра CallClient можно создать CallAgent экземпляр, вызвав его createCallAgent. Этот метод асинхронно возвращает объект экземпляра CallAgent.

Метод createCallAgent использует CommunicationTokenCredential в качестве аргумента. Он принимает маркер доступа пользователя.

Можно применить метод getDeviceManager для экземпляра CallClient, чтобы получить доступ к deviceManager.

const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");

// Set the logger's log level
setLogLevel('verbose');

// Redirect log output to console, file, buffer, REST API, or whatever location you want
AzureLogger.log = (...args) => {
    console.log(...args); // Redirect log output to console
};

const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()

Осуществление вызовов

Чтобы создать и запустить вызов, используйте один из API callAgent и укажите пользователя, созданного с помощью пакета SDK удостоверений служб коммуникации.

Операции создания и начала вызовов выполняются синхронно. Экземпляр call позволяет подписываться на события вызова.

Осуществление вызова 1:n к пользователю или ТСОП

Чтобы осуществить вызов к другому пользователю Служб коммуникации, вызовите метод startCall для callAgent и передайте CommunicationUserIdentifier получателя, который вы создали с помощью библиотеки администрирования Служб коммуникации.

Для вызова пользователя "1:1" используйте следующий код:

const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const oneToOneCall = callAgent.startCall([userCallee]);

Чтобы осуществить вызов к телефонной сети общего пользования (ТСОП), вызовите метод startCall для callAgent и передайте PhoneNumberIdentifier получателя. Для осуществления вызовов к ТСОП необходимо настроить ресурс Служб коммуникации.

При вызове номера ТСОП необходимо указать альтернативный идентификатор вызывающего. Альтернативный идентификатор вызывающего обозначает номер телефона (по стандарту E.164), который определяет вызывающую сторону в вызове ТСОП. Это номер телефона, который получатель вызова видит при входящем вызове.

Примечание.

Проверка подробные сведения о предложении звонков по ТСОП. Для доступа к программе предварительной версии применяется к программе раннего внедрения.

Для осуществления персонального вызова по номеру PSTN используйте следующий код:

const pstnCallee = { phoneNumber: '<ACS_USER_ID>' }
const alternateCallerId = {phoneNumber: '<ALTERNATE_CALLER_ID>'};
const oneToOneCall = callAgent.startCall([pstnCallee], {alternateCallerId});

Для осуществления вызова пользователю с несколькими участниками по номеру PSTN используйте следующий код:

const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const pstnCallee = { phoneNumber: '<PHONE_NUMBER>'};
const alternateCallerId = {phoneNumber: '<ALTERNATE_CALLER_ID>'};
const groupCall = callAgent.startCall([userCallee, pstnCallee], {alternateCallerId});

Присоединение к вызову комнаты

Чтобы присоединиться к вызову room , можно создать экземпляр объекта контекста с roomId свойством в качестве идентификатора room . Чтобы присоединиться к вызову join , используйте метод и передайте экземпляр контекста.

const context = { roomId: '<RoomId>' }
const call = callAgent.join(context);

Разработчики room приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Дополнительные сведения см rooms. в концептуальной документации или кратком руководстве по началу работы.

Присоединение к групповому вызову

Примечание.

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

Параметр groupId требует, чтобы данные имели формат GUID. Рекомендуется использовать созданные случайным образом GUID, которые в ваших системах не считаются личными данными.

Чтобы начать новый групповой вызов или присоединиться к текущему групповому вызову, примените метод join и передайте ему объект со свойством groupId. В качестве значения groupId должен быть указан идентификатор GUID.

const context = { groupId: '<GUID>'};
const call = callAgent.join(context);

Прием входящего вызова

Экземпляр callAgent создает событие incomingCall, когда зарегистрированный в системе идентификатор принимает входящий вызов. Чтобы прослушать это событие, подпишитесь с помощью одного из следующих вариантов.

const incomingCallHandler = async (args: { incomingCall: IncomingCall }) => {
    const incomingCall = args.incomingCall;

    // Get incoming call ID
    var incomingCallId = incomingCall.id

    // Get information about this Call. This API is provided as a preview for developers
    // and may change based on feedback that we receive. Do not use this API in a production environment.
    // To use this api please use 'beta' release of Azure Communication Services Calling Web SDK
    var callInfo = incomingCall.info;

    // Get information about caller
    var callerInfo = incomingCall.callerInfo

    // Accept the call
    var call = await incomingCall.accept();

    // Reject the call
    incomingCall.reject();

    // Subscribe to callEnded event and get the call end reason
     incomingCall.on('callEnded', args => {
        console.log(args.callEndReason);
    });

    // callEndReason is also a property of IncomingCall
    var callEndReason = incomingCall.callEndReason;
};
callAgentInstance.on('incomingCall', incomingCallHandler);

Событие incomingCall включает экземпляр incomingCall, который можно принять или отклонить.

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

Удержание и возобновление вызова

Примечание.

В любой момент времени должно быть только 1 активный вызов (в Connected состоянии с активным носителем). Все остальные вызовы должны храниться пользователем или программно по приложению. Это обычно в таких сценариях, как центры контактов, где пользователю может потребоваться обрабатывать несколько исходящих и входящих вызовов, все неактивные вызовы должны быть помещены в удержание, и пользователь должен взаимодействовать с другими пользователями только в активном вызове.

Для удержания или возобновления вызова можно использовать hold асинхронные resume API:

Удержание вызова

await call.hold();

При hold разрешении API для состояния вызова задано значение LocalHold. В вызове 1:1 другой участник также помещается на удержание, а состояние вызова с точки зрения этого участника имеет значение RemoteHold. Позже другой участник может поместить свой вызов на удержание, что приведет к изменению LocalHoldсостояния. В групповом вызове или собрании — hold это локальная операция, она не проводит звонок для других участников звонка. Чтобы возобновить вызов всех пользователей, инициирувших удержание, необходимо возобновить его.

Чтобы возобновить вызов из удержания:

await call.resume();

resume При разрешении API состояние вызова снова задаетсяConnected.

Отключение и отмена вызова

Чтобы отключить или включить звук для локальной конечной точки, можно использовать асинхронные вызовы API mute и unmute:

//mute local device (microphone / sent audio)
await call.mute();

//unmute local device (microphone / sent audio)
await call.unmute();

Отключение и отключение входящего звука

Отключение входящего звука задает для тома вызова значение 0. Чтобы отключить или отменить входящий звук, можно использовать muteIncomingAudio асинхронные unmuteIncomingAudio API:

//mute local device (speaker)
await call.muteIncomingAudio();

//unmute local device (speaker)
await call.unmuteIncomingAudio();

При отключении входящего звука пакет SDK клиента участника по-прежнему получает звук вызова (звук удаленного участника). Звук вызова не услышится в динамике, и участник не сможет прослушивать до вызова call.unmuteIncomingAudio(). Однако мы можем применить фильтр к звуку вызова и воспроизвести отфильтрованный звук.

Отключение звука других участников

Примечание.

Этот API предоставляется в качестве предварительной версии для разработчиков и может быть изменен на основе полученных нами отзывов. Чтобы использовать этот API, используйте бета-версию Службы коммуникации Azure вызова веб-пакета SDK версии 1.18.1 или более поздней.

Чтобы отключить звук всех остальных участников или отключить определенный участник, можно использовать асинхронные API muteAllRemoteParticipants для вызова и mute удаленного участника:

//mute all participants except yourself
await call.muteAllRemoteParticipants();

//mute a specific participant
await call.remoteParticipants[0].mute();

Управление удаленными участниками

Все удаленные участники подробно описаны в RemoteParticipant объекте и доступны через remoteParticipants коллекцию в экземпляре вызова. Он remoteParticipants доступен из экземпляра Call .

Вывод списка участников в вызове

Коллекция remoteParticipants возвращает список удаленных участников в вызове:

call.remoteParticipants; // [remoteParticipant, remoteParticipant....]

Добавление участника в вызов

Чтобы добавить участника (пользователя или номер телефона) в звонок, можно использовать addParticipant API. Предоставьте один из типов Identifier. Он синхронно возвращает экземпляр remoteParticipant. Событие remoteParticipantsUpdated из вызова вызывается при успешном добавлении участника к вызову.

const userIdentifier = { communicationUserId: '<ACS_USER_ID>' };
const pstnIdentifier = { phoneNumber: '<PHONE_NUMBER>' }
const remoteParticipant = call.addParticipant(userIdentifier);
const remoteParticipant = call.addParticipant(pstnIdentifier, {alternateCallerId: '<ALTERNATE_CALLER_ID>'});

Удаление участника из вызова

Чтобы удалить участника (пользователя или номер телефона) из вызова, можно вызвать removeParticipant. Необходимо передать один из типов Identifier. Этот метод разрешается асинхронно после удаления участника из вызова. Этот же участник удаляется из коллекции remoteParticipants.

const userIdentifier = { communicationUserId: '<ACS_USER_ID>' };
const pstnIdentifier = { phoneNumber: '<PHONE_NUMBER>' }
await call.removeParticipant(userIdentifier);
await call.removeParticipant(pstnIdentifier);

Получение доступа к свойствам удаленного участника

С удаленными участниками связаны наборы свойств и коллекций:

  • CommunicationIdentifier: получение идентификатора для удаленного участника. Идентификатор имеет один из типов CommunicationIdentifier:
const identifier = remoteParticipant.identifier;
  • Может иметь один из следующих типов CommunicationIdentifier.

    • { communicationUserId: '<ACS_USER_ID'> }: объект, представляющий пользователя Службы коммуникации Azure.
    • { phoneNumber: '<E.164>' }: объект, представляющий номер телефона в формате E.164.
    • { microsoftTeamsUserId: '<TEAMS_USER_ID>', isAnonymous?: boolean; cloud?: "public" | "dod" | "gcch" }: объект, представляющий пользователя Teams.
    • { id: string }: объект, представляющий идентификатор, который не соответствует ни одному из других типов идентификаторов.
  • state: получение состояния удаленного участника.

const state = remoteParticipant.state;
  • Состояние может иметь одно из следующих значений.

    • Idle: начальное состояние.
    • Connecting: переходное состояние во время подключения участника к вызову.
    • Ringing: для участника звучит сигнал вызова.
    • Connected: участник подключен к вызову.
    • Hold: участник находится в режиме ожидания.
    • EarlyMedia: объявление, которое воспроизводится перед подключением участника к вызову.
    • InLobby: указывает, что удаленный участник находится в зале ожидания.
    • Disconnected: конечное состояние. Обозначает завершение вызова для участника. Если у удаленного участника пропадает подключение к сети, через две минуты его состояние меняется на Disconnected.
  • callEndReason: чтобы узнать, почему участник покинул вызов, проверьте свойство callEndReason.

    const callEndReason = remoteParticipant.callEndReason;
    const callEndReasonCode = callEndReason.code // (number) code associated with the reason
    const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason
    

    Примечание.

    • Это свойство задается только при добавлении удаленного участника через API Call.addParticipant(), а удаленный участник отклоняется, например.
    • В сценарии, когда UserB запускает UserC, с точки зрения UserA, UserA не видит этот флаг, установленный для UserC. Другими словами, UserA не отображает свойство UserC callEndReason вообще.
  • Состояние isMuted: чтобы узнать, отключен ли звук у удаленного участника, проверьте свойство isMuted. Он возвращает Boolean.

    const isMuted = remoteParticipant.isMuted;
    
  • Состояние isSpeaking: чтобы узнать, говорит ли удаленный участник, проверьте свойство isSpeaking. Он возвращает Boolean.

    const isSpeaking = remoteParticipant.isSpeaking;
    
  • videoStreams: чтобы проверить все видеопотоки, отправляемые определенным участником в вызове, проверьте коллекцию videoStreams. Она содержит объекты RemoteVideoStream.

    const videoStreams = remoteParticipant.videoStreams; // [RemoteVideoStream, ...]
    
  • displayName: чтобы получить отображаемое имя для этого удаленного участника, проверьте свойство displayName в возвращенной строке.

    const displayName = remoteParticipant.displayName;
    
  • endpointDetails: получение сведений обо всех конечных точках для этого удаленного участника

        const endpointDetails: EndpointDetails[] = remoteParticipant.endpointDetails;
    

    Примечание. Удаленный участник может находиться в вызове из многих конечных точек, и каждая конечная точка имеет свой собственный уникальный participantId. participantId отличается от необработанного идентификатора RemoteParticipant.identifier.

Проверка свойств вызова

Получите уникальный идентификатор (в строковом формате) вызова:

const callId: string = call.id;

Получите идентификатор локального участника:

const participantId: string = call.info.participantId;

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

Получите идентификатор потока при присоединении к собранию Teams:

const threadId: string | undefined = call.info.threadId;

Получение сведений о вызове:

const callInfo = call.info;

Чтобы получить данные о других участниках вызова, просмотрите коллекцию remoteParticipants в экземпляре Call:

const remoteParticipants = call.remoteParticipants;

Идентифицируйте вызывающего для входящего вызова:

const callerIdentity = call.callerInfo.identifier;

identifier имеет один из типов CommunicationIdentifier.

Получите состояние вызова:

const callState = call.state;

Возвращает строку, которая представляет текущее состояние вызова:

  • None: исходное состояние любого вызова;
  • Connecting: исходное переходное состояние после осуществления или приема вызова;
  • Ringing: для исходящего вызова означает, что на стороне удаленных участников звучит сигнал вызова. На их стороне это Incoming;
  • EarlyMedia: обозначает состояние, при котором перед вызовом воспроизводится объявление;
  • Connected: указывает, что вызов осуществлен;
  • LocalHold: указывает, что локальный участник вызова помещает вызов на удержание. Передача мультимедиа между локальной конечной точкой и удаленными участниками не выполняется;
  • RemoteHold: указывает, что удаленный участник вызова помещает вызов в удержание. Передача мультимедиа между локальной конечной точкой и удаленными участниками не выполняется;
  • InLobby: указывает, что пользователь находится в зале ожидания.
  • Disconnecting: переходное состояние перед переходом вызова в состояние Disconnected;
  • Disconnected: конечное состояние вызова. При потере сетевого подключения состояние меняется на Disconnected через две минуты.

Выясните причину завершения вызова путем изучения свойства callEndReason:

const callEndReason = call.callEndReason;
const callEndReasonCode = callEndReason.code // (number) code associated with the reason
const callEndReasonSubCode = callEndReason.subCode // (number) subCode associated with the reason

Чтобы выяснить, является ли текущий вызов входящим или исходящим, проверьте свойство direction. Он возвращает CallDirection.

const isIncoming = call.direction == 'Incoming';
const isOutgoing = call.direction == 'Outgoing';

Проверьте активные видеопотоки и активные потоки общего доступа к экранам, проверка коллекцииlocalVideoStreams. localVideoStreams API возвращает LocalVideoStream объекты типа Video, ScreenSharingили RawMedia.

const localVideoStreams = call.localVideoStreams;

Проверьте, отключен ли текущий микрофон. Он возвращает Boolean.

const muted = call.isMuted;

Проверьте, отключен ли текущий входящий звук (динамик). Он возвращает Boolean.

const incomingAudioMuted = call.isIncomingAudioMuted;

Проверьте, включен ли видео. Он возвращает Boolean.

const isLocalVideoStarted = call.isLocalVideoStarted;

Проверьте, включен общий доступ к экрану. Он возвращает Boolean.

const isScreenSharingOn = call.isScreenSharingOn;

Установка пакета 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();

Осуществление вызовов

Чтобы создать и начать вызов, необходимо вызвать метод CallAgent.startCall() и предоставить Identifier вызываемой стороны. Чтобы присоединиться к групповому вызову, нужно вызвать метод CallAgent.join() и предоставить значение groupId. Идентификаторы групп должны иметь формат GUID или UUID.

Операции создания и начала вызовов выполняются синхронно. Экземпляр вызова позволяет подписываться на все события в вызове.

Осуществление персонального вызова к пользователю

Чтобы осуществить вызов к другому пользователю Служб коммуникации, вызовите метод call для callAgent и передайте в нем объект с ключом communicationUserId.

StartCallOptions startCallOptions = new StartCallOptions();
Context appContext = this.getApplicationContext();
CommunicationUserIdentifier acsUserId = new CommunicationUserIdentifier(<USER_ID>);
CommunicationUserIdentifier participants[] = new CommunicationUserIdentifier[]{ acsUserId };
call oneToOneCall = callAgent.startCall(appContext, participants, startCallOptions);

Осуществление группового вызова к пользователям и ТСОП

Примечание.

Проверка подробные сведения о предложении звонков по ТСОП. Для доступа к программе предварительной версии применяется к программе раннего внедрения.

Чтобы осуществить групповой вызов к пользователю и номеру ТСОП, необходимо указать номер телефона вызываемой стороны. Для осуществления вызовов к ТСОП необходимо настроить ресурс Служб коммуникации.

CommunicationUserIdentifier acsUser1 = new CommunicationUserIdentifier(<USER_ID>);
PhoneNumberIdentifier acsUser2 = new PhoneNumberIdentifier("<PHONE_NUMBER>");
CommunicationIdentifier participants[] = new CommunicationIdentifier[]{ acsUser1, acsUser2 };
StartCallOptions startCallOptions = new StartCallOptions();
Context appContext = this.getApplicationContext();
Call groupCall = callAgent.startCall(participants, startCallOptions);

Прием вызова

Чтобы принять вызов, вызовите метод accept для объекта вызова.

Context appContext = this.getApplicationContext();
IncomingCall incomingCall = retrieveIncomingCall();
Call call = incomingCall.accept(context).get();

Чтобы принять вызов с включенной видеокамерой, сделайте следующее:

Context appContext = this.getApplicationContext();
IncomingCall incomingCall = retrieveIncomingCall();
AcceptCallOptions acceptCallOptions = new AcceptCallOptions();
VideoDeviceInfo desiredCamera = callClient.getDeviceManager().get().getCameraList().get(0);
acceptCallOptions.setVideoOptions(new VideoOptions(new LocalVideoStream(desiredCamera, appContext)));
Call call = incomingCall.accept(context, acceptCallOptions).get();

Чтобы получить входящий вызов, следует подписаться на событие onIncomingCall в объекте callAgent:

// Assuming "callAgent" is an instance property obtained by calling the 'createCallAgent' method on CallClient instance 
public Call retrieveIncomingCall() {
    IncomingCall incomingCall;
    callAgent.addOnIncomingCallListener(new IncomingCallListener() {
        void onIncomingCall(IncomingCall inboundCall) {
            // Look for incoming call
            incomingCall = inboundCall;
        }
    });
    return incomingCall;
}

Присоединение к вызову комнаты

CallAgent Используйте и RoomCallLocator присоединитесь к вызову комнаты, указав номерroomId. Метод CallAgent.join вернет Call объект:

val roomCallLocator = RoomCallLocator(roomId)
call = callAgent.join(applicationContext, roomCallLocator, joinCallOptions)

Разработчики room приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Дополнительные сведения см rooms. в концептуальной документации или кратком руководстве по началу работы.

Присоединение к групповому вызову

Чтобы начать новый групповой вызов или присоединиться к текущему групповому вызову, необходимо вызвать метод "join" и передать ему объект со свойством groupId. В качестве значения должен быть указан идентификатор GUID.

Context appContext = this.getApplicationContext();
GroupCallLocator groupCallLocator = new GroupCallLocator("<GUID>");
JoinCallOptions joinCallOptions = new JoinCallOptions();

call = callAgent.join(context, groupCallLocator, joinCallOptions);

Свойства вызова

Получите уникальный идентификатор для вызова:

String callId = call.getId();

Чтобы получить данные о других участниках вызова, просмотрите коллекцию remoteParticipant для экземпляра call:

List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants();

Для входящих вызовов это идентификатор вызывающей стороны:

CommunicationIdentifier callerId = call.getCallerInfo().getIdentifier();

Получите состояние вызова:

CallState callState = call.getState();

Возвращается строка, которая представляет текущее состояние вызова:

  • NONE — исходное состояние любого вызова;
  • EARLY_MEDIA — обозначает состояние, при котором перед вызовом воспроизводится объявление;
  • CONNECTING — исходное переходное состояние после осуществления или приема вызова;
  • RINGING — для исходящего вызова означает, что на стороне удаленных участников звучит сигнал вызова;
  • CONNECTED — вызов осуществлен;
  • LOCAL_HOLD — вызов переведен локальным участником в режим ожидания, и потоки мультимедиа не передаются между локальной конечной точкой и удаленными участниками;
  • REMOTE_HOLD — вызов переведен удаленным участником в режим ожидания, и потоки мультимедиа не передаются между локальной конечной точкой и удаленными участниками;
  • DISCONNECTING — переходное состояние перед тем, как вызов перейдет в состояние DISCONNECTED;
  • DISCONNECTED — завершающее состояние вызова.
  • IN_LOBBY — в зале ожидания для взаимодействия конференций Teams.

Чтобы узнать, почему вызов завершился, проверьте свойство callEndReason. Оно содержит основной код и дополнительный код:

CallEndReason callEndReason = call.getCallEndReason();
int code = callEndReason.getCode();
int subCode = callEndReason.getSubCode();

Чтобы узнать, является ли текущий вызов входящим или исходящим, проверьте свойство callDirection:

CallDirection callDirection = call.getCallDirection(); 
// callDirection == CallDirection.INCOMING for incoming call
// callDirection == CallDirection.OUTGOING for outgoing call

Чтобы узнать, отключен ли выбранный микрофон, проверьте свойство muted:

boolean muted = call.isMuted();

Чтобы проверить активные видеопотоки, проверьте коллекцию localVideoStreams:

List<LocalVideoStream> localVideoStreams = call.getLocalVideoStreams();

Отключить звук и включить звук

Чтобы отключить или включить звук для локальной конечной точки, можно использовать асинхронные вызовы API mute и unmute:

Context appContext = this.getApplicationContext();
call.mute(appContext).get();
call.unmute(appContext).get();

Отключение звука других участников

Примечание.

Этот API предоставляется как общедоступная предварительная версия для разработчиков и может изменяться на основе полученных отзывов. Чтобы использовать этот API, используйте бета-версию Службы коммуникации Azure пакета SDK для Android версии 2.6.0-beta.5 или более поздней версии.

Чтобы отключить звук всех остальных участников вызова, используйте muteAllRemoteParticipants API для вызова.

call.muteAllRemoteParticipants();

Чтобы отключить отдельный удаленный участник, используйте mute API для данного удаленного участника.

remoteParticipant.mute();

Изменение объема вызова

Находясь в вызове, аппаратные ключи регулировки громкости на телефоне должны позволить пользователю изменить громкость вызова. Это осуществляется с помощью метода setVolumeControlStream с типом потока AudioManager.STREAM_VOICE_CALL для действия, куда помещается вызов. Это позволяет аппаратным ключам регулировки громкости изменить громкость вызова (обозначенную значком телефонной трубки или другим, аналогичным ползунком громкости), предотвращая изменение громкости для других профилей, таких как громкость оповещений, мультимедиа или системных звуков. Дополнительные сведения см. в статье Обработка изменений в выводе аудио | Разработчикам Android.

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
}

Управление удаленными участниками

Все удаленные участники представлены типом RemoteParticipant и доступны через коллекцию remoteParticipants в экземпляре вызова.

Вывод списка участников в вызове

Коллекция remoteParticipants возвращает список удаленных участников в указанном вызове:

List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants(); // [remoteParticipant, remoteParticipant....]

Добавление участника в вызов

Чтобы добавить в вызов участника (пользователя или номер телефона), можно вызвать addParticipant. Этот вызов в синхронном режиме возвращает экземпляр удаленного участника.

const acsUser = new CommunicationUserIdentifier("<acs user id>");
const acsPhone = new PhoneNumberIdentifier("<phone number>");
RemoteParticipant remoteParticipant1 = call.addParticipant(acsUser);
AddPhoneNumberOptions addPhoneNumberOptions = new AddPhoneNumberOptions(new PhoneNumberIdentifier("<alternate phone number>"));
RemoteParticipant remoteParticipant2 = call.addParticipant(acsPhone, addPhoneNumberOptions);

Удаление участника из вызова

Чтобы удалить участника (пользователя или номер телефона) из вызова, можно вызвать removeParticipant. Это значение будет разрешаться асинхронно после удаления участника из вызова. Этот же участник будет удален из коллекции remoteParticipants.

RemoteParticipant acsUserRemoteParticipant = call.getParticipants().get(0);
RemoteParticipant acsPhoneRemoteParticipant = call.getParticipants().get(1);
call.removeParticipant(acsUserRemoteParticipant).get();
call.removeParticipant(acsPhoneRemoteParticipant).get();

Свойства удаленного участника

С каждым конкретным удаленным участником связан набор свойств и коллекций:

  • Получите идентификатор для этого удаленного участника. Идентификатор имеет один из типов Identifier.

    CommunicationIdentifier participantIdentifier = remoteParticipant.getIdentifier();
    
  • Получите состояние удаленного участника.

    ParticipantState state = remoteParticipant.getState();
    

Состояние может иметь одно из следующих значений:

  • IDLE — исходное состояние;

  • EARLY_MEDIA — перед подключением к вызову для участника воспроизводится объявление;

  • RINGING — для участника звучит сигнал вызова;

  • CONNECTING — переходное состояние во время подключения участника к вызову;

  • CONNECTED — участник подключен к вызову;

  • HOLD — участник находится в режиме ожидания;

  • IN_LOBBY — участник ожидает допуска в зале ожидания. (в настоящее время используется только в сценарии взаимодействия с Teams);

  • DISCONNECTED — окончательное состояние, которое обозначает завершение вызова для участника.

  • Чтобы узнать, почему участник покинул вызов, проверьте свойство callEndReason:

    CallEndReason callEndReason = remoteParticipant.getCallEndReason();
    
  • Чтобы проверить, отключен ли звук для удаленного участника, проверьте свойство isMuted:

    boolean isParticipantMuted = remoteParticipant.isMuted();
    
  • Чтобы проверить, говорит ли сейчас удаленный участник, проверьте свойство isSpeaking:

    boolean isParticipantSpeaking = remoteParticipant.isSpeaking();
    
  • Чтобы проверить все видеопотоки, отправляемые определенным участником в вызове, проверьте коллекцию videoStreams:

    List<RemoteVideoStream> videoStreams = remoteParticipant.getVideoStreams(); // [RemoteVideoStream, RemoteVideoStream, ...]
    

Использование служб переднего плана

В случаях, когда вы хотите запустить пользователь видимую задачу, даже если приложение находится в фоновом режиме, можно использовать службы Foreground.

Например, используя службы Foreground, вы можете сохранить отображаемое пользователем уведомление при активном вызове приложения. Таким образом, даже если пользователь переходит на домашний экран или удаляет приложение из последнего экрана, вызов будет продолжать активно.

Если вы не используете службу переднего плана во время вызова, переход к домашнему экрану может поддерживать активный вызов, но удаление приложения с экрана последних может остановить вызов, если ОС Android убьет процесс приложения.

При запуске или присоединении к вызову необходимо запустить службу переднего плана, например:

call = callAgent.startCall(context, participants, options);
startService(yourForegroundServiceIntent);

И остановите службу переднего плана при зависание вызова или состояние вызова отключено, например:

call.hangUp(new HangUpOptions()).get();
stopService(yourForegroundServiceIntent);

Заметки об использовании служб Foreground

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

Если приложение останавливает службу переднего плана в методе службы onTaskRemoved , например, приложение может запускать и останавливать аудио и видео в соответствии с жизненным циклом действий, например остановкой звука и видео при уничтожении действия с onDestroy помощью переопределения метода.

Настройка системы

Создайте проект Xcode

В Xcode создайте новый проект iOS и выберите шаблон Single View App (Приложение с одним представлением). В этом кратком руководстве используется платформа SwiftUI, поэтому необходимо задать для языка значениеSwiftUI и задать для интерфейса значение SwiftUI.

В рамках этого краткого руководства вы не будете создавать тесты. Вы можете очистить поле "Включить тесты" проверка box.

Снимок экрана, на котором показано окно для создания проекта в 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")
        }
})

Примечание.

Для реализации делегатов событий приложением требуется, чтобы оно содержало строгую ссылку на объекты, которым требуются подписки на события. Например, если объект RemoteParticipant возвращается при вызове метода call.addParticipant, а приложение настраивает делегата для прослушивания RemoteParticipantDelegate, приложение должно содержать строгую ссылку на объект RemoteParticipant. В противном случае делегат выдаст неустранимое исключение при запросе этого объекта вызывающим пакетом SDK, если объект уже был удален обработчиком мусора.

Осуществление исходящего вызова

Чтобы создать и начать вызов, необходимо вызвать одну из API для объекта CallAgent и предоставить в вызове удостоверение Служб коммуникации того пользователя, которое вы ранее подготовили к работе с помощью пакета SDK управления Службами коммуникации.

Операции создания и начала вызовов выполняются синхронно. Вы получите экземпляр вызова, который позволяет подписываться на все события в этом вызове.

Осуществление персонального вызова к пользователю или группового вызова к пользователям и ТСОП

let callees = [CommunicationUser(identifier: 'UserId')]
self.callAgent?.startCall(participants: callees, options: StartCallOptions()) { (call, error) in
     if error == nil {
         print("Successfully started outgoing call")
         self.call = call
     } else {
         print("Failed to start outgoing call")
     }
}

Осуществление группового вызова к пользователям и ТСОП

Примечание.

Проверка подробные сведения о предложении звонков по ТСОП. Для доступа к программе предварительной версии применяется к программе раннего внедрения.

Чтобы создать вызов к ТСОП, необходимо указать номер телефона, полученный от Служб коммуникации.

let pstnCallee = PhoneNumberIdentifier(phoneNumber: '+1999999999')
let callee = CommunicationUserIdentifier('UserId')
self.callAgent?.startCall(participants: [pstnCallee, callee], options: StartCallOptions()) { (groupCall, error) in
     if error == nil {
         print("Successfully started outgoing call to multiple participants")
         self.call = groupCall
     } else {
         print("Failed to start outgoing call to multiple participants")
     }
}

Присоединение к вызову комнаты

Чтобы присоединиться к вызову room , укажите roomId свойство в качестве идентификатора room . Чтобы присоединиться к вызову join , используйте метод и передайте метод roomCallLocator.

func joinRoomCall() {
    if self.callAgent == nil {
        print("CallAgent not initialized")
        return
    }
    
    if (self.roomId.isEmpty) {
        print("Room ID not set")
        return
    }
    
    // Join a call with a Room ID
    let options = JoinCallOptions()
    let audioOptions = AudioOptions()
    audioOptions.muted = self.muted
    
    options.audioOptions = audioOptions
    
    let roomCallLocator = RoomCallLocator(roomId: roomId)
    self.callAgent!.join(with: roomCallLocator, joinCallOptions: options) { (call, error) in
        self.setCallAndObserver(call: call, error: error)
    }
}

Разработчики room приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Дополнительные сведения см rooms. в концептуальной документации или кратком руководстве по началу работы.

Присоединение к групповому вызову

Чтобы присоединиться к вызову, необходимо вызвать одну из API для объекта CallAgent.

let groupCallLocator = GroupCallLocator(groupId: UUID(uuidString: "uuid_string")!)
self.callAgent?.join(with: groupCallLocator, joinCallOptions: JoinCallOptions()) { (call, error) in
    if error == nil {
        print("Successfully joined group call")
        self.call = call
    } else {
        print("Failed to join group call")
    }
}

Подписка на входящий вызов

Подписка на событие входящего вызова.

final class IncomingCallHandler: NSObject, CallAgentDelegate, IncomingCallDelegate
{
    // Event raised when there is an incoming call
    public func callAgent(_ callAgent: CallAgent, didReceiveIncomingCall incomingcall: IncomingCall) {
        self.incomingCall = incomingcall
        // Subscribe to get OnCallEnded event
        self.incomingCall?.delegate = self
    }

    // Event raised when incoming call was not answered
    public func incomingCall(_ incomingCall: IncomingCall, didEnd args: PropertyChangedEventArgs) {
        print("Incoming call was not answered")
        self.incomingCall = nil
    }
}

Прием входящего вызова

Чтобы принять вызов, вызовите метод accept для объекта IncomingCall.

self.incomingCall!.accept(options: AcceptCallOptions()) { (call, error) in
   if (error == nil) {
       print("Successfully accepted incoming call")
       self.call = call
   } else {
       print("Failed to accept incoming call")
   }
}

let firstCamera: VideoDeviceInfo? = self.deviceManager!.cameras.first
localVideoStreams = [LocalVideoStream]()
localVideoStreams!.append(LocalVideoStream(camera: firstCamera!))
let acceptCallOptions = AcceptCallOptions()
acceptCallOptions.videoOptions = VideoOptions(localVideoStreams: localVideoStreams!)
if let incomingCall = self.incomingCall {
    incomingCall.accept(options: acceptCallOptions) { (call, error) in
        if error == nil {
            print("Incoming call accepted")
        } else {
            print("Failed to accept incoming call")
        }
    }
} else {
  print("No incoming call found to accept")
}

Выполнение операций в процессе вызова

Во время вызова вы можете выполнять различные операции для управления параметрами видео и аудио.

Отключить звук и включить звук

Чтобы отключить или включить звук для локальной конечной точки, можно использовать асинхронные вызовы API mute и unmute.

call!.mute { (error) in
    if error == nil {
        print("Successfully muted")
    } else {
        print("Failed to mute")
    }
}

Используйте следующий код для асинхронного отключения локальной конечной точки.

call!.unmute { (error) in
    if error == nil {
        print("Successfully un-muted")
    } else {
        print("Failed to unmute")
    }
}

Отключение звука других участников

Примечание.

Этот API предоставляется как общедоступная предварительная версия для разработчиков и может изменяться на основе полученных отзывов. Чтобы использовать этот API, используйте бета-версию пакета SDK Службы коммуникации Azure для iOS версии 2.7.0-beta.3 или более поздней.

Чтобы отключить звук всех остальных участников вызова, используйте muteAllRemoteParticipants API для вызова.

call!.muteAllRemoteParticipants { (error) in
    if error == nil {
        print("Successfully muted all remote participants.")
    } else {
        print("Failed to mute remote participants.")
    }
}

Чтобы отключить отдельный удаленный участник, используйте mute API для данного удаленного участника.

remoteParticipant.mute { (error) in
    if error == nil {
        print("Successfully muted participant.")
    } else {
        print("Failed to mute participant.")
    }
}

Управление удаленными участниками

Все удаленные участники представлены типом RemoteParticipant и доступны через коллекцию remoteParticipants в экземпляре вызова.

Вывод списка участников в вызове

call.remoteParticipants

Добавление участника в вызов

Чтобы добавить в вызов участника (пользователя или номер телефона), можно вызвать addParticipant. Вызов этой команды возвращает в синхронном режиме экземпляр удаленного участника.

let remoteParticipantAdded: RemoteParticipant = call.add(participant: CommunicationUserIdentifier(identifier: "userId"))

Удаление участника из вызова

Чтобы удалить участника (пользователя или номер телефона) из вызова, можно воспользоваться вызовом API removeParticipant. Разрешение выполняется асинхронно.

call!.remove(participant: remoteParticipantAdded) { (error) in
    if (error == nil) {
        print("Successfully removed participant")
    } else {
        print("Failed to remove participant")
    }
}

Получение свойств удаленного участника

// [RemoteParticipantDelegate] delegate - an object you provide to receive events from this RemoteParticipant instance
var remoteParticipantDelegate = remoteParticipant.delegate

// [CommunicationIdentifier] identity - same as the one used to provision a token for another user
var identity = remoteParticipant.identifier

// ParticipantStateIdle = 0, ParticipantStateEarlyMedia = 1, ParticipantStateConnecting = 2, ParticipantStateConnected = 3, ParticipantStateOnHold = 4, ParticipantStateInLobby = 5, ParticipantStateDisconnected = 6
var state = remoteParticipant.state

// [Error] callEndReason - reason why participant left the call, contains code/subcode/message
var callEndReason = remoteParticipant.callEndReason

// [Bool] isMuted - indicating if participant is muted
var isMuted = remoteParticipant.isMuted

// [Bool] isSpeaking - indicating if participant is currently speaking
var isSpeaking = remoteParticipant.isSpeaking

// RemoteVideoStream[] - collection of video streams this participants has
var videoStreams = remoteParticipant.videoStreams // [RemoteVideoStream, RemoteVideoStream, ...]

Настройка системы

Создание проекта Visual Studio

Для приложения UWP в Visual Studio 2022 создайте проект пустого приложения (универсального приложения Windows). После ввода имени проекта вы можете выбрать любой пакет SDK для Windows позже 10.0.17763.0.

Для приложения WinUI 3 создайте проект с шаблоном "Пустое приложение" (WinUI 3 в классическом приложении) для настройки одностраничного приложения WinUI 3. Требуется пакет SDK для приложений Windows версии 1.3 или более поздней.

Установка пакета и зависимостей с помощью NuGet диспетчер пакетов

Api и библиотеки пакета SDK для вызовов общедоступны через пакет NuGet.

Ниже приведены инструкции по поиску, скачиванию и установке пакета NuGet пакета Sdk для вызовов:

  1. Откройте nuGet диспетчер пакетов, выбрав инструменты>NuGet диспетчер пакетов> Manage NuGet Packages for Solution.
  2. Нажмите кнопку "Обзор", а затем введите Azure.Communication.Calling.WindowsClient в поле поиска.
  3. Убедитесь, что выбрано поле "Включить предварительную версию" проверка.
  4. Azure.Communication.Calling.WindowsClient Выберите пакет и выберите Azure.Communication.Calling.WindowsClientверсию 1.4.0-beta.1 или более новую версию.
  5. Выберите поле проверка, соответствующее проекту служб коммуникации на правой части вкладки.
  6. Нажмите кнопку Установить.

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

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

В следующих шагах показано, как это сделать.

  1. На панели Solution Explorer дважды щелкните файл с расширением .appxmanifest.
  2. Щелкните вкладку Capabilities.
  3. Установите флажок Microphone в списке возможностей.

Создание кнопок пользовательского интерфейса для совершения и завершения вызова

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

  1. Solution Explorer На панели дважды щелкните файл с именем MainPage.xaml UWP или MainWindows.xaml WinUI 3.
  2. На центральной панели найдите код XAML в предварительной версии пользовательского интерфейса.
  3. Измените код XAML следующим фрагментом:
<TextBox x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" />
<StackPanel>
    <Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" />
    <Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" />
</StackPanel>

Настройка приложения с помощью API пакета SDK для вызовов

API пакета SDK для вызовов находятся в двух разных пространствах имен. С помощью следующих шагов можно сообщить компилятору C# об этих пространствах имен, что позволяет IntelliSense в Visual Studio упростить разработку кода.

  1. Solution Explorer На панели щелкните стрелку в левой части файла с именем MainPage.xaml UWP или MainWindows.xaml WinUI 3.
  2. Дважды щелкните файл с именем MainPage.xaml.cs или MainWindows.xaml.cs.
  3. Добавьте следующие команды в конце текущих инструкций using.
using Azure.Communication.Calling.WindowsClient;

Сохранение MainPage.xaml.cs или MainWindows.xaml.cs открытие. Вы добавите в него дополнительный код с помощью последующих действий.

Разрешение взаимодействий с приложением

Добавленные ранее кнопки пользовательского интерфейса должны работать на основе размещенного вызова (CommunicationCall). Это означает, что CommunicationCall член данных должен быть добавлен в MainPage класс или MainWindow класс. Кроме того, чтобы обеспечить успешное выполнение асинхронной операции для создания CallAgent, элемент данных CallAgent также необходимо добавить в тот же класс.

Добавьте в класс pr MainWindow следующие элементы MainPage данных:

CallAgent callAgent;
CommunicationCall call;

Создание обработчиков кнопок

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

private async void CallButton_Click(object sender, RoutedEventArgs e)
{
    // Start call
}

private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
    // End the current call
}

Объектная модель

Следующие классы и интерфейсы реализуют некоторые основные функции клиентской библиотеки вызовов в Службах коммуникации Azure для UWP:

Имя Описание
CallClient Это CallClient основная точка входа в клиентную библиотеку вызовов.
CallAgent Используется CallAgent для запуска и присоединения вызовов.
CommunicationCall Используется CommunicationCall для управления размещенными или присоединенными вызовами.
CommunicationTokenCredential Используется CommunicationTokenCredential в качестве учетных данных маркера для создания экземпляра CallAgent.
CallAgentOptions Содержит CallAgentOptions сведения для идентификации вызывающего объекта.
HangupOptions Сообщает HangupOptions , следует ли прервать звонок всем участникам.

Инициализация CallAgent

Чтобы создать CallAgent экземпляр, CallClientнеобходимо использовать CallClient.CreateCallAgentAsync метод, который асинхронно возвращает CallAgent объект после инициализации.

Для создания CallAgent необходимо передать объект CallTokenCredential и объект CallAgentOptions. Помните, что CallTokenCredential выдает исключение при передаче неправильного маркера.

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

var callClient = new CallClient();
this.deviceManager = await callClient.GetDeviceManagerAsync();

var tokenCredential = new CallTokenCredential("<AUTHENTICATION_TOKEN>");
var callAgentOptions = new CallAgentOptions()
{
    DisplayName = "<DISPLAY_NAME>"
};

this.callAgent = await callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);

Измените <AUTHENTICATION_TOKEN> допустимый маркер учетных данных для ресурса. Если вам необходимо получить маркер учетных данных, см. документацию по маркеру доступа пользователя.

Создание CallAgent и совершение вызова

Объекты, необходимые для создания CallAgent, теперь готовы. Пришло время асинхронно создавать CallAgent и размещать вызов.

Следующий код следует добавить после обработки исключения из предыдущего шага.

var startCallOptions = new StartCallOptions();
var callees = new [] { new UserCallIdentifier(CalleeTextBox.Text.Trim()) };

this.call = await this.callAgent.StartCallAsync(callees, startCallOptions);
this.call.OnStateChanged += Call_OnStateChangedAsync;

Вы можете поговорить 8:echo123 с Службы коммуникации Azure эхо-ботом.

Отключить звук и включить звук

Чтобы отключить или отменить исходящий звук, можно использовать MuteOutgoingAudioAsync асинхронные UnmuteOutgoingAudioAsync API:

// mute outgoing audio
await this.call.MuteOutgoingAudioAsync();

// unmute outgoing audio
await this.call.UnmuteOutgoingAudioAsync();

Отключение звука других участников

Примечание.

Этот API предоставляется как общедоступная предварительная версия для разработчиков и может изменяться на основе полученных отзывов. Чтобы использовать этот API, используйте бета-версию Службы коммуникации Azure вызова пакета SDK для Windows версии 1.4.0-beta.1 или более поздней.

Чтобы отключить звук всех остальных участников или отключить определенный участник, можно использовать асинхронные API MuteAllRemoteParticipantsAsync для вызова и MuteAsync удаленного участника:

// mute all participants except yourself
await this.call.MuteAllRemoteParticipantsAsync();

// mute specific participant in the call
await this.call.RemoteParticipants.FirstOrDefault().MuteAsync();

Завершение вызова

После совершения вызова используйте метод HangupAsync объекта CommunicationCall, чтобы завершить вызов.

Экземпляр HangupOptions также следует использовать для сообщения всем участникам о необходимости завершения вызова.

Следующий код нужно добавить в HangupButton_Click.

this.call.OnStateChanged -= Call_OnStateChangedAsync;
await this.call.HangUpAsync(new HangUpOptions() { ForEveryone = false });

Выполнение кода

Убедитесь, что Visual Studio создает приложение для x64, x86 или ARM64нажмите, F5 чтобы запустить приложение. После этого нажмите кнопку Call, чтобы совершить вызов к определенному вызываемому.

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

Следующие шаги