Zarządzanie wideo podczas połączeń
Dowiedz się, jak zarządzać wywołaniami wideo za pomocą zestawu SDK usług Azure Communication Services. Dowiesz się, jak zarządzać odbieraniem i wysyłaniem wideo w ramach połączenia.
Wymagania wstępne
- Konto platformy Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.
- Wdrożony zasób usług komunikacyjnych. Utwórz zasób usług komunikacyjnych.
- Token dostępu użytkownika umożliwiający włączenie klienta wywołującego. Aby uzyskać więcej informacji, zobacz Tworzenie tokenów dostępu i zarządzanie nimi.
- Opcjonalnie: ukończ przewodnik Szybki start, aby dodać połączenie głosowe do aplikacji
Instalacja zestawu SDK
Użyj polecenia , npm install
aby zainstalować wspólny zestaw SDK usług Azure Communication Services i wywołujący dla języka JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Inicjowanie wymaganych obiektów
Wystąpienie CallClient
jest wymagane w przypadku większości operacji wywołania. Podczas tworzenia nowego CallClient
wystąpienia można skonfigurować je za pomocą opcji niestandardowych, takich jak Logger
wystąpienie.
CallClient
Za pomocą wystąpienia można utworzyć CallAgent
wystąpienie, wywołując element createCallAgent
. Ta metoda asynchronicznie zwraca CallAgent
obiekt wystąpienia.
Metoda createCallAgent
używa CommunicationTokenCredential
jako argumentu. Akceptuje token dostępu użytkownika.
Aby uzyskać dostęp deviceManager
do obiektu , możesz użyć getDeviceManager
metody w wystąpieniu CallClient
.
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()
Jak najlepiej zarządzać łącznością zestawu SDK z infrastrukturą firmy Microsoft
Wystąpienie Call Agent
pomaga zarządzać wywołaniami (aby dołączyć lub uruchomić wywołania). Aby można było pracować z zestawem SDK wywołującym, należy połączyć się z infrastrukturą firmy Microsoft, aby otrzymywać powiadomienia o połączeniach przychodzących i koordynować inne szczegóły połączeń. Istnieją Call Agent
dwa możliwe stany:
Połączono — Call Agent
wartość Connected
connectionStatue oznacza, że zestaw SDK klienta jest połączony i może odbierać powiadomienia z infrastruktury firmy Microsoft.
Rozłączone — Call Agent
wartość Disconnected
connectionStatue stanów występuje problem uniemożliwiający prawidłowe nawiązywanie połączenia z zestawem SDK. Call Agent
należy utworzyć ponownie.
invalidToken
: Jeśli token wygasł lub jest nieprawidłoweCall Agent
wystąpienie rozłącza się z tym błędem.connectionIssue
: Jeśli występuje problem z połączeniem klienta z infrastrukturą firmy Microsoft, po wielu ponownych próbachCall Agent
connectionIssue
wystąpi błąd.
Możesz sprawdzić, czy środowisko lokalne Call Agent
jest połączone z infrastrukturą firmy Microsoft, sprawdzając bieżącą connectionState
wartość właściwości. Podczas aktywnego wywołania można nasłuchiwać zdarzenia, connectionStateChanged
aby określić, czy Call Agent
zmiany ze stanu Połączono z Odłączone .
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);
Zarządzanie urządzeniami
Aby rozpocząć korzystanie z wideo z zestawem SDK wywoływania, musisz mieć możliwość zarządzania urządzeniami. Urządzenia umożliwiają sterowanie tym, co przesyła dźwięk i wideo do wywołania.
Za pomocą programu deviceManager
można wyliczyć urządzenia lokalne, które mogą przesyłać strumienie audio i wideo w wywołaniu. Możesz również użyć polecenia deviceManager
, aby zażądać uprawnień dostępu do mikrofonów i kamer urządzenia lokalnego.
Dostęp można uzyskać deviceManager
, wywołując metodę callClient.getDeviceManager()
:
const deviceManager = await callClient.getDeviceManager();
Pobieranie urządzeń lokalnych
Aby uzyskać dostęp do urządzeń lokalnych, możesz użyć deviceManager
metod getCameras()
wyliczania i getMicrophones
. Te metody są akcjami asynchronicznymi.
// Get a list of available video devices for use.
const localCameras = await deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
// Get a list of available microphone devices for use.
const localMicrophones = await deviceManager.getMicrophones(); // [AudioDeviceInfo, AudioDeviceInfo...]
// Get a list of available speaker devices for use.
const localSpeakers = await deviceManager.getSpeakers(); // [AudioDeviceInfo, AudioDeviceInfo...]
Ustawianie urządzeń domyślnych
Gdy dowiesz się, jakie urządzenia są dostępne do użycia, możesz ustawić domyślne urządzenia dla mikrofonu, głośnika i aparatu fotograficznego. Jeśli wartości domyślne klienta nie są ustawione, zestaw SDK usług komunikacyjnych używa wartości domyślnych systemu operacyjnego.
Mikrofon
Uzyskiwanie dostępu do używanego urządzenia
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
Ustawianie urządzenia do użycia
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
Speaker
Uzyskiwanie dostępu do używanego urządzenia
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Ustawianie urządzenia do użycia
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Kamera
Uzyskiwanie dostępu do używanego urządzenia
// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Ustawianie urządzenia do użycia
// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);
Każdy CallAgent
z nich może wybrać swój własny mikrofon i głośniki na skojarzonym z nim DeviceManager
. Zalecamy, aby różne CallAgents
mikrofony i głośniki używały różnych mikrofonów. Nie powinny one współdzielić tych samych mikrofonów ani głośników. W przypadku udostępniania może zostać wyzwolona diagnostyka mikrofonu, a mikrofon przestanie działać w zależności od przeglądarki/systemu operacyjnego.
Lokalny strumień wideo
Aby móc wysyłać wideo w wywołaniu, należy utworzyć LocalVideoStream
obiekt.
const localVideoStream = new LocalVideoStream(camera);
Aparat przekazany jako parametr jest jednym z VideoDeviceInfo
obiektów zwracanych przez metodę deviceManager.getCameras()
.
Element LocalVideoStream
ma następujące właściwości:
source
: informacje o urządzeniu.
const source = localVideoStream.source;
mediaStreamType
: może to byćVideo
,ScreenSharing
lubRawMedia
.
const type: MediaStreamType = localVideoStream.mediaStreamType;
Podgląd aparatu lokalnego
Możesz użyć funkcji deviceManager
i VideoStreamRenderer
, aby rozpocząć renderowanie strumieni z aparatu lokalnego.
Po utworzeniu elementu LocalVideoStream
użyj go do skonfigurowaniaVideoStreamRenderer
. Po utworzeniu VideoStreamRenderer
metody wywołaj metodę createView()
, aby uzyskać widok, który można dodać jako element podrzędny do strony.
Ten strumień nie jest wysyłany do innych uczestników; jest to lokalny kanał informacyjny w wersji zapoznawczej.
// To start viewing local camera preview
const cameras = await deviceManager.getCameras();
const camera = cameras[0];
const localVideoStream = new LocalVideoStream(camera);
const videoStreamRenderer = new VideoStreamRenderer(localVideoStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);
Zatrzymywanie lokalnej wersji zapoznawczej
Aby zatrzymać lokalne wywołanie podglądu, należy usunąć widok pochodzący z elementu VideoStreamRenderer
.
Po usunięciu elementu VideoStreamRenderer usuń widok z drzewa HTML, wywołując removeChild()
metodę z węzła DOM zawierającego podgląd.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Żądanie uprawnień do aparatu i mikrofonu
Aplikacja nie może używać aparatu ani mikrofonu bez uprawnień. Możesz użyć menedżera urządzeń, aby monitować użytkownika o udzielenie uprawnień aparatu i/lub mikrofonu:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
Po rozwiązaniu obietnicy metoda zwraca obiekt, DeviceAccess
który wskazuje, czy audio
udzielono uprawnień i video
uprawnień:
console.log(result.audio);
console.log(result.video);
Uwagi
videoDevicesUpdated
zdarzenie jest uruchamiane, gdy urządzenia wideo są podłączone/odłączone.audioDevicesUpdated
zdarzenie jest uruchamiane, gdy urządzenia audio są podłączone.- Po utworzeniu menedżera urządzeń na początku nie wiadomo o żadnych urządzeniach, jeśli nie udzielono jeszcze uprawnień, więc początkowo jego nazwa urządzenia jest pusta i nie zawiera szczegółowych informacji o urządzeniu. Jeśli następnie wywołamy interfejs API DeviceManager.askPermission(), użytkownik zostanie poproszony o dostęp do urządzenia. Gdy użytkownik wybierze opcję "zezwalaj", aby udzielić dostępu menedżerowi urządzeń dowiesz się o urządzeniach w systemie, zaktualizuj je na listach urządzeń i emituje zdarzenia "audioDevicesUpdated" i "videoDevicesUpdated". Jeśli użytkownik odświeży stronę i utworzy menedżera urządzeń, menedżer urządzeń będzie mógł dowiedzieć się więcej o urządzeniach, ponieważ użytkownik udzielił wcześniej dostępu. Ma wypełnione początkowo listy urządzeń i nie emituje zdarzeń "audioDevicesUpdated" ani "videoDevicesUpdated".
- Wyliczenie/wybór osoby mówiącej nie jest obsługiwane w przeglądarce Android Chrome, iOS Safari ani macOS Safari.
Umieszczanie połączenia za pomocą kamery wideo
Ważne
Obecnie obsługiwany jest tylko jeden wychodzący lokalny strumień wideo.
Aby umieścić wywołanie wideo, należy wyliczyć lokalne kamery przy użyciu getCameras()
metody w deviceManager
pliku .
Po wybraniu aparatu użyj go do utworzenia LocalVideoStream
wystąpienia.
Przekaż go jako videoOptions
element w tablicy localVideoStream
do CallAgent
startCall
metody .
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
const placeCallOptions = {videoOptions: {localVideoStreams:[localVideoStream]}};
const userCallee = { communicationUserId: '<ACS_USER_ID>' }
const call = callAgent.startCall([userCallee], placeCallOptions);
- Możesz również dołączyć połączenie za pomocą wideo za pomocą
CallAgent.join()
interfejsu API i zaakceptować i wywołać za pomocą wideo za pomocąCall.Accept()
interfejsu API. - Po nawiązaniu połączenia następuje automatyczne wysłanie strumienia wideo z wybranego aparatu do innego uczestnika.
Uruchamianie i zatrzymywanie wysyłania lokalnego wideo podczas rozmowy
Rozpocznij wideo
Aby rozpocząć wideo podczas wywołania, należy wyliczyć kamery przy użyciu getCameras
metody na deviceManager
obiekcie .
Następnie utwórz nowe wystąpienie LocalVideoStream
obiektu z żądanym aparatem, a następnie przekaż LocalVideoStream
obiekt do startVideo
metody istniejącego obiektu wywołania:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Zatrzymaj wideo
Po pomyślnym rozpoczęciu wysyłania wideo LocalVideoStream
wystąpienie typu Video
zostanie dodane do localVideoStreams
kolekcji w wystąpieniu wywołania.
Znajdowanie strumienia wideo w obiekcie Call
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );
Zatrzymaj lokalne wideo Aby zatrzymać lokalne wideo podczas wywołania, przekaż localVideoStream
wystąpienie używane do wideo do metody stopVideo metody Call
:
await call.stopVideo(localVideoStream);
Możesz przełączyć się do innego urządzenia z kamerą, używając aktywnego elementu LocalVideoStream, wywołując switchSource
to LocalVideoStream
wystąpienie:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Jeśli określone urządzenie wideo nie jest dostępne:
- Podczas wywołania, jeśli wideo jest wyłączone i rozpoczynasz wideo przy użyciu
call.startVideo()
metody , ta metoda zgłasza, że diagnostyka skierowana przezSourceUnavailableError
cameraStartFailed
użytkownika jest ustawiona na wartość true. - Wywołanie
localVideoStream.switchSource()
metody powodujecameraStartFailed
ustawienie wartości true. Nasz przewodnik diagnostyki połączeń zawiera dodatkowe informacje na temat diagnozowania problemów związanych z wywołaniem.
Aby sprawdzić, czy lokalne wideo jest włączone lub wyłączone, możesz użyć Call
metody isLocalVideoStarted
, która zwraca wartość true lub false:
// Check if local video is on or off
call.isLocalVideoStarted;
Aby nasłuchiwać zmian w lokalnym filmie wideo, możesz subskrybować i anulować subskrypcję zdarzenia isLocalVideoStartedChanged:
// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
// Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
// Callback();
});
Uruchamianie i zatrzymywanie udostępniania ekranu podczas rozmowy
Aby uruchomić udostępnianie ekranu podczas wywołania, możesz użyć metody startScreenSharing()
asynchronicznej w Call
obiekcie:
Udostępnianie ekranu startowego
// Start screen sharing
await call.startScreenSharing();
Uwaga: wysyłanie udziału ekranu jest obsługiwane tylko w przeglądarce klasycznej.
Znajdź udostępnianie ekranu w kolekcji LocalVideoStream
Po pomyślnym rozpoczęciu wysyłania udostępniania LocalVideoStream
ekranu wystąpienie typu ScreenSharing
jest dodawane do localVideoStreams
kolekcji w wystąpieniu wywołania.
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );
Zatrzymywanie udostępniania ekranu
Aby zatrzymać udostępnianie ekranu podczas wywołania, możesz użyć asynchronicznego interfejsu API stoptScreenSharing:
// Stop screen sharing
await call.stopScreenSharing();
Sprawdzanie stanu udostępniania ekranu
Aby sprawdzić, czy udostępnianie ekranu jest włączone lub wyłączone, możesz użyć interfejsu API isScreenSharingOn, który zwraca wartość true lub false:
// Check if screen sharing is on or off
call.isScreenSharingOn;
Aby nasłuchiwać zmian w udziale ekranu, możesz subskrybować i anulować subskrypcję zdarzenia isScreenSharingOnChanged:
// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
// Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
// Callback();
});
Ważne
Ta funkcja usług Azure Communication Services jest obecnie dostępna w wersji zapoznawczej.
Interfejsy API i zestawy SDK w wersji zapoznawczej są udostępniane bez umowy dotyczącej poziomu usług. Zalecamy, aby nie używać ich w przypadku obciążeń produkcyjnych. Niektóre funkcje mogą nie być obsługiwane lub mogą mieć ograniczone możliwości.
Aby uzyskać więcej informacji, zapoznaj się z dodatkowymi warunkami użytkowania dla wersji zapoznawczych platformy Microsoft Azure.
Podgląd lokalnego udziału ekranu jest dostępny w publicznej wersji zapoznawczej i jest dostępny w wersji 1.15.1-beta.1 lub nowszej.
Podgląd udziału ekranu lokalnego
Możesz użyć elementu , VideoStreamRenderer
aby rozpocząć renderowanie strumieni z udziału lokalnego ekranu, aby zobaczyć, co wysyłasz jako strumień udostępniania ekranu.
// To start viewing local screen share preview
await call.startScreenSharing();
const localScreenSharingStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing' });
const videoStreamRenderer = new VideoStreamRenderer(localScreenSharingStream);
const view = await videoStreamRenderer.createView();
htmlElement.appendChild(view.target);
// To stop viewing local screen share preview.
await call.stopScreenSharing();
view.dispose();
htmlElement.removeChild(view.target);
// Screen sharing can also be stoped by clicking on the native browser's "Stop sharing" button.
// The isScreenSharingOnChanged event will be triggered where you can check the value of call.isScreenSharingOn.
// If the value is false, then that means screen sharing is turned off and so we can go ahead and dispose the screen share preview.
// This event is also triggered for the case when stopping screen sharing via Call.stopScreenSharing() API.
call.on('isScreenSharingOnChanged', () => {
if (!call.isScreenSharingOn) {
view.dispose();
htmlElement.removeChild(view.target);
}
});
Renderowanie strumieni wideo/udostępniania ekranu uczestnika zdalnego
Aby renderować wideo lub udostępnianie ekranu uczestnika zdalnego, pierwszym krokiem jest uzyskanie odwołania do elementu RemoteVideoStream, który chcesz renderować.
Można to zrobić, przechodząc przez tablicę lub strumień wideo (videoStreams
) obiektu RemoteParticipant
. Dostęp do kolekcji uczestników zdalnych jest uzyskiwany za pośrednictwem Call
obiektu .
const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;
Aby renderować RemoteVideoStream
plik , musisz subskrybować jego isAvailableChanged
zdarzenie. isAvailable
Jeśli właściwość zmieni się na true
, uczestnik zdalny wysyła strumień wideo.
Następnie utwórz nowe wystąpienie VideoStreamRenderer
klasy , a następnie utwórz nowe VideoStreamRendererView
wystąpienie przy użyciu metody asynchronicznej createView
.
Następnie możesz dołączyć view.target
do dowolnego elementu interfejsu użytkownika.
Za każdym razem, gdy dostępność strumienia zdalnego ulegnie zmianie, możesz zniszczyć całość VideoStreamRenderer
lub określony VideoStreamRendererView
element .
Jeśli zdecydujesz się je zachować, w widoku zostanie wyświetlona pusta ramka wideo.
// Reference to the html's div where we would display a grid of all remote video stream from all participants.
let remoteVideosGallery = document.getElementById('remoteVideosGallery');
subscribeToRemoteVideoStream = async (remoteVideoStream) => {
let renderer = new VideoStreamRenderer(remoteVideoStream);
let view;
let remoteVideoContainer = document.createElement('div');
remoteVideoContainer.className = 'remote-video-container';
let loadingSpinner = document.createElement('div');
// See the css example below for styling the loading spinner.
loadingSpinner.className = 'loading-spinner';
remoteVideoStream.on('isReceivingChanged', () => {
try {
if (remoteVideoStream.isAvailable) {
const isReceiving = remoteVideoStream.isReceiving;
const isLoadingSpinnerActive = remoteVideoContainer.contains(loadingSpinner);
if (!isReceiving && !isLoadingSpinnerActive) {
remoteVideoContainer.appendChild(loadingSpinner);
} else if (isReceiving && isLoadingSpinnerActive) {
remoteVideoContainer.removeChild(loadingSpinner);
}
}
} catch (e) {
console.error(e);
}
});
const createView = async () => {
// Create a renderer view for the remote video stream.
view = await renderer.createView();
// Attach the renderer view to the UI.
remoteVideoContainer.appendChild(view.target);
remoteVideosGallery.appendChild(remoteVideoContainer);
}
// Remote participant has switched video on/off
remoteVideoStream.on('isAvailableChanged', async () => {
try {
if (remoteVideoStream.isAvailable) {
await createView();
} else {
view.dispose();
remoteVideosGallery.removeChild(remoteVideoContainer);
}
} catch (e) {
console.error(e);
}
});
// Remote participant has video on initially.
if (remoteVideoStream.isAvailable) {
try {
await createView();
} catch (e) {
console.error(e);
}
}
console.log(`Initial stream size: height: ${remoteVideoStream.size.height}, width: ${remoteVideoStream.size.width}`);
remoteVideoStream.on('sizeChanged', () => {
console.log(`Remote video stream size changed: new height: ${remoteVideoStream.size.height}, new width: ${remoteVideoStream.size.width}`);
});
}
ARKUSZ CSS do stylów spinner ładowania na zdalnym strumieniu wideo.
.remote-video-container {
position: relative;
}
.loading-spinner {
border: 12px solid #f3f3f3;
border-radius: 50%;
border-top: 12px solid #ca5010;
width: 100px;
height: 100px;
-webkit-animation: spin 2s linear infinite; /* Safari */
animation: spin 2s linear infinite;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
transform: translate(-50%, -50%);
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
Zdalna jakość wideo
Zestaw SDK webJS usług Azure Communication Services udostępnia funkcję o nazwie Optimal Video Count (OVC), począwszy od wersji 1.15.1.
Ta funkcja może służyć do informowania aplikacji w czasie wykonywania o tym, ile przychodzących filmów wideo od różnych uczestników może być optymalnie renderowanych w danym momencie w wywołaniu grupy (2+ uczestnicy).
Ta funkcja uwidacznia właściwość optimalVideoCount
, która dynamicznie zmienia się podczas wywołania na podstawie możliwości sieci i sprzętu lokalnego punktu końcowego. Wartość optimalVideoCount
szczegółów, ile filmów wideo z innej aplikacji uczestnika powinno być renderowanych w danym momencie. Aplikacje powinny obsługiwać te zmiany i aktualizować liczbę renderowanych filmów wideo odpowiednio do zalecenia. Między poszczególnymi aktualizacjami występuje okres odrzucenia (około 10 s).
Użycie Funkcja optimalVideoCount
jest funkcją wywołania. Należy odwołać się do funkcji OptimalVideoCount
za pomocą feature
metody Call
obiektu. Następnie można ustawić odbiornik za pomocą on
metody OptimalVideoCountCallFeature
, aby otrzymywać powiadomienia po zmianie parametru optimalVideoCount. Aby anulować subskrypcję zmian, możesz wywołać metodę off
. Bieżąca maksymalna liczba przychodzących filmów wideo , które można renderować, wynosi 16. Aby prawidłowo obsługiwać 16 przychodzących filmów wideo, komputer powinien mieć mimimum 16 GB pamięci RAM i 4-rdzeniowy lub większy procesor, który nie jest starszy niż 3 lata.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Przykładowe użycie: aplikacja powinna subskrybować zmiany optymalnej liczby wideo w wywołaniach grupowych. Zmiana optymalnej liczby wideo może być obsługiwana przez utworzenie nowego modułu renderowania (createView
metody) lub usuwanie widoków (dispose
) i odpowiednio zaktualizowanie układu aplikacji.
Właściwości zdalnego strumienia wideo
Zdalne strumienie wideo mają następujące właściwości:
const id: number = remoteVideoStream.id;
id
: identyfikator zdalnego strumienia wideo.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
mediaStreamType
: może mieć wartośćVideo
lubScreenSharing
.
const isAvailable: boolean = remoteVideoStream.isAvailable;
isAvailable
: określa, czy punkt końcowy uczestnika zdalnego aktywnie wysyła strumień.
const isReceiving: boolean = remoteVideoStream.isReceiving;
isReceiving
:Informuje aplikację o odebraniu lub braku zdalnych danych strumienia wideo.
Flaga zostanie przeniesiona do
false
w następujących scenariuszach:- Zdalny uczestnik, który jest w przeglądarce mobilnej, przenosi aplikację przeglądarki w tle.
- Uczestnik zdalny lub użytkownik odbierający wideo ma problem z siecią, który znacząco wpływa na jakość wideo.
- Zdalny uczestnik, który jest w systemie macOS/iOS Safari, wybiera pozycję "Wstrzymaj" na pasku adresu.
- Uczestnik zdalny ma rozłączenie sieci.
- Zdalny uczestnik na urządzeniach przenośnych zabija lub kończy przeglądarkę.
- Uczestnik zdalny na urządzeniach przenośnych lub stacjonarnych blokuje swoje urządzenie. Ten scenariusz ma zastosowanie również wtedy, gdy uczestnik zdalny znajduje się na komputerze stacjonarnym i przejdzie w tryb uśpienia.
Flaga zostanie przeniesiona do
true
w następujących scenariuszach:- Zdalny uczestnik, który jest w przeglądarce mobilnej i ma w tle przeglądarkę, przywraca go na pierwszym planie.
- Zdalny uczestnik, który jest w systemie macOS/iOS Safari wybiera pozycję "Wznów" na pasku adresu po wstrzymaniu filmu wideo.
- Uczestnik zdalny ponownie łączy się z siecią po tymczasowym rozłączeniu.
- Uczestnik zdalny na urządzeniu przenośnym odblokuj swoje urządzenie i wróć do wywołania w przeglądarce mobilnej.
Ta funkcja usprawnia środowisko użytkownika do renderowania zdalnych strumieni wideo.
Podczas odbierania flagi na fałsz można wyświetlić pokrętło ładowania na zdalnym strumieniu wideo. Nie musisz implementować spinneru ładowania, ale spinner ładowania jest najczęstszym użyciem w celu uzyskania lepszego środowiska użytkownika.
const size: StreamSize = remoteVideoStream.size;
size
: rozmiar strumienia z informacjami o szerokości i wysokości filmu wideo.
Metody i właściwości usługi VideoStreamRenderer
await videoStreamRenderer.createView();
VideoStreamRendererView
Utwórz wystąpienie, które można dołączyć w interfejsie użytkownika aplikacji, aby renderować zdalny strumień wideo, użyć metody asynchronicznejcreateView()
, rozpoznaje, gdy strumień jest gotowy do renderowania i zwraca obiekt z właściwością reprezentującą target
video
element, który można wstawić w dowolnym miejscu w drzewie DOM.
videoStreamRenderer.dispose();
videoStreamRenderer
Usuwanie i wszystkie skojarzone VideoStreamRendererView
wystąpienia.
Właściwości i metody VideoStreamRendererView
Podczas tworzenia obiektu VideoStreamRendererView
można określić scalingMode
właściwości i isMirrored
. scalingMode
może to być Stretch
, Crop
lub Fit
. Jeśli isMirrored
zostanie określony, renderowany strumień jest przerzucany w pionie.
const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });
Każde VideoStreamRendererView
wystąpienie ma właściwość reprezentującą target
powierzchnię renderowania. Dołącz tę właściwość w interfejsie użytkownika aplikacji:
htmlElement.appendChild(view.target);
Możesz zaktualizować scalingMode
, wywołując metodę updateScalingMode
:
view.updateScalingMode('Crop');
Wysyłaj strumienie wideo z dwóch różnych kamer w tym samym wywołaniu z tego samego urządzenia stacjonarnego.
Ważne
Ta funkcja usług Azure Communication Services jest obecnie dostępna w wersji zapoznawczej.
Interfejsy API i zestawy SDK w wersji zapoznawczej są udostępniane bez umowy dotyczącej poziomu usług. Zalecamy, aby nie używać ich w przypadku obciążeń produkcyjnych. Niektóre funkcje mogą nie być obsługiwane lub mogą mieć ograniczone możliwości.
Aby uzyskać więcej informacji, zapoznaj się z dodatkowymi warunkami użytkowania dla wersji zapoznawczych platformy Microsoft Azure.
Wysyłanie strumieni wideo z dwóch różnych aparatów w tym samym wywołaniu jest obsługiwane w ramach wersji 1.17.1-beta.1 lub nowszej w przeglądarkach obsługiwanych przez komputery.
- Strumienie wideo można wysyłać z dwóch różnych kamer z jednej karty/aplikacji przeglądarki klasycznej, w tym samym wywołaniu, przy użyciu następującego fragmentu kodu:
// Create your first CallAgent with identity A
const callClient1 = new CallClient();
const callAgent1 = await callClient1.createCallAgent(tokenCredentialA);
const deviceManager1 = await callClient1.getDeviceManager();
// Create your second CallAgent with identity B
const callClient2 = new CallClient();
const callAgent2 = await callClient2.createCallAgent(tokenCredentialB);
const deviceManager2 = await callClient2.getDeviceManager();
// Join the call with your first CallAgent
const camera1 = await deviceManager1.getCameras()[0];
const callObj1 = callAgent1.join({ groupId: ‘123’}, { videoOptions: { localVideoStreams: [new LocalVideoStream(camera1)] } });
// Join the same call with your second CallAgent and make it use a different camera
const camera2 = (await deviceManager2.getCameras()).filter((camera) => { return camera !== camera1 })[0];
const callObj2 = callAgent2.join({ groupId: '123' }, { videoOptions: { localVideoStreams: [new LocalVideoStream(camera2)] } });
//Mute the microphone and speakers of your second CallAgent’s Call, so that there is no echos/noises.
await callObj2.muteIncomingAudio();
await callObj2.mute();
Ograniczenia:
- Należy to zrobić z dwoma różnymi
CallAgent
wystąpieniami przy użyciu różnych tożsamości. Fragment kodu przedstawia dwóch używanych agentów wywołań, z których każdy ma własny obiekt Call. - W przykładzie kodu oba elementy CallAgent dołączają do tego samego wywołania (te same identyfikatory wywołań). Możesz również dołączyć różne połączenia z każdym agentem i wysłać jeden film wideo w jednym wywołaniu i inny film wideo w drugim połączeniu.
- Wysyłanie tego samego aparatu w obu wywołaniach nie jest obsługiwane. Muszą być dwoma różnymi kamerami.
- Wysyłanie dwóch różnych aparatów z jedną funkcją CallAgent nie jest obecnie obsługiwane.
- W przeglądarce Safari w systemie macOS efekty wideo rozmycia tła (z @azure/communication-effects)programu można zastosować tylko do jednego aparatu, a nie obu w tym samym czasie.
Instalacja zestawu SDK
Znajdź plik na poziomie build.gradle
projektu i dodaj mavenCentral()
go do listy repozytoriów w obszarze buildscript
i allprojects
:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Następnie w pliku na poziomie build.gradle
modułu dependencies
dodaj następujące wiersze do sekcji:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Inicjowanie wymaganych obiektów
Aby utworzyć CallAgent
wystąpienie, należy wywołać createCallAgent
metodę w wystąpieniu CallClient
. To wywołanie asynchroniczne zwraca CallAgent
obiekt wystąpienia.
Metoda createCallAgent
przyjmuje CommunicationUserCredential
jako argument, który hermetyzuje token dostępu.
Aby uzyskać dostęp, DeviceManager
należy najpierw utworzyć callAgent
wystąpienie. Następnie możesz użyć metody , aby pobrać metodę 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();
Aby ustawić nazwę wyświetlaną elementu wywołującego, użyj tej alternatywnej metody:
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();
Zarządzanie urządzeniami
Aby rozpocząć korzystanie z wideo z funkcją Wywoływanie, musisz wiedzieć, jak zarządzać urządzeniami. Urządzenia umożliwiają sterowanie tym, co przesyła dźwięk i wideo do wywołania.
DeviceManager
Umożliwia wyliczanie urządzeń lokalnych, które mogą być używane w wywołaniu do przesyłania strumieni audio/wideo. Umożliwia również zażądanie uprawnień od użytkownika w celu uzyskania dostępu do mikrofonu i aparatu przy użyciu natywnego interfejsu API przeglądarki.
Dostęp można uzyskać deviceManager
, wywołując callClient.getDeviceManager()
metodę .
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Wyliczanie urządzeń lokalnych
Aby uzyskać dostęp do urządzeń lokalnych, możesz użyć metod wyliczania w Menedżer urządzeń. Wyliczenie jest akcją synchroniczną.
// Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
Podgląd aparatu lokalnego
Możesz użyć funkcji DeviceManager
i Renderer
, aby rozpocząć renderowanie strumieni z aparatu lokalnego. Ten strumień nie zostanie wysłany do innych uczestników; jest to lokalny kanał informacyjny w wersji zapoznawczej. Jest to akcja asynchroniczna.
VideoDeviceInfo videoDevice = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();
LocalVideoStream currentVideoStream = new LocalVideoStream(videoDevice, appContext);
LocalVideoStream[] localVideoStreams = new LocalVideoStream[1];
localVideoStreams[0] = currentVideoStream;
VideoOptions videoOptions = new VideoOptions(localVideoStreams);
RenderingOptions renderingOptions = new RenderingOptions(ScalingMode.Fit);
VideoStreamRenderer previewRenderer = new VideoStreamRenderer(currentVideoStream, appContext);
VideoStreamRendererView uiView = previewRenderer.createView(renderingOptions);
// Attach the uiView to a viewable location on the app at this point
layout.addView(uiView);
Umieść połączenie 1:1 za pomocą kamery wideo
Ostrzeżenie
Obecnie obsługiwany jest tylko jeden wychodzący lokalny strumień wideo Aby umieścić połączenie z wideo, musisz wyliczyć lokalne kamery przy użyciu interfejsu deviceManager
getCameras
API.
Po wybraniu żądanego aparatu użyj go, aby skonstruować LocalVideoStream
wystąpienie i przekazać je jako videoOptions
element w localVideoStream
tablicy do call
metody.
Po nawiązaniu połączenia automatycznie rozpocznie wysyłanie strumienia wideo z wybranego aparatu do innych uczestników.
Uwaga
Ze względu na obawy dotyczące prywatności klip wideo nie zostanie udostępniony wywołaniu, jeśli nie jest on w wersji zapoznawczej lokalnie. Aby uzyskać więcej szczegółów, zobacz Podgląd aparatu lokalnego.
VideoDeviceInfo desiredCamera = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();
LocalVideoStream currentVideoStream = new LocalVideoStream(desiredCamera, appContext);
LocalVideoStream[] localVideoStreams = new LocalVideoStream[1];
localVideoStreams[0] = currentVideoStream;
VideoOptions videoOptions = new VideoOptions(localVideoStreams);
// Render a local preview of video so the user knows that their video is being shared
Renderer previewRenderer = new VideoStreamRenderer(currentVideoStream, appContext);
View uiView = previewRenderer.createView(new CreateViewOptions(ScalingMode.FIT));
// Attach the uiView to a viewable location on the app at this point
layout.addView(uiView);
CommunicationUserIdentifier[] participants = new CommunicationUserIdentifier[]{ new CommunicationUserIdentifier("<acs user id>") };
StartCallOptions startCallOptions = new StartCallOptions();
startCallOptions.setVideoOptions(videoOptions);
Call call = callAgent.startCall(context, participants, startCallOptions);
Uruchamianie i zatrzymywanie wysyłania lokalnego wideo
Aby rozpocząć film wideo, musisz wyliczyć kamery przy użyciu interfejsu getCameraList
API w deviceManager
obiekcie. Następnie utwórz nowe wystąpienie przekazywania żądanego LocalVideoStream
aparatu i przekaż je do interfejsu startVideo
API jako argument:
VideoDeviceInfo desiredCamera = <get-video-device>; // See the `Enumerate local devices` topic above
Context appContext = this.getApplicationContext();
LocalVideoStream currentLocalVideoStream = new LocalVideoStream(desiredCamera, appContext);
VideoOptions videoOptions = new VideoOptions(currentLocalVideoStream);
Future startVideoFuture = call.startVideo(appContext, currentLocalVideoStream);
startVideoFuture.get();
Po pomyślnym rozpoczęciu wysyłania wideo LocalVideoStream
wystąpienie zostanie dodane do localVideoStreams
kolekcji w wystąpieniu wywołania.
List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).
Aby zatrzymać lokalne wideo, przekaż LocalVideoStream
wystąpienie dostępne w localVideoStreams
kolekcji:
call.stopVideo(appContext, currentLocalVideoStream).get();
Możesz przełączyć się na inne urządzenie aparatu, gdy wideo jest wysyłane przez wywołanie switchSource
wystąpienia LocalVideoStream
:
currentLocalVideoStream.switchSource(source).get();
Renderowanie strumieni wideo uczestnika zdalnego
Aby wyświetlić listę strumieni wideo i strumieni udostępniania ekranu uczestników zdalnych, sprawdź videoStreams
kolekcje:
List<RemoteParticipant> remoteParticipants = call.getRemoteParticipants();
RemoteParticipant remoteParticipant = remoteParticipants.get(0); // Please make sure there are remote participants in the list before calling get(0).
List<RemoteVideoStream> remoteStreams = remoteParticipant.getVideoStreams();
RemoteVideoStream remoteParticipantStream = remoteStreams.get(0); // Please make sure there are video streams in the list before calling get(0).
MediaStreamType streamType = remoteParticipantStream.getType(); // of type MediaStreamType.Video or MediaStreamType.ScreenSharing
Aby renderować element RemoteVideoStream
od uczestnika zdalnego, musisz zasubskrybować OnVideoStreamsUpdated
wydarzenie.
W ramach zdarzenia zmiana isAvailable
właściwości na true wskazuje, że uczestnik zdalny wysyła obecnie strumień. Gdy tak się stanie, utwórz nowe wystąpienie Renderer
klasy , a następnie utwórz nowe RendererView
przy użyciu asynchronicznego createView
interfejsu API i dołącz go view.target
w dowolnym miejscu w interfejsie użytkownika aplikacji.
Za każdym razem, gdy dostępność strumienia zdalnego zmieni się, możesz zniszczyć cały moduł renderujący, określone RendererView
lub zachować je, ale spowoduje to wyświetlenie pustej ramki wideo.
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteParticipantStream, appContext);
VideoStreamRendererView uiView = remoteVideoRenderer.createView(new RenderingOptions(ScalingMode.FIT));
layout.addView(uiView);
remoteParticipant.addOnVideoStreamsUpdatedListener(e -> onRemoteParticipantVideoStreamsUpdated(p, e));
void onRemoteParticipantVideoStreamsUpdated(RemoteParticipant participant, RemoteVideoStreamsEvent args) {
for(RemoteVideoStream stream : args.getAddedRemoteVideoStreams()) {
if(stream.getIsAvailable()) {
startRenderingVideo();
} else {
renderer.dispose();
}
}
}
Właściwości zdalnego strumienia wideo
Zdalny strumień wideo ma kilka właściwości
Id
- Identyfikator zdalnego strumienia wideo
int id = remoteVideoStream.getId();
MediaStreamType
- Może to być "Wideo" lub "ScreenSharing"
MediaStreamType type = remoteVideoStream.getMediaStreamType();
isAvailable
— Wskazuje, czy punkt końcowy uczestnika zdalnego aktywnie wysyła strumień
boolean availability = remoteVideoStream.isAvailable();
Metody i właściwości modułu renderowania
Obiekt renderatora po interfejsach API
VideoStreamRendererView
Utwórz wystąpienie, które można później dołączyć w interfejsie użytkownika aplikacji w celu renderowania zdalnego strumienia wideo.
// Create a view for a video stream
VideoStreamRendererView.createView()
- Usuwanie modułu renderowania i wszystkich
VideoStreamRendererView
skojarzonych z tym modułem renderowania. Wywołanie wywołania po usunięciu wszystkich skojarzonych widoków z interfejsu użytkownika.
VideoStreamRenderer.dispose()
StreamSize
- rozmiar (szerokość/wysokość) zdalnego strumienia wideo
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();
Metody i właściwości elementu RendererView
Podczas tworzenia VideoStreamRendererView
obiektu można określić ScalingMode
właściwości i mirrored
, które będą stosowane do tego widoku: tryb skalowania może mieć wartość "CROP" | "FIT"
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));
Utworzony element RendererView można następnie dołączyć do interfejsu użytkownika aplikacji przy użyciu następującego fragmentu kodu:
layout.addView(rendererView);
Później możesz zaktualizować tryb skalowania, wywołując updateScalingMode
interfejs API w obiekcie RendererView za pomocą jednego z elementów ScalingMode.CROP | ScalingMode.FIT jako argument.
// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)
Konfigurowanie systemu
Wykonaj następujące kroki, aby skonfigurować system.
Tworzenie projektu Xcode
W programie Xcode utwórz nowy projekt systemu iOS i wybierz szablon Aplikacja z jednym widokiem. W tym artykule jest używana struktura SwiftUI, dlatego należy ustawić wartość Language na Swift i ustawić wartość Interface na SwiftUI.
Nie zamierzasz tworzyć testów w tym artykule. Możesz wyczyścić pole wyboru Uwzględnij testy .
Instalowanie pakietu i zależności przy użyciu narzędzia CocoaPods
Utwórz plik Podfile dla aplikacji, podobnie jak w tym przykładzie:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Uruchom program
pod install
.Otwórz
.xcworkspace
za pomocą programu Xcode.
Żądanie dostępu do mikrofonu
Aby uzyskać dostęp do mikrofonu urządzenia, należy zaktualizować listę właściwości informacji aplikacji przy użyciu polecenia NSMicrophoneUsageDescription
. Ustaw skojarzona wartość na ciąg zawarty w oknie dialogowym używanym przez system do żądania dostępu od użytkownika.
Kliknij prawym przyciskiem myszy wpis Info.plist drzewa projektu, a następnie wybierz pozycję Otwórz jako>kod źródłowy. Dodaj następujące wiersze w sekcji najwyższego poziomu <dict>
, a następnie zapisz plik.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Konfigurowanie struktury aplikacji
Otwórz plik projektu ContentView.swift
. Dodaj deklarację import
na początku pliku, aby zaimportować bibliotekę AzureCommunicationCalling
. Ponadto zaimportuj plik AVFoundation
. Potrzebne są żądania uprawnień dźwięku w kodzie.
import AzureCommunicationCalling
import AVFoundation
Inicjowanie klasy CallAgent
Aby utworzyć CallAgent
wystąpienie z CallClient
klasy , należy użyć callClient.createCallAgent
metody, która asynchronicznie zwraca CallAgent
obiekt po zainicjowaniu.
Aby utworzyć klienta wywołania, przekaż CommunicationTokenCredential
obiekt:
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
Przekaż utworzony obiekt do CallClient
, a następnie ustaw nazwę wyświetlaną:
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")
}
})
Zarządzanie urządzeniami
Aby rozpocząć korzystanie z wideo z funkcją Wywoływanie, musisz wiedzieć, jak zarządzać urządzeniami. Urządzenia umożliwiają sterowanie tym, co przesyła dźwięk i wideo do wywołania.
DeviceManager
Umożliwia wyliczanie urządzeń lokalnych, które mogą być używane w wywołaniu do przesyłania strumieni audio lub wideo. Umożliwia również zażądanie od użytkownika uprawnień dostępu do mikrofonu lub kamery. Dostęp do obiektu można uzyskać deviceManager
callClient
.
self.callClient!.getDeviceManager { (deviceManager, error) in
if (error == nil) {
print("Got device manager instance")
self.deviceManager = deviceManager
} else {
print("Failed to get device manager instance")
}
}
Wyliczanie urządzeń lokalnych
Aby uzyskać dostęp do urządzeń lokalnych, możesz użyć metod wyliczania w Menedżerze urządzeń. Wyliczenie jest akcją synchroniczną.
// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]
Uzyskiwanie podglądu aparatu lokalnego
Możesz użyć Renderer
polecenia , aby rozpocząć renderowanie strumienia z aparatu lokalnego. Ten strumień nie zostanie wysłany do innych uczestników; jest to lokalny kanał informacyjny w wersji zapoznawczej. Jest to akcja asynchroniczna.
let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()
Pobieranie właściwości podglądu aparatu lokalnego
Program renderujący ma zestaw właściwości i metod, które umożliwiają sterowanie renderowaniem.
// Constructor can take in LocalVideoStream or RemoteVideoStream
let localRenderer = VideoStreamRenderer(localVideoStream:localVideoStream)
let remoteRenderer = VideoStreamRenderer(remoteVideoStream:remoteVideoStream)
// [StreamSize] size of the rendering view
localRenderer.size
// [VideoStreamRendererDelegate] an object you provide to receive events from this Renderer instance
localRenderer.delegate
// [Synchronous] create view
try! localRenderer.createView()
// [Synchronous] create view with rendering options
try! localRenderer!.createView(withOptions: CreateViewOptions(scalingMode: ScalingMode.fit))
// [Synchronous] dispose rendering view
localRenderer.dispose()
Umieść połączenie 1:1 za pomocą wideo
Aby uzyskać wystąpienie menedżera urządzeń, zobacz sekcję dotyczącą zarządzania urządzeniami.
let firstCamera = self.deviceManager!.cameras.first
self.localVideoStreams = [LocalVideoStream]()
self.localVideoStreams!.append(LocalVideoStream(camera: firstCamera!))
let videoOptions = VideoOptions(localVideoStreams: self.localVideoStreams!)
let startCallOptions = StartCallOptions()
startCallOptions.videoOptions = videoOptions
let callee = CommunicationUserIdentifier('UserId')
self.callAgent?.startCall(participants: [callee], options: startCallOptions) { (call, error) in
if error == nil {
print("Successfully started outgoing video call")
self.call = call
} else {
print("Failed to start outgoing video call")
}
}
Renderowanie strumieni wideo uczestnika zdalnego
Uczestnicy zdalni mogą inicjować udostępnianie wideo lub ekranu podczas rozmowy.
Obsługa udostępniania wideo lub udostępniania ekranu strumieni zdalnych uczestników
Aby wyświetlić listę strumieni uczestników zdalnych, sprawdź videoStreams
kolekcje.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Pobieranie właściwości zdalnego strumienia wideo
var type: MediaStreamType = remoteParticipantVideoStream.type // 'MediaStreamTypeVideo'
var isAvailable: Bool = remoteParticipantVideoStream.isAvailable // indicates if remote stream is available
var id: Int = remoteParticipantVideoStream.id // id of remoteParticipantStream
Renderowanie strumieni uczestników zdalnych
Aby rozpocząć renderowanie strumieni uczestników zdalnych, użyj następującego kodu.
let renderer = VideoStreamRenderer(remoteVideoStream: remoteParticipantVideoStream)
let targetRemoteParticipantView = renderer?.createView(withOptions: CreateViewOptions(scalingMode: ScalingMode.crop))
// To update the scaling mode later
targetRemoteParticipantView.update(scalingMode: ScalingMode.fit)
Uzyskiwanie zdalnych metod i właściwości modułu renderowania wideo
// [Synchronous] dispose() - dispose renderer and all `RendererView` associated with this renderer. To be called when you have removed all associated views from the UI.
remoteVideoRenderer.dispose()
Konfigurowanie systemu
Wykonaj następujące kroki, aby skonfigurować system.
Tworzenie projektu programu Visual Studio
W przypadku aplikacji platforma uniwersalna systemu Windows w programie Visual Studio 2022 utwórz nowy projekt Pusta aplikacja (uniwersalny system Windows). Po wprowadzeniu nazwy projektu możesz wybrać dowolny zestaw Windows SDK nowszy niż 10.0.17763.0.
W przypadku aplikacji WinUI 3 utwórz nowy projekt z pustą aplikacją, spakowanym szablonem (WinUI 3 w programie Desktop), aby skonfigurować jednostronicową aplikację WinUI 3. Wymagany jest zestaw Windows App SDK w wersji 1.3 lub nowszej.
Instalowanie pakietu i zależności przy użyciu Menedżer pakietów NuGet
Interfejsy API i biblioteki zestawu SDK wywołujących są publicznie dostępne za pośrednictwem pakietu NuGet.
Aby znaleźć, pobrać i zainstalować pakiet NuGet zestawu SDK wywołującego:
- Otwórz Menedżer pakietów NuGet, wybierając pozycję Narzędzia>NuGet Menedżer pakietów> Zarządzanie pakietami NuGet dla rozwiązania.
- Wybierz pozycję Przeglądaj, a następnie wprowadź ciąg Azure.Communication.Calling.WindowsClient w polu wyszukiwania.
- Upewnij się, że pole wyboru Uwzględnij wersję wstępną zostało zaznaczone.
- Wybierz pakiet Azure.Communication.Calling.WindowsClient, a następnie wybierz pozycję Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 lub nowszą wersję.
- Zaznacz pole wyboru odpowiadające projektowi usług Azure Communication Services w okienku po prawej stronie.
- Wybierz Zainstaluj.
Żądanie dostępu do mikrofonu
Aplikacja wymaga dostępu do aparatu, aby działał prawidłowo. W aplikacjach platformy UWP funkcja aparatu powinna być zadeklarowana w pliku manifestu aplikacji.
W poniższych krokach przedstawiono sposób, w jaki to osiągnąć.
Solution Explorer
Na panelu kliknij dwukrotnie plik z.appxmanifest
rozszerzeniem.- Kliknij kartę
Capabilities
. Camera
Zaznacz pole wyboru z listy możliwości.
Tworzenie przycisków interfejsu użytkownika w celu umieszczania i zawieszania się wywołania
Ta prosta przykładowa aplikacja zawiera dwa przyciski. Jeden do umieszczenia połączenia, a drugi, aby zawiesić umieszczone połączenie. W poniższych krokach przedstawiono sposób dodawania tych przycisków do aplikacji.
Solution Explorer
Na panelu kliknij dwukrotnie plik o nazwieMainPage.xaml
dla platformy UWP lubMainWindows.xaml
winUI 3.- Na panelu centralnym wyszukaj kod XAML w obszarze podglądu interfejsu użytkownika.
- Zmodyfikuj kod XAML, korzystając z następującego fragmentu:
<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>
Konfigurowanie aplikacji przy użyciu wywoływanych interfejsów API zestawu SDK
Interfejsy API wywołującego zestawu SDK znajdują się w dwóch różnych przestrzeniach nazw. Poniższe kroki informują kompilator języka C# o tych przestrzeniach nazw, dzięki czemu funkcja IntelliSense programu Visual Studio może pomóc w tworzeniu kodu.
Solution Explorer
W panelu kliknij strzałkę po lewej stronie pliku o nazwieMainPage.xaml
dla platformy UWP lubMainWindows.xaml
winUI 3.- Kliknij dwukrotnie plik o nazwie
MainPage.xaml.cs
lubMainWindows.xaml.cs
. - Dodaj następujące polecenia w dolnej części bieżących
using
instrukcji.
using Azure.Communication.Calling.WindowsClient;
Zachowaj MainPage.xaml.cs
lub MainWindows.xaml.cs
otwórz. Następne kroki spowodują dodanie do niego większej liczby kodu.
Zezwalaj na interakcje aplikacji
Przyciski interfejsu użytkownika dodane wcześniej muszą działać na górze umieszczonego CommunicationCall
elementu . Oznacza to, że element członkowski CommunicationCall
danych powinien zostać dodany do MainPage
klasy lub MainWindow
.
Ponadto aby umożliwić tworzenie operacji asynchronicznej w celu pomyślnego wykonania CallAgent
, CallAgent
należy również dodać element członkowski danych do tej samej klasy.
Dodaj następujące składowe danych do MainPage
klasy or MainWindow
:
CallAgent callAgent;
CommunicationCall call;
Tworzenie procedur obsługi przycisków
Wcześniej do kodu XAML dodano dwa przyciski interfejsu użytkownika. Poniższy kod dodaje programy obsługi do wykonania po wybraniu przycisku przez użytkownika. Poniższy kod powinien zostać dodany po elementach członkowskich danych z poprzedniej sekcji.
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start call
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// End the current call
}
Model obiektów
Następujące klasy i interfejsy obsługują niektóre główne funkcje biblioteki klienta wywołujących usługi Azure Communication Services dla platformy UWP.
Nazwa/nazwisko | opis |
---|---|
CallClient |
Jest CallClient to główny punkt wejścia do biblioteki wywołującej klienta. |
CallAgent |
Element służy do uruchamiania CallAgent i dołączania wywołań. |
CommunicationCall |
Służy CommunicationCall do zarządzania umieszczonymi lub sprzężonym wywołaniami. |
CommunicationTokenCredential |
Element CommunicationTokenCredential jest używany jako poświadczenie tokenu w celu utworzenia wystąpienia elementu CallAgent . |
CallAgentOptions |
Zawiera CallAgentOptions informacje identyfikujące obiekt wywołujący. |
HangupOptions |
Informuje, HangupOptions czy połączenie powinno zostać zakończone dla wszystkich jego uczestników. |
Rejestrowanie programu obsługi schematu wideo
Składnik interfejsu użytkownika, taki jak MediaElement języka XAML lub MediaPlayerElement, potrzebuje aplikacji rejestrującej konfigurację renderowania lokalnych i zdalnych kanałów informacyjnych wideo.
Dodaj następującą zawartość między tagami Package
elementu Package.appxmanifest
:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
Inicjowanie klasy CallAgent
Aby utworzyć CallAgent
wystąpienie z CallClient
klasy , należy użyć CallClient.CreateCallAgentAsync
metody, która asynchronicznie zwraca CallAgent
obiekt po zainicjowaniu.
Aby utworzyć CallAgent
obiekt , należy przekazać CallTokenCredential
obiekt i CallAgentOptions
obiekt. Należy pamiętać, że CallTokenCredential
zgłasza błąd w przypadku przekazania źle sformułowanego tokenu.
Poniższy kod powinien zostać dodany wewnątrz funkcji pomocnika i wywoływany w inicjalizacji aplikacji.
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);
this.callAgent.CallsUpdated += Agent_OnCallsUpdatedAsync;
this.callAgent.IncomingCallReceived += Agent_OnIncomingCallAsync;
Zmień element <AUTHENTICATION_TOKEN>
przy użyciu prawidłowego tokenu poświadczeń dla zasobu. Jeśli token poświadczeń musi być źródłowy, zapoznaj się z dokumentacją tokenu dostępu użytkownika.
Umieść połączenie 1:1 za pomocą kamery wideo
Obiekty potrzebne do utworzenia obiektu CallAgent
są teraz gotowe. Nadszedł czas, aby asynchronicznie utworzyć i umieścić CallAgent
połączenie wideo.
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
var callString = CalleeTextBox.Text.Trim();
if (!string.IsNullOrEmpty(callString))
{
if (callString.StartsWith("8:")) // 1:1 Azure Communication Services call
{
this.call = await StartAcsCallAsync(callString);
}
}
if (this.call != null)
{
this.call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
this.call.StateChanged += OnStateChangedAsync;
}
}
private async Task<CommunicationCall> StartAcsCallAsync(string acsCallee)
{
var options = await GetStartCallOptionsAsynnc();
var call = await this.callAgent.StartCallAsync( new [] { new UserCallIdentifier(acsCallee) }, options);
return call;
}
var micStream = new LocalOutgoingAudioStream(); // Create a default local audio stream
var cameraStream = new LocalOutgoingVideoStreamde(this.viceManager.Cameras.FirstOrDefault() as VideoDeviceDetails); // Create a default video stream
private async Task<StartCallOptions> GetStartCallOptionsAsynnc()
{
return new StartCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsMuted = true, Stream = micStream },
OutgoingVideoOptions = new OutgoingVideoOptions() { Streams = new OutgoingVideoStream[] { cameraStream } }
};
}
Podgląd aparatu lokalnego
Opcjonalnie można skonfigurować podgląd aparatu lokalnego. Wideo można renderować za pomocą programu MediaPlayerElement
:
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
Aby zainicjować lokalną wersję zapoznawcza MediaPlayerElement
:
private async void CameraList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (cameraStream != null)
{
await cameraStream?.StopPreviewAsync();
if (this.call != null)
{
await this.call?.StopVideoAsync(cameraStream);
}
}
var selectedCamerea = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamerea);
var localUri = await cameraStream.StartPreviewAsync();
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
if (this.call != null) {
await this.call?.StartVideoAsync(cameraStream);
}
}
Renderowanie strumienia zdalnego aparatu
Skonfiguruj nawet program obsługi w odpowiedzi na OnCallsUpdated
zdarzenie:
private async void OnCallsUpdatedAsync(object sender, CallsUpdatedEventArgs args)
{
var removedParticipants = new List<RemoteParticipant>();
var addedParticipants = new List<RemoteParticipant>();
foreach(var call in args.RemovedCalls)
{
removedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
}
foreach (var call in args.AddedCalls)
{
addedParticipants.AddRange(call.RemoteParticipants.ToList<RemoteParticipant>());
}
await OnParticipantChangedAsync(removedParticipants, addedParticipants);
}
private async void OnRemoteParticipantsUpdatedAsync(object sender, ParticipantsUpdatedEventArgs args)
{
await OnParticipantChangedAsync(
args.RemovedParticipants.ToList<RemoteParticipant>(),
args.AddedParticipants.ToList<RemoteParticipant>());
}
private async Task OnParticipantChangedAsync(IEnumerable<RemoteParticipant> removedParticipants, IEnumerable<RemoteParticipant> addedParticipants)
{
foreach (var participant in removedParticipants)
{
foreach(var incomingVideoStream in participant.IncomingVideoStreams)
{
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
if (remoteVideoStream != null)
{
await remoteVideoStream.StopPreviewAsync();
}
}
participant.VideoStreamStateChanged -= OnVideoStreamStateChanged;
}
foreach (var participant in addedParticipants)
{
participant.VideoStreamStateChanged += OnVideoStreamStateChanged;
}
}
private void OnVideoStreamStateChanged(object sender, VideoStreamStateChangedEventArgs e)
{
CallVideoStream callVideoStream = e.CallVideoStream;
switch (callVideoStream.StreamDirection)
{
case StreamDirection.Outgoing:
OnOutgoingVideoStreamStateChanged(callVideoStream as OutgoingVideoStream);
break;
case StreamDirection.Incoming:
OnIncomingVideoStreamStateChanged(callVideoStream as IncomingVideoStream);
break;
}
}
Uruchom renderowanie zdalnego strumienia wideo w usłudze MediaPlayerElement
:
private async void OnIncomingVideoStreamStateChanged(IncomingVideoStream incomingVideoStream)
{
switch (incomingVideoStream.State)
{
case VideoStreamState.Available:
{
switch (incomingVideoStream.Kind)
{
case VideoStreamKind.RemoteIncoming:
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
var uri = await remoteVideoStream.StartPreviewAsync();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
RemoteVideo.Source = MediaSource.CreateFromUri(uri);
});
/* Or WinUI 3
this.DispatcherQueue.TryEnqueue(() => {
RemoteVideo.Source = MediaSource.CreateFromUri(uri);
RemoteVideo.MediaPlayer.Play();
});
*/
break;
case VideoStreamKind.RawIncoming:
break;
}
break;
}
case VideoStreamState.Started:
break;
case VideoStreamState.Stopping:
break;
case VideoStreamState.Stopped:
if (incomingVideoStream.Kind == VideoStreamKind.RemoteIncoming)
{
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
await remoteVideoStream.StopPreviewAsync();
}
break;
case VideoStreamState.NotAvailable:
break;
}
}
Kończ połączenie
Po umieszczeniu HangupAsync
wywołania należy użyć metody CommunicationCall
obiektu w celu zawieszenia wywołania.
Należy również użyć wystąpienia HangupOptions
, aby poinformować, czy połączenie musi zostać zakończone dla wszystkich jego uczestników.
W pliku HangupButton_Click
należy dodać następujący kod.
var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
foreach (var localVideoStream in call.OutgoingVideoStreams)
{
await call.StopVideoAsync(localVideoStream);
}
try
{
if (cameraStream != null)
{
await cameraStream.StopPreviewAsync();
}
await call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
}
catch(Exception ex)
{
var errorCode = unchecked((int)(0x0000FFFFU & ex.HResult));
if (errorCode != 98) // Sample error code, sam_status_failed_to_hangup_for_everyone (98)
{
throw;
}
}
}
}
Uruchamianie kodu
Upewnij się, że program Visual Studio skompiluje aplikację dla x64
x86
, lub ARM64
, a następnie naciśnij polecenie F5
, aby rozpocząć uruchamianie aplikacji. Następnie kliknij CommunicationCall
przycisk, aby umieścić wywołanie do zdefiniowanej metody wywoływanej.
Pamiętaj, że przy pierwszym uruchomieniu aplikacji system monituje użytkownika o udzielenie dostępu do mikrofonu.