Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описывается, как управлять вызовами с помощью пакета SDK для вызовов служб коммуникации Azure. В разделах содержатся сведения о том, как размещать вызовы, управлять участниками и управлять свойствами.
Предварительные условия
- Учетная запись Azure с активной подпиской. Создайте учетную запись бесплатно .
- Развернут ресурс службы коммуникаций. Создайте ресурс Служб коммуникации.
-
User Access Tokenдля активации клиента связи. Дополнительные сведения о том, как получитьUser Access Token. - Необязательно: завершите настройку функции вызовов в вашем приложении.
Поддержка
В следующих таблицах описывается поддержка комнат для обсуждений в Службах коммуникации Azure.
Идентичности и типы вызовов
В следующей таблице показана поддержка функций для конкретного типа вызова и идентификации.
| Удостоверения | Встреча в Teams | Комната | Вызов 1:1 | Групповой вызов | Вызов для взаимодействия команд в режиме 1:1 | Взаимодействие групп в Teams |
|---|---|---|---|---|---|---|
| Пользователь служб коммуникации | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Пользователь Microsoft 365 | ✔️ | ✔️ | ✔️ |
Операции
В следующей таблице показана поддержка отдельных API в пакете SDK для вызовов, связанном с отдельными типами удостоверений.
| Операции | Пользователь служб коммуникации | Пользователь Microsoft 365 |
|---|---|---|
| Начать вызов пользователю Службы связи | ✔️ | |
| Запуск вызова пользователю Microsoft 365 | ✔️ | ✔️ |
| Запуск звонка на номер телефона | ✔️ | ✔️ |
| Присоединитесь к комнате | ✔️ | |
| Присоединитесь к собранию Teams | ✔️ | ✔️ |
| Подключиться к вызову по идентификатору группы groupId | ✔️ | |
| Принятие или отклонение входящего вызова | ✔️ | ✔️ |
| Удержание и возобновление вызова | ✔️ | ✔️ |
| Пригласить участников | ✔️ | ✔️ |
| Добавление пользователя Служб коммуникации | ✔️ | |
| Удаление пользователя Служб коммуникации | ✔️ | ✔️ |
| Добавление или удаление пользователя Microsoft 365 | ✔️ | ✔️ |
| Добавление или удаление номера телефона | ✔️ | ✔️ |
| Включение или выключение звука удаленного участника | ✔️ [1] | ✔️ [1] |
| Положить трубку | ✔️ | ✔️ |
| Завершите вызов для всех | ✔️ [2] | ✔️ |
[1] API поддерживается только в групповых вызовах, комнатах для совещаний и собраниях Teams. [2] API не поддерживается в комнатах.
Пакеты SDK
В следующих таблицах показана поддержка функций в отдельных пакетах SDK Службы коммуникации Azure.
| Состояние поддержки | Интернет | Веб-интерфейс | iOS | Пользовательский интерфейс iOS | Андроид | Пользовательский интерфейс Android | Виндоус |
|---|---|---|---|---|---|---|---|
| Поддерживается | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Установка пакета SDK
Используйте команду npm install для установки пакета JavaScript SDK для общих функций и вызовов службы связи Azure.
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()
Управление подключением пакета SDK к инфраструктуре Майкрософт
Экземпляр Call Agent помогает вам управлять вызовами, присоединяться к ним или начинать их. Для работы пакета SDK для вызова необходимо подключиться к инфраструктуре Майкрософт для получения уведомлений о входящих звонках и координации других сведений о вызове. Ваш Call Agent имеет два возможных состояния:
Подключено — Call Agent значение Connected connectionStatue означает, что клиентский пакет SDK подключен и способен получать уведомления из инфраструктуры Майкрософт.
Отключено — значение Call Agent статуса соединения Disconnected указывает на проблему, которая препятствует правильному подключению SDK.
Call Agent следует создать заново.
-
invalidToken: если срок действия маркера истек или он недействителен,Call Agentэкземпляр отключается из-за этой ошибки. - Если у клиента возникает проблема с подключением к инфраструктуре Майкрософт, после многих повторных попыток проявляется ошибка #D2.
Вы можете проверить, подключен ли локальный сервер Call Agent к инфраструктуре Майкрософт, проверив текущее значение connectionState свойства. Во время активного вызова можно прослушивать connectionStateChanged событие, чтобы определить, изменяется ли Call Agent из состояния Подключено в состояние Отключено.
const connectionState = callAgentInstance.connectionState;
console.log(connectionState); // it may return either of 'Connected' | 'Disconnected'
const connectionStateCallback = (args) => {
console.log(args); // it will return an object with oldState and newState, each of having a value of either of 'Connected' | 'Disconnected'
// it will also return reason, either of 'invalidToken' | 'connectionIssue'
}
callAgentInstance.on('connectionStateChanged', connectionStateCallback);
Осуществление вызовов
Чтобы создать и запустить вызов, используйте один из интерфейсов API на callAgent и предоставьте пользователя, созданного с помощью набора средств разработки идентификаций служб связи.
Операции создания и начала вызовов выполняются синхронно. Экземпляр call позволяет подписываться на события вызова.
Совершить 1:n вызов пользователю или ТСОП (общественная телефонная сеть)
Чтобы позвонить другому пользователю Служб коммуникации, вызовите метод startCall на callAgent и передайте CommunicationUserIdentifier получателя, который вы создали с помощью библиотеки управления Служб коммуникации.
Для вызова пользователя 1:1 используйте следующий код:
const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const oneToOneCall = callAgent.startCall([userCallee]);
Чтобы осуществить вызов к телефонной сети общего пользования (ТСОП), вызовите метод startCall на callAgent и передайте PhoneNumberIdentifier получателю. В вашем ресурсе коммуникационных служб должно быть разрешено осуществление вызовов в ТСОП.
При вызове номера PSTN укажите свой альтернативный ID вызывающего абонента. Альтернативный идентификатор вызывающего — это номер телефона (по стандарту E.164), который определяет звонящего в вызове ТСОП. Это номер телефона, который получатель вызова видит при входящем вызове.
Примечание.
Посмотрите подробности предложения звонков по ТСОП. Для доступа к программе предварительной версии подайте заявку на участие в программе раннего внедрения.
Для осуществления персонального вызова по номеру PSTN используйте следующий код:
const pstnCallee = { phoneNumber: '<ACS_USER_ID>' }
const alternateCallerId = {phoneNumber: '<ALTERNATE_CALLER_ID>'};
const oneToOneCall = callAgent.startCall([pstnCallee], { alternateCallerId });
Для осуществления 1:n вызова пользователю и по номеру 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 приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Для получения дополнительной информации о комнатах см. API для комнат структурированных собраний и подключение к звонку в комнате.
Присоединение к групповому вызову
Примечание.
Параметр 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 вызывает диагностику cameraStartFailed: true вызовов, если камера недоступна при запуске, принятии или присоединении к вызову с включенным видео. В этом случае вызов начинается с выключенным видео. Камера может быть недоступна, так как она используется другим процессом или отключена в операционной системе.
Удержание и возобновление вызова
Примечание.
В любой момент должен быть только один активный вызов (1) в Connected состоянии с активным носителем. Все остальные вызовы должны быть помещены на удержание пользователем либо с помощью приложения. Этот сценарий распространен в таких сценариях, как центры контактов, где пользователю может потребоваться обрабатывать несколько исходящих и входящих вызовов. В этом случае все неактивные вызовы должны быть помещены на удержание, и пользователь должен взаимодействовать с другими только в активном вызове.
Чтобы удерживать или возобновлять вызов, используйте асинхронные API: hold и resume
Чтобы провести вызов, выполните следующие действия:
await call.hold();
Когда операция hold разрешается, состояние вызова устанавливается в LocalHold. Во время личного вызова другой участник также ставится на удержание, и состояние вызова по мнению этого участника задано RemoteHold. Позже другой участник может поместить свой вызов на удержание, что приведет к изменению состояния на LocalHold.
В групповом вызове или собрании — hold это локальная операция, она не удерживает вызов для других участников.
Чтобы возобновить звонок, все пользователи, инициирующие удержание, должны возобновить его.
Чтобы возобновить вызов из режима удержания:
await call.resume();
resume При разрешении операции состояние вызова снова задает значение 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.
//mute local device (speaker)
await call.muteIncomingAudio();
//unmute local device (speaker)
await call.unmuteIncomingAudio();
При отключении входящего звука пакет SDK клиента участника по-прежнему получает звук вызова (звук удаленного участника). Звук вызова не услышится в динамике, и участник не может прослушивать, пока call.unmuteIncomingAudio() не будет вызван. Однако мы можем применить фильтр к звуку вызова и воспроизвести отфильтрованный звук.
Управление удаленными участниками
Все удаленные участники включены в объект RemoteParticipant и доступны через коллекцию remoteParticipants в экземпляре вызова. Объект remoteParticipants доступен из экземпляра Call .
Перечислите участников вызова
Коллекция remoteParticipants возвращает список удаленных участников в вызове:
call.remoteParticipants; // [remoteParticipant, remoteParticipant....]
Добавьте участника в вызов
Чтобы добавить участника (пользователя или номер телефона) на звонок, используйте addParticipant операцию. Предоставьте один из типов Identifier. Он синхронно возвращает экземпляр remoteParticipant. При успешном добавлении участника в вызов генерируется событие remoteParticipantsUpdated для вызова.
const userIdentifier = { communicationUserId: '<ACS_USER_ID>' };
const pstnIdentifier = { phoneNumber: '<PHONE_NUMBER>' }
const remoteParticipant = call.addParticipant(userIdentifier);
const alternateCallerId = { phoneNumber: '<ALTERNATE_CALLER_ID>' };
const remoteParticipant = call.addParticipant(pstnIdentifier, { alternateCallerId });
Удаление участника из вызова
Чтобы удалить участника (пользователя или номер телефона) из звонка, можно позвонить 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 он не видит, что этот флаг установлен для UserC. Другими словами, UserA вовсе не видит, чтобы свойство callEndReason для UserC было установлено.
Состояние
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.
Отключение звука других участников
Примечание.
Чтобы отключить звук других участников VoIP, необходимо использовать веб-пакет SDK для служб коммуникации Azure версии 1.26.1 или более поздней версии. Чтобы отключить конечные точки ТСОП, необходимо использовать GA 1.33.1 WebJS (или более поздняя версия).
Примечание.
Отключение звука других пользователей при 1:1 вызове не поддерживается.
Чтобы отключить звук всех остальных участников или определенного участника, подключенного к вызову, можно использовать асинхронные API muteAllRemoteParticipants на вызове и mute на удаленном участнике. Событие mutedByOthers в приложении Call возникает, когда локального участника отключают другие.
Отключение конечной точки ТСОП с помощью вызывающего пакета SDK WebJS в настоящее время находится в общедоступной версии и доступно в сборке 1.34.1 1.34.1 и более поздних версиях.
//mute all participants except yourself
await call.muteAllRemoteParticipants();
//mute a specific participant
await call.remoteParticipants[0].mute();
Проверка свойств вызова
Получите уникальный идентификатор (в строковом формате) вызова:
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 callEndReasonMessage = callEndReason.message // (string) user friendly message
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 возвращает 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;
Положить трубку
Есть два способа закончить звонок.
- Первоначальный звонящий может покинуть звонок, а другие участники остаются в звонке.
- Когда первый вызывающий абонент завершает участие, вызов завершается для всех участников.
Чтобы выйти из звонка, используйте:
call.hangUp();
Завершите вызов для всех участников, используя HangUpOptions.
Примечание.
Эта операция недоступна в комнатах.
call.hangUp( forEveryone: true);
Установка пакета 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);
Совершите вызов 1:n с пользователями и ТСОП
Примечание.
Посмотрите подробности предложения звонков по ТСОП. Для доступа к программе предварительной версии подайте заявку на участие в программе раннего внедрения.
Чтобы осуществить 1:n звонок пользователю и на номер общедоступной телефонной сети (ТСОП), необходимо указать номер телефона получателя или получателей.
Ресурс Служб коммуникации должен быть настроен для включения вызова ТСОП:
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 приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Для получения дополнительной информации о комнатах см. API для комнат структурированных собраний и подключение к звонку в комнате.
Присоединение к групповому вызову
Чтобы запустить новый групповой вызов или присоединиться к текущему групповому вызову, необходимо вызвать 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();
Изменение объема вызова
Во время звонка кнопки регулировки громкости на телефоне должны позволять пользователю изменять громкость звонка.
Используйте метод 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, ...]
Отключение звука других участников
Примечание.
Используйте пакет SDK для Служб коммуникации Azure для Android версии 2.11.0 или более поздней.
Когда участник ТСОП имеет выключенный звук, он получает объявление о том, что у него выключен звук и что он может нажать сочетание клавиш (например, *6), чтобы включить звук. Когда они нажимают *6, они не мутируются.
Чтобы отключить звук всех остальных участников вызова, используйте muteAllRemoteParticipants операцию API.
call.muteAllRemoteParticipants();
Чтобы отключить отдельный удаленный участник, используйте mute операцию API для данного удаленного участника.
remoteParticipant.mute();
Чтобы уведомить локального участника о том, что они отключены другими пользователями, подпишитесь на onMutedByOthers событие.
Использование служб переднего плана
Если вы хотите запустить задачу, видимую пользователем, даже если приложение находится в фоновом режиме, можно использовать службы Foreground Services.
Используйте службы Foreground, например, для предоставления пользователям видимого уведомления при активном вызове приложения. Таким образом, даже если пользователь переходит на домашний экран или удаляет приложение с экрана последних версий, вызов продолжает быть активным.
Если вы не используете службу переднего плана во время вызова, переключение на домашний экран может поддерживать активный вызов, но удаление приложения с экрана последних приложений может завершить вызов, если ОС Android завершит процесс вашего приложения.
При запуске или присоединении пользователя к вызову следует запустить службу Foreground, например:
call = callAgent.startCall(context, participants, options);
startService(yourForegroundServiceIntent);
Вы также должны остановить службу переднего плана, когда вы завершаете звонок или состояние вызова — разъединено, например, когда:
call.hangUp(new HangUpOptions()).get();
stopService(yourForegroundServiceIntent);
Сведения о фоновой службе
Помните, что в таких сценариях, как остановка уже работающей службы переднего плана при удалении приложения из списка недавних, также удаляется уведомление, видимое пользователю. В этом случае ОС Android может поддерживать процесс приложения в течение некоторого дополнительного периода времени, что означает, что вызов может оставаться активным в течение этого периода.
Если приложение останавливает службу переднего плана в методе службы onTaskRemoved , например, приложение может запускать или останавливать звук и видео в соответствии с жизненным циклом действий. Например, остановка аудио и видео при завершении активности с помощью переопределения метода onDestroy.
Настройка системы
Выполните следующие действия, чтобы настроить систему.
Создайте проект Xcode
В Xcode создайте новый проект iOS и выберите шаблон Single View App (Приложение с одним представлением). В этой статье используется платформа SwiftUI, поэтому необходимо задать для языка значение Swift и задать для интерфейсазначение SwiftUI.
Вы не собираетесь создавать тесты в этой статье. Вы можете снять флажок "Включить тесты".
Установка пакета и зависимостей с помощью CocoaPods
Создайте Podfile для приложения, как показано в следующем примере:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' endЗапустите
pod install.Откройте
.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")
}
})
Примечание.
Когда приложение реализует делегаты событий, оно должно содержать надежную ссылку на объекты, требующие подписок на события. Например, при вызове call.addParticipant метода и возврате RemoteParticipant объекта. Затем приложение устанавливает делегата для прослушивания на 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")
}
}
Совершите вызов 1:n с пользователями и ТСОП
Примечание.
Посмотрите подробности предложения звонков по ТСОП. Для доступа к программе предварительной версии подайте заявку на участие в программе раннего внедрения.
Чтобы установить соединение 1:n с пользователем и публичной коммутируемой телефонной сетью (ТСОП), необходимо указать номер телефона, полученный с помощью Служб Коммуникации.
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 приложений лучше управляют тем, кто может присоединиться к вызову, когда они встречаются и как они сотрудничают. Для получения дополнительной информации о комнатах см. API для комнат структурированных собраний и подключение к звонку в комнате.
Присоединение к групповому вызову
Чтобы присоединиться к вызову, необходимо вызвать одну из 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")
}
}
Управление удаленными участниками
Тип RemoteParticipant представляет всех удаленных участников. Они доступны через коллекцию remoteParticipants в экземпляре вызова.
Список участников вызова
call.remoteParticipants
Добавьте участника в вызов
Чтобы добавить в звонок участника как пользователя или номер телефона, выполните операцию addParticipant. Эта операция синхронно возвращает удаленный экземпляр объекта участника.
let remoteParticipantAdded: RemoteParticipant = call.add(participant: CommunicationUserIdentifier(identifier: "userId"))
Удаление участника из вызова
Чтобы удалить участника - пользователя или телефонный номер - из звонка, используйте 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, ...]
Отключение звука других участников
Примечание.
Используйте пакет SDK для служб коммуникации Azure для вызовов iOS версии 2.13.0 или более поздней.
Когда участник ТСОП имеет выключенный звук, он получает объявление о том, что у него выключен звук и что он может нажать сочетание клавиш (например, *6), чтобы включить звук. Когда они нажимают *6, они разблокируют звук.
Чтобы отключить звук всех остальных участников вызова, используйте muteAllRemoteParticipants операцию при вызове.
call!.muteAllRemoteParticipants { (error) in
if error == nil {
print("Successfully muted all remote participants.")
} else {
print("Failed to mute remote participants.")
}
}
Чтобы отключить отдельного удаленного участника, используйте операцию mute для этого участника.
remoteParticipant.mute { (error) in
if error == nil {
print("Successfully muted participant.")
} else {
print("Failed to mute participant.")
}
}
Чтобы уведомить локального участника о том, что они отключены другими пользователями, подпишитесь на onMutedByOthers событие.
Настройка системы
Выполните следующие действия, чтобы настроить систему.
Создание проекта Visual Studio
Для приложения на платформе универсальных приложений Windows в 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:
- Откройте nuGet диспетчер пакетов, выбрав > Manage NuGet Packages for Solution.
- Выберите "Обзор" и введите Azure.Communication.Calling.WindowsClient в поле поиска.
- Убедитесь, что установлен флажок "Включить предварительную версию ".
- Выберите пакет Azure.Communication.Calling.WindowsClient, а затем выберите Azure.Communication.Calling.WindowsClient1.4.0-beta.1 или более позднюю версию.
- Установите флажок, соответствующий проекту Службы коммуникации Azure на правой панели.
- Выберите Установить.
Реализация примера приложения в Visual Studio
В этом разделе описывается, как разработать приложение для управления вызовами, работающими в Visual Studio.
Запрос доступа к микрофону
Приложению требуется доступ к микрофону. В приложениях универсальной платформы Windows (UWP) возможность микрофона должна быть объявлена в файле манифеста приложения.
Чтобы получить доступ к микрофону, выполните следующие действия.
- На панели
Solution Explorerдважды щелкните файл с расширением.appxmanifest. - Щелкните вкладку
Capabilities. - Установите флажок
Microphoneв списке возможностей.
Создание кнопок пользовательского интерфейса для совершения и завершения вызова
Этот пример приложения содержит две кнопки. одну для проведения вызова и другую для завершения соединения.
Добавьте две кнопки в приложение.
- В панели
Solution Explorerдважды щелкните файл с именем "MainPage.xaml" для UWP или "MainWindows.xaml" для WinUI 3. - На центральной панели найдите код XAML в предварительной версии пользовательского интерфейса.
- Измените код 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 облегчать разработку кода.
- В
Solution Explorerпанели щелкните стрелку слева от файла с именемMainPage.xamlдля UWP илиMainWindows.xamlдля WinUI 3. - Дважды щелкните файл с именем
MainPage.xaml.csилиMainWindows.xaml.cs. - Добавьте следующие команды в конце текущих инструкций
using.
using Azure.Communication.Calling.WindowsClient;
Держите MainPage.xaml.cs или MainWindows.xaml.cs открытым. Дальнейшие действия по добавлению дополнительного кода.
Включение взаимодействия с приложением
Добавленные ранее кнопки пользовательского интерфейса должны работать поверх размещенного CommunicationCall. Это означает, что CommunicationCall член данных должен быть добавлен в MainPage класс или MainWindow класс.
Кроме того, чтобы обеспечить успешное выполнение асинхронной операции для создания CallAgent, элемент данных CallAgent также необходимо добавить в тот же класс.
Добавьте в класс MainPage pr MainWindow следующие поля данных:
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 |
Это основная точка входа в клиентскую библиотеку для вызовов. |
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.
// mute outgoing audio
await this.call.MuteOutgoingAudioAsync();
// unmute outgoing audio
await this.call.UnmuteOutgoingAudioAsync();
Отключение звука других участников
Примечание.
Используйте пакет SDK для Служб коммуникации Azure для Windows версии 1.9.0 или более поздней.
Когда участник ТСОП отключен, он должен получить объявление о том, что его звук был отключен, и что он может нажать сочетание клавиш (например *6), чтобы включить звук. Когда они нажимают *6, они должны быть незамечены.
Чтобы заглушить всех остальных участников или заглушить определенного участника, используйте асинхронные операции MuteAllRemoteParticipantsAsync с вызовом и MuteAsync удаленным участником:
// mute all participants except yourself
await this.call.MuteAllRemoteParticipantsAsync();
// mute specific participant in the call
await this.call.RemoteParticipants.FirstOrDefault().MuteAsync();
Чтобы уведомить локального участника о том, что они отключены другими пользователями, подпишитесь на MutedByOthers событие.
Завершение вызова
После установления вызова используйте HangupAsync метод объекта CommunicationCall для завершения вызова.
Используйте экземпляр HangupOptions для информирования всех участников о необходимости завершения вызова.
Добавьте в нее следующий код HangupButton_Click:
this.call.OnStateChanged -= Call_OnStateChangedAsync;
await this.call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
Выполнение кода
- Убедитесь, что Visual Studio создает приложение для
x64,x86илиARM64. - Нажмите клавишу F5 , чтобы начать запуск приложения.
- После запуска приложения нажмите кнопку "Звонок ", чтобы поместить вызов определенному получателю.
При первом запуске приложения система предложит пользователю предоставить доступ к микрофону.