Správa videa během hovorů
Zjistěte, jak spravovat videohovory pomocí sady SDK služby Azure Communication Services. Dozvíte se, jak spravovat příjem a odesílání videa během hovoru.
Požadavky
- Účet Azure s aktivním předplatným. Vytvoření účtu zdarma
- Nasazený prostředek komunikační služby. Vytvořte prostředek komunikační služby.
- Přístupový token uživatele pro povolení volajícího klienta. Další informace najdete v tématu Vytváření a správa přístupových tokenů.
- Volitelné: Dokončením rychlého startu přidáte do aplikace hlasové hovory.
Nainstalujte sadu SDK .
npm install
Pomocí příkazu nainstalujte sadu AZURE Communication Services Common and Calling SDK pro JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Inicializace požadovaných objektů
Pro CallClient
většinu operací volání se vyžaduje instance. Když vytvoříte novou CallClient
instanci, můžete ji nakonfigurovat s vlastními možnostmi, jako je Logger
instance.
CallClient
S instancí můžete vytvořit CallAgent
instanci voláním createCallAgent
. Tato metoda asynchronně vrátí CallAgent
objekt instance.
Metoda createCallAgent
se používá CommunicationTokenCredential
jako argument. Přijímá přístupový token uživatele.
K přístupu deviceManager
můžete použít metodu getDeviceManager
v CallClient
instanci .
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 nejlépe spravovat připojení sady SDK k infrastruktuře Microsoftu
Tato Call Agent
instance vám pomůže spravovat hovory (pro připojení nebo zahájení hovorů). Aby bylo možné pracovat s vaší sadou SDK volání, musí se připojit k infrastruktuře Microsoftu, aby bylo možné dostávat oznámení o příchozích hovorech a koordinovat další podrobnosti volání. Máte Call Agent
dva možné stavy:
Připojeno – Call Agent
Hodnota connectionStatue znamená, Connected
že klientská sada SDK je připojená a dokáže přijímat oznámení z infrastruktury Microsoftu.
Odpojeno – Call Agent
Hodnota Disconnected
connectionStatue stavů existuje problém, který brání sadě SDK, aby se správně připojil. Call Agent
by se mělo znovu vytvořit.
invalidToken
: Pokud vypršela platnost tokenu nebo je neplatnáCall Agent
instance, odpojí se s touto chybou.connectionIssue
: Pokud došlo k problému s klientem, který se připojuje k infrascture Microsoftu, po mnoha opakovaných pokusechCall Agent
connectionIssue
se zobrazí chyba.
Zkontrolujte, jestli je vaše místní Call Agent
infrastruktura připojená k infrastruktuře Microsoftu, a to kontrolou aktuální hodnoty connectionState
vlastnosti. Během aktivního volání můžete naslouchat connectionStateChanged
události a zjistit, jestli Call Agent
se změny ze stavu Připojeno k Odpojeno .
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);
Správa zařízení
Pokud chcete začít používat video se sadou SDK pro volání, musíte být schopni spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.
deviceManager
Pomocí , můžete vytvořit výčet místních zařízení, která mohou přenášet zvukové a video streamy v hovoru. Můžete také požádat deviceManager
o oprávnění pro přístup k mikrofonům a kamerám místního zařízení.
Přístup můžete deviceManager
získat voláním callClient.getDeviceManager()
metody:
const deviceManager = await callClient.getDeviceManager();
Získání místních zařízení
Pro přístup k místním zařízením můžete použít metody getCameras()
výčtu deviceManager
a getMicrophones
. Tyto metody jsou asynchronní akce.
// 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...]
Nastavení výchozích zařízení
Jakmile budete vědět, která zařízení se dají používat, můžete nastavit výchozí zařízení pro mikrofon, reproduktor a kameru. Pokud nejsou nastavené výchozí hodnoty klienta, sada SDK komunikačních služeb používá výchozí nastavení operačního systému.
Mikrofon
Přístup k použitému zařízení
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
Nastavení zařízení, které se má použít
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
Speaker
Přístup k použitému zařízení
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Nastavení zařízení, které se má použít
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Kamera
Přístup k použitému zařízení
// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Nastavení zařízení, které se má použít
// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);
Každý CallAgent
si může vybrat svůj vlastní mikrofon a reproduktory na přidruženém DeviceManager
. Doporučujeme používat různé CallAgents
mikrofony a reproduktory. Neměli by sdílet stejné mikrofony ani reproduktory. Pokud dojde ke sdílení, může se aktivovat diagnostika uživatelů mikrofonu a mikrofon přestane fungovat v závislosti na prohlížeči nebo operačním systému.
Místní stream videa
Abyste mohli posílat video ve volání, musíte vytvořit LocalVideoStream
objekt.
const localVideoStream = new LocalVideoStream(camera);
Kamera předaná jako parametr je jedním z VideoDeviceInfo
objektů vrácených metodou deviceManager.getCameras()
.
A LocalVideoStream
má následující vlastnosti:
source
: Informace o zařízení.
const source = localVideoStream.source;
mediaStreamType
: Může býtVideo
,ScreenSharing
neboRawMedia
.
const type: MediaStreamType = localVideoStream.mediaStreamType;
Náhled místního fotoaparátu
Můžete použít deviceManager
a VideoStreamRenderer
začít vykreslovat streamy z místní kamery.
Jakmile se vytvoří LocalVideoStream
, použijte ho k nastaveníVideoStreamRenderer
. VideoStreamRenderer
Po vytvoření volání metody createView()
získat zobrazení, které můžete přidat jako dítě na stránku.
Tento stream se neodesílají ostatním účastníkům; je to místní informační kanál ve verzi Preview.
// 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);
Zastavení místního náhledu
Chcete-li zastavit místní volání náhledu, odstraňte zobrazení odvozené z objektu VideoStreamRenderer
.
Jakmile videoStreamRenderer odstraníte, odeberte zobrazení ze stromu HTML voláním removeChild()
metody z DOM Node obsahující váš náhled.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Žádost o oprávnění ke kameře a mikrofonu
Aplikace nemůže používat kameru ani mikrofon bez oprávnění. Správce zařízení můžete použít k zobrazení výzvy uživateli k udělení oprávnění fotoaparátu nebo mikrofonu:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
Jakmile je příslib vyřešen, vrátí metoda s DeviceAccess
objektem, který označuje, zda audio
a video
oprávnění byla udělena:
console.log(result.audio);
console.log(result.video);
Notes
videoDevicesUpdated
událost se aktivuje, když jsou videozařízení připojená/odpojená.audioDevicesUpdated
událost se aktivuje, když jsou připojena zvuková zařízení.- Při vytváření správce zařízení nejprve nezná žádná zařízení, pokud ještě nejsou udělená oprávnění, takže jeho název zařízení je zpočátku prázdný a neobsahuje podrobné informace o zařízení. Pokud pak zavoláme rozhraní API DeviceManager.askPermission(), zobrazí se uživateli výzva k přístupu k zařízení. Když uživatel vybere možnost Povolit, aby správci zařízení udělil přístup, dozví se o zařízeních v systému, aktualizujte jeho seznamy zařízení a vygenerujte události audioDevicesUpdated a videoDevicesUpdated. Pokud uživatel stránku aktualizuje a vytvoří správce zařízení, může se správce zařízení dozvědět o zařízeních, protože uživatel udělil přístup dříve. Má zpočátku vyplněné seznamy zařízení a nevysílají události audioDevicesUpdated ani videoDevicesUpdated.
- Výčet a výběr mluvčího se nepodporuje v Android Chrome, iOS Safari ani macOS Safari.
Volání pomocí videokamery
Důležité
Aktuálně se podporuje jenom jeden odchozí místní video stream.
Chcete-li umístit videohovor, musíte vytvořit výčet místních fotoaparátů pomocí getCameras()
metody v deviceManager
.
Jakmile vyberete kameru, použijte ji k vytvoření LocalVideoStream
instance.
Předejte ji videoOptions
jako položku v rámci localVideoStream
pole metodě CallAgent
startCall
.
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);
- Můžete se také připojit k volání pomocí videa s rozhraním
CallAgent.join()
API a přijmout a volat s videem pomocíCall.Accept()
rozhraní API. - Když se hovor připojí, automaticky začne odesílat stream videa z vybrané kamery druhému účastníkovi.
Spuštění a zastavení odesílání místního videa během hovoru
Spustit video
Pokud chcete zahájit video během hovoru, musíte vytvořit výčet fotoaparátů pomocí getCameras
metody na objektu deviceManager
.
Pak vytvořte novou instanci LocalVideoStream
s požadovanou kamerou a pak předejte LocalVideoStream
objekt do startVideo
metody existujícího objektu volání:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Zastavit video
Po úspěšném zahájení odesílání videa LocalVideoStream
se do localVideoStreams
kolekce v instanci volání přidá instance typuVideo
.
Vyhledání streamu videa v objektu Volání
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );
Zastavte místní video , pokud chcete zastavit místní video během hovoru, předejte localVideoStream
instanci, která se používá pro video do metody stopVideo metody Call
:
await call.stopVideo(localVideoStream);
Když budete mít aktivní LocalVideoStream, můžete přepnout na jiné zařízení fotoaparátu tak, že na této LocalVideoStream
instanci vyvoláteswitchSource
:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Pokud zadané videoza zařízení není k dispozici:
- Pokud je vaše video při volání vypnuté a začnete používat
call.startVideo()
video , tato metoda vyvoláSourceUnavailableError
diagnostiku acameraStartFailed
uživatelem je nastavena na hodnotu true. - Volání
localVideoStream.switchSource()
metody způsobícameraStartFailed
, že se nastaví na true. Náš průvodce diagnostikou hovorů poskytuje další informace o tom, jak diagnostikovat problémy související s voláním.
Pokud chcete ověřit, jestli je místní video zapnuté nebo vypnuté, můžete použít metodu Call
isLocalVideoStarted
, která vrátí hodnotu true nebo false:
// Check if local video is on or off
call.isLocalVideoStarted;
Pokud chcete naslouchat změnám místního videa, můžete se přihlásit k odběru a odhlášení odběru události isLocalVideoStartedChanged:
// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
// Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
// Callback();
});
Spuštění a zastavení sdílení obrazovky během hovoru
Pokud chcete zahájit sdílení obrazovky během volání, můžete použít asynchronní metodu startScreenSharing()
objektu Call
:
Spuštění sdílení obrazovky
// Start screen sharing
await call.startScreenSharing();
Poznámka: Odesílání sdílení obrazovky je podporováno pouze v prohlížeči v počítači.
Vyhledání sdílení obrazovky v kolekci LocalVideoStream
Po úspěšném zahájení odesílání sdílení LocalVideoStream
obrazovky se do kolekce v instanci volání přidá localVideoStreams
instance typuScreenSharing
.
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );
Ukončení sdílení obrazovky
Pokud chcete během hovoru ukončit sdílení obrazovky, můžete použít asynchronní zastavení obrazovky API StoptScreenSharing:
// Stop screen sharing
await call.stopScreenSharing();
Kontrola stavu sdílení obrazovky
Pokud chcete ověřit, jestli je sdílení obrazovky zapnuté nebo vypnuté, můžete použít rozhraní APIscreenSharingOn, které vrací hodnotu true nebo false:
// Check if screen sharing is on or off
call.isScreenSharingOn;
Pokud chcete naslouchat změnám sdílené složky obrazovky, můžete se přihlásit k odběru a odhlásit odběr události isScreenSharingOnChanged:
// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
// Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
// Callback();
});
Důležité
Tato funkce služeb Azure Communication Services je aktuálně ve verzi Preview.
Rozhraní API a sady SDK verze Preview jsou poskytovány bez smlouvy o úrovni služeb. Doporučujeme je nepoužívat pro produkční úlohy. Některé funkce nemusí být podporované nebo můžou mít omezené možnosti.
Další informace najdete v dodatečných podmínkách použití pro verze Preview Microsoft Azure.
Náhled místní sdílené složky obrazovky je ve veřejné verzi Preview a je k dispozici jako součást verze 1.15.1-beta.1+.
Náhled sdílení místní obrazovky
Můžete použít VideoStreamRenderer
k zahájení vykreslování streamů z místní sdílené složky obrazovky, abyste viděli, co posíláte jako stream sdílení obrazovky.
// 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);
}
});
Vykreslení videa nebo sdílení obrazovek vzdáleného účastníka
Pokud chcete vykreslit video nebo sdílení obrazovky vzdáleného účastníka, prvním krokem je získání odkazu na RemoteVideoStream, který chcete vykreslit.
To lze provést procházením pole nebo video streamu (videoStreams
) z RemoteParticipant
. Ke kolekci vzdálených účastníků se přistupuje prostřednictvím objektu Call
.
const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;
Pokud chcete vykreslit RemoteVideoStream
, musíte se přihlásit k odběru události isAvailableChanged
. Pokud se isAvailable
vlastnost změní na true
, vzdálený účastník odesílá stream videa.
Potom vytvořte novou instanci VideoStreamRenderer
a pak vytvořte novou VideoStreamRendererView
instanci pomocí asynchronní createView
metody.
Pak se můžete připojit view.target
k libovolnému prvku uživatelského rozhraní.
Kdykoli se změní dostupnost vzdáleného streamu, můžete zničit celý VideoStreamRenderer
nebo konkrétní VideoStreamRendererView
.
Pokud se rozhodnete je zachovat, zobrazí se v zobrazení prázdný rámeček videa.
// 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}`);
});
}
CSS pro stylování číselníku načítání přes vzdálený datový proud videa.
.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); }
}
Kvalita vzdáleného videa
Sada Azure Communication Services WebJS SDK poskytuje funkci s názvem Optimální počet videí (OVC) počínaje verzí 1.15.1.
Tuto funkci lze použít k informování aplikací za běhu o tom, kolik příchozích videí od různých účastníků se dá v daném okamžiku optimálně vykreslit ve skupinovém hovoru (2+ účastníci).
Tato funkce zveřejňuje vlastnost optimalVideoCount
, která se dynamicky mění během volání na základě síťových a hardwarových funkcí místního koncového bodu. Hodnota podrobností, optimalVideoCount
kolik videí z jiné aplikace účastníka by se mělo vykreslit v daném okamžiku. Aplikace by měly tyto změny zpracovat a odpovídajícím způsobem aktualizovat počet vykreslovaných videí podle doporučení. Mezi každou aktualizací je období zrušení (přibližně 10 s).
Použití funkce optimalVideoCount
je funkce volání. Funkci musíte odkazovat OptimalVideoCount
prostřednictvím feature
metody objektu Call
. Potom můžete nastavit naslouchací OptimalVideoCountCallFeature
proces pomocí on
metody, která se má upozornit, když se změní optimalVideoCount. Pokud se chcete odhlásit od změn, můžete metodu off
volat. Aktuální maximální počet příchozích videí , která se dají vykreslit, je 16. Aby počítač správně podporoval 16 příchozích videí, měl by mít mimimum 16 GB RAM a 4jádrový nebo větší procesor, který není starší než 3 roky.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Příklad použití: Aplikace by se měla přihlásit k odběru změn optimálního počtu videí ve skupinových voláních. Změnu optimálního počtu videí je možné zpracovat vytvořením nového rendereru (createView
metody) nebo odstraněním zobrazení (dispose
) a odpovídajícím způsobem aktualizovat rozložení aplikace.
Vlastnosti vzdáleného streamu videa
Vzdálené streamy videa mají následující vlastnosti:
const id: number = remoteVideoStream.id;
id
: ID vzdáleného streamu videa.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
mediaStreamType
: Může býtVideo
neboScreenSharing
.
const isAvailable: boolean = remoteVideoStream.isAvailable;
isAvailable
: Definuje, jestli koncový bod vzdáleného účastníka aktivně odesílá stream.
const isReceiving: boolean = remoteVideoStream.isReceiving;
isReceiving
:Informuje aplikaci, pokud se přijímají nebo neschovávají data vzdáleného datového proudu videa.
Příznak se přesune do
false
následujících scénářů:- Vzdálený účastník, který je v mobilním prohlížeči, přenese aplikaci prohlížeče na pozadí.
- Vzdálený účastník nebo uživatel, který video obdrží, má problém se sítí, který výrazně ovlivňuje kvalitu videa.
- Vzdálený účastník, který je v macOS/iOS Safari, vybere "Pozastavit" z adresního řádku.
- Vzdálený účastník má odpojení sítě.
- Vzdálený účastník na mobilním zařízení ukončí nebo ukončí prohlížeč.
- Vzdálený účastník na mobilním zařízení nebo na ploše uzamkne své zařízení. Tento scénář platí také v případě, že je vzdálený účastník na stolním počítači a přejde do režimu spánku.
Příznak se přesune do
true
následujících scénářů:- Vzdálený účastník, který je v mobilním prohlížeči a má pozadí prohlížeče, ho vrátí do popředí.
- Vzdálený účastník, který je v macOS/iOS Safari, vybere na panelu Adresa po pozastavení videa možnost Pokračovat.
- Vzdálený účastník se po dočasném odpojení znovu připojí k síti.
- Vzdálený účastník na mobilním zařízení odemkne a vrátí se do hovoru v mobilním prohlížeči.
Tato funkce zlepšuje uživatelské prostředí pro vykreslování vzdálených datových proudů videa.
Pokud se příznak isReceiving změní na false, můžete zobrazit číselník načítání přes vzdálený stream videa. Nemusíte implementovat číselník načítání, ale číselník načítání je nejběžnějším využitím pro lepší uživatelské prostředí.
const size: StreamSize = remoteVideoStream.size;
size
: Velikost datového proudu s informacemi o šířce a výšce videa.
Metody a vlastnosti VideoStreamRenderer
await videoStreamRenderer.createView();
Vytvořte VideoStreamRendererView
instanci, kterou lze připojit v uživatelském rozhraní aplikace k vykreslení vzdáleného video streamu, použít asynchronní createView()
metodu, přeloží, když je stream připravený k vykreslení a vrátí objekt s target
vlastností, která představuje video
prvek, který lze vložit kdekoli ve stromu MODELU DOM.
videoStreamRenderer.dispose();
Dispose of videoStreamRenderer
and all associated VideoStreamRendererView
instances.
VideoStreamRendererView – metody a vlastnosti
Při vytváření VideoStreamRendererView
můžete zadat scalingMode
vlastnosti a isMirrored
vlastnosti. scalingMode
může být Stretch
, Crop
nebo Fit
. Pokud isMirrored
je zadán, vykreslený datový proud se překlopí svisle.
const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });
Každá VideoStreamRendererView
instance má target
vlastnost, která představuje plochu vykreslování. Připojte tuto vlastnost v uživatelském rozhraní aplikace:
htmlElement.appendChild(view.target);
Aktualizaci můžete provést scalingMode
vyvoláním updateScalingMode
metody:
view.updateScalingMode('Crop');
Odešlete streamy videa ze dvou různých fotoaparátů ve stejném hovoru ze stejného stolního zařízení.
Důležité
Tato funkce služeb Azure Communication Services je aktuálně ve verzi Preview.
Rozhraní API a sady SDK verze Preview jsou poskytovány bez smlouvy o úrovni služeb. Doporučujeme je nepoužívat pro produkční úlohy. Některé funkce nemusí být podporované nebo můžou mít omezené možnosti.
Další informace najdete v dodatečných podmínkách použití pro verze Preview Microsoft Azure.
Odesílání streamů videa ze dvou různých fotoaparátů ve stejném hovoru se podporuje jako součást verze 1.17.1-beta.1 nebo novější v prohlížečích podporovaných pro stolní počítače.
- Streamy videa ze dvou různých fotoaparátů můžete odesílat z jedné karty nebo aplikace desktopového prohlížeče ve stejném volání s následujícím fragmentem kódu:
// 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();
Omezení:
- Musí to být provedeno se dvěma různými
CallAgent
instancemi pomocí různých identit. Fragment kódu ukazuje, že se používají dva agenti volání, z nichž každý má vlastní objekt Call. - V příkladu kódu se oba CallAgents připojují ke stejnému volání (stejné ID volání). Můžete se také připojit k různým voláním s jednotlivými agenty a odeslat jedno video na jeden hovor a jiné video na druhém hovoru.
- Odesílání stejné kamery v obou callagentech se nepodporuje. Musí to být dvě různé kamery.
- Odesílání dvou různých fotoaparátů pomocí jednoho callagentu se v současné době nepodporuje.
- V macOS Safari, rozostření pozadí efekty videa (z @azure/communication-effects), lze použít pouze na jednu kameru, a ne na obou současně.
Nainstalujte sadu SDK .
Vyhledejte soubor na úrovni build.gradle
projektu a přidejte mavenCentral()
ho do seznamu úložišť v části buildscript
a allprojects
:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Potom do souboru na úrovni build.gradle
modulu přidejte do oddílu dependencies
následující řádky:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Inicializace požadovaných objektů
Pokud chcete vytvořit CallAgent
instanci, musíte metodu createCallAgent
CallClient
volat v instanci. Toto volání asynchronně vrátí CallAgent
objekt instance.
Metoda createCallAgent
přebírá CommunicationUserCredential
jako argument, který zapouzdřuje přístupový token.
Pokud chcete získat přístup DeviceManager
, musíte nejprve vytvořit callAgent
instanci. Pak můžete použít metodu CallClient.getDeviceManager
získat 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();
Pokud chcete nastavit zobrazovaný název volajícího, použijte tuto alternativní metodu:
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();
Správa zařízení
Pokud chcete začít používat video s voláním, budete muset vědět, jak spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.
DeviceManager
umožňuje vytvořit výčet místních zařízení, která se dají použít při volání k přenosu zvukových datových proudů nebo datových proudů videa. Umožňuje také požádat uživatele o oprávnění pro přístup k mikrofonu a fotoaparátu pomocí nativního rozhraní API prohlížeče.
Přístup můžete deviceManager
provést voláním callClient.getDeviceManager()
metody.
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Vytvoření výčtu místních zařízení
Pro přístup k místním zařízením můžete v Správce zařízení použít metody výčtu. Výčet je synchronní akce.
// Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
Náhled místního fotoaparátu
Můžete použít DeviceManager
a Renderer
začít vykreslovat streamy z místní kamery. Tento datový proud se neodesílají ostatním účastníkům; je to místní informační kanál ve verzi Preview. Jedná se o asynchronní akci.
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);
1:1 hovor s videokamerou
Upozorňující
V současné době je podporován pouze jeden odchozí místní video stream, pokud chcete umístit hovor s videem, které musíte vytvořit výčet místních fotoaparátů pomocí deviceManager
getCameras
rozhraní API.
Jakmile vyberete požadovanou kameru, použijte ji k vytvoření LocalVideoStream
instance a předání videoOptions
jako položky v localVideoStream
poli metodě call
.
Jakmile se hovor připojí, automaticky začne odesílat stream videa z vybrané kamery jiným účastníkům.
Poznámka:
Vzhledem k obavám o ochranu osobních údajů se video nesdílí do hovoru, pokud se nesdílí v místním náhledu. Další podrobnosti najdete v části Náhled místní kamery.
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);
Spuštění a zastavení odesílání místního videa
Pokud chcete zahájit video, musíte vytvořit výčet fotoaparátů pomocí rozhraní API na deviceManager
objektugetCameraList
. Pak vytvořte novou instanci LocalVideoStream
předání požadované kamery a předejte ji do startVideo
rozhraní 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 úspěšném zahájení odesílání videa LocalVideoStream
se do kolekce v instanci volání přidá localVideoStreams
instance.
List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).
Pokud chcete zastavit místní video, předejte instanci dostupnou LocalVideoStream
v localVideoStreams
kolekci:
call.stopVideo(appContext, currentLocalVideoStream).get();
Při odesílání videa na switchSource
LocalVideoStream
instanci můžete přepnout na jiné zařízení fotoaparátu:
currentLocalVideoStream.switchSource(source).get();
Vykreslení datových proudů videa vzdáleného účastníka
Pokud chcete zobrazit seznam streamů videa a streamů sdílení obrazovky vzdálených účastníků, prohlédněte si videoStreams
kolekce:
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
Pokud chcete vykreslit RemoteVideoStream
od vzdáleného účastníka, musíte se přihlásit k odběru OnVideoStreamsUpdated
události.
V rámci události změna isAvailable
vlastnosti na true znamená, že vzdálený účastník právě odesílá stream. Jakmile k tomu dojde, vytvořte novou instanci Renderer
a pak vytvořte novou RendererView
pomocí asynchronního createView
rozhraní API a připojte view.target
ji kdekoli v uživatelském rozhraní vaší aplikace.
Kdykoli se změní dostupnost vzdáleného streamu, můžete se rozhodnout zničit celý renderer, konkrétní RendererView
nebo zachovat, ale výsledkem bude zobrazení prázdného rámečku videa.
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();
}
}
}
Vlastnosti vzdáleného streamu videa
Vzdálený stream videa má několik vlastností.
Id
- ID vzdáleného streamu videa
int id = remoteVideoStream.getId();
MediaStreamType
– Může se jednat o video nebo sdílení obrazovky.
MediaStreamType type = remoteVideoStream.getMediaStreamType();
isAvailable
– Označuje, jestli koncový bod vzdáleného účastníka aktivně odesílá stream.
boolean availability = remoteVideoStream.isAvailable();
Metody a vlastnosti rendereru
Objekt rendereru následující rozhraní API
VideoStreamRendererView
Vytvořte instanci, kterou můžete později připojit v uživatelském rozhraní aplikace k vykreslení vzdáleného streamu videa.
// Create a view for a video stream
VideoStreamRendererView.createView()
- Vyřaďte renderer a všechny
VideoStreamRendererView
přidružené k tomuto rendereru. Chcete-li volat, když jste odebrali všechna přidružená zobrazení z uživatelského rozhraní.
VideoStreamRenderer.dispose()
StreamSize
- velikost (šířka/výška) vzdáleného video streamu
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();
RendererView – metody a vlastnosti
Při vytváření VideoStreamRendererView
můžete zadat ScalingMode
vlastnosti a mirrored
vlastnosti, které budou platit pro toto zobrazení: Režim škálování může být buď oříznout | FIT
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));
Vytvořený RendererView je pak možné připojit k uživatelskému rozhraní aplikace pomocí následujícího fragmentu kódu:
layout.addView(rendererView);
Později můžete režim škálování aktualizovat vyvoláním updateScalingMode
rozhraní API na objektu RendererView jedním z ScalingMode.CROP | ScalingMode.FIT jako argument.
// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)
Nastavení systému
Podle těchto kroků nastavte systém.
Vytvoření projektu Xcode
V Xcode vytvořte nový projekt pro iOS a vyberte šablonu aplikace s jedním zobrazením . Tento článek používá architekturu SwiftUI, takže byste měli nastavit jazyk na Swift a nastavit rozhraní na SwiftUI.
V tomto článku nebudete vytvářet testy. Zrušte zaškrtnutí políčka Zahrnout testy .
Instalace balíčku a závislostí pomocí CocoaPods
Vytvořte pro aplikaci soubor Podfile, například v tomto příkladu:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Spusťte
pod install
.Otevřete
.xcworkspace
pomocí Xcode.
Vyžádání přístupu k mikrofonu
Pokud chcete získat přístup k mikrofonu zařízení, musíte aktualizovat seznam vlastností informací aplikace pomocí NSMicrophoneUsageDescription
. Nastavte přidruženou hodnotu na řetězec, který je součástí dialogového okna, který systém používá k vyžádání přístupu od uživatele.
Klikněte pravým tlačítkem myši na položku Info.plist stromu projektu a pak vyberte Open As>Source Code. Do oddílu nejvyšší úrovně <dict>
přidejte následující řádky a pak soubor uložte.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Nastavení architektury aplikace
Otevřete soubor projektu ContentView.swift
. import
Přidejte deklaraci do horní části souboru pro import AzureCommunicationCalling
knihovny. Kromě toho import AVFoundation
. Potřebujete ho pro žádosti o zvuková oprávnění v kódu.
import AzureCommunicationCalling
import AVFoundation
Inicializace callagentu
Chcete-li vytvořit CallAgent
instanci z CallClient
, musíte použít metodu callClient.createCallAgent
, která asynchronně vrátí CallAgent
objekt po inicializaci.
Pokud chcete vytvořit klienta volání, předejte CommunicationTokenCredential
objekt:
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
Předejte objekt, který jste vytvořiliCallClient
, a nastavte zobrazovaný název:
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")
}
})
Správa zařízení
Pokud chcete začít používat video s voláním, budete muset vědět, jak spravovat zařízení. Zařízení umožňují řídit, co do hovoru přenáší zvuk a video.
DeviceManager
umožňuje vytvořit výčet místních zařízení, která lze použít při volání k přenosu zvukových nebo video streamů. Umožňuje také požádat uživatele o oprávnění pro přístup k mikrofonu nebo kameře. K objektu callClient
máte přístupdeviceManager
.
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")
}
}
Vytvoření výčtu místních zařízení
Pro přístup k místním zařízením můžete použít metody výčtu ve Správci zařízení. Výčet je synchronní akce.
// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]
Získání náhledu místního fotoaparátu
Můžete začít Renderer
vykreslovat stream z místní kamery. Tento datový proud se neodesílají ostatním účastníkům; je to místní informační kanál ve verzi Preview. Jedná se o asynchronní akci.
let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()
Získání vlastností náhledu místního fotoaparátu
Renderer má sadu vlastností a metod, které umožňují řídit vykreslování.
// 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()
1:1 hovor s videem
Pokud chcete získat instanci správce zařízení, přečtěte si část o správě zařízení.
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")
}
}
Vykreslení datových proudů videa vzdáleného účastníka
Vzdálení účastníci můžou zahájit sdílení videa nebo obrazovky během hovoru.
Zpracování streamů sdílení videa nebo sdílení obrazovky vzdálených účastníků
Pokud chcete zobrazit seznam datových proudů vzdálených účastníků, zkontrolujte videoStreams
kolekce.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Získání vlastností vzdáleného streamu videa
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
Vykreslení datových proudů vzdálených účastníků
Pokud chcete začít vykreslovat streamy vzdálených účastníků, použijte následující kód.
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)
Získání metod a vlastností vzdáleného rendereru videa
// [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()
Nastavení systému
Podle těchto kroků nastavte systém.
Vytvoření projektu sady Visual Studio
V případě Univerzální platforma Windows aplikace vytvořte v sadě Visual Studio 2022 nový projekt Prázdná aplikace (Universal Windows). Po zadání názvu projektu si můžete vybrat libovolnou sadu Windows SDK později než 10.0.17763.0.
V případě aplikace WinUI 3 vytvořte nový projekt pomocí šablony Prázdná aplikace zabalená (WinUI 3 v desktopové verzi) pro nastavení jednostráňové aplikace WinUI 3. Vyžaduje se sada Windows App SDK verze 1.3 nebo novější.
Instalace balíčku a závislostí pomocí Správce balíčků NuGet
Rozhraní API a knihovny volající sady SDK jsou veřejně dostupné prostřednictvím balíčku NuGet.
Vyhledání, stažení a instalace balíčku NuGet volající sady SDK:
- Otevřete Správce balíčků NuGet výběrem nástrojů>NuGet Správce balíčků> Nabídky NuGet pro řešení.
- Vyberte Procházet a do vyhledávacího pole zadejte Azure.Communication.Calling.WindowsClient .
- Ujistěte se, že je zaškrtnuté políčko Zahrnout předběžné verze .
- Vyberte balíček Azure.Communication.Calling.WindowsClient a pak vyberte Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 nebo novější verzi.
- Zaškrtněte políčko odpovídající projektu Azure Communication Services v pravém podokně.
- Vyberte volbu Instalovat.
Vyžádání přístupu k mikrofonu
Aby aplikace fungovala správně, vyžaduje přístup k fotoaparátu. V aplikacích pro UPW by měla být funkce fotoaparátu deklarována v souboru manifestu aplikace.
Následující kroky ukazují, jak toho dosáhnout.
- Na panelu
Solution Explorer
poklikejte na soubor s příponou.appxmanifest
. - Klikněte na
Capabilities
kartu. Camera
V seznamu možností zaškrtněte políčko.
Vytvoření tlačítek uživatelského rozhraní pro umístění a zavěsit hovor
Tato jednoduchá ukázková aplikace obsahuje dvě tlačítka. Jeden pro umístění hovoru a druhý zavěsit umístěný hovor. Následující postup ukazuje, jak tato tlačítka přidat do aplikace.
- Na panelu
Solution Explorer
poklikejte na soubor s názvemMainPage.xaml
UPW neboMainWindows.xaml
WinUI 3. - Na centrálním panelu vyhledejte kód XAML v náhledu uživatelského rozhraní.
- Upravte kód XAML následujícím výňatkem:
<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>
Nastavení aplikace pomocí rozhraní API pro volání sady SDK
Rozhraní API volající sady SDK jsou ve dvou různých oborech názvů. Následující kroky informují kompilátor jazyka C# o těchto oborech názvů, což umožňuje intellisense sady Visual Studio pomáhat s vývojem kódu.
- Na panelu
Solution Explorer
klikněte na šipku na levé straně souboru s názvemMainPage.xaml
UPW neboMainWindows.xaml
WinUI 3. - Poklikejte na soubor s názvem
MainPage.xaml.cs
neboMainWindows.xaml.cs
. - Na konec aktuálních
using
příkazů přidejte následující příkazy.
using Azure.Communication.Calling.WindowsClient;
Nechte MainPage.xaml.cs
nebo MainWindows.xaml.cs
otevřete. Další kroky do něj přidají další kód.
Povolit interakce aplikací
Tlačítka uživatelského rozhraní, která byla přidána, musí pracovat nad umístěním CommunicationCall
. To znamená, že CommunicationCall
datový člen by měl být přidán do MainPage
třídy nebo MainWindow
třídy.
Kromě toho, aby bylo možné úspěšně vytvořit CallAgent
asynchronní operaci, CallAgent
by měl být také přidán datový člen do stejné třídy.
Do třídy nebo MainWindow
třídy přidejte následující datové členyMainPage
:
CallAgent callAgent;
CommunicationCall call;
Vytváření obslužných rutin tlačítek
Dříve byly do kódu XAML přidány dvě tlačítka uživatelského rozhraní. Následující kód přidá obslužné rutiny, které se mají spustit, když uživatel tlačítko vybere. Následující kód by se měl přidat za datové členy z předchozí části.
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start call
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// End the current call
}
Objektový model
Následující třídy a rozhraní zpracovávají některé z hlavních funkcí klientské knihovny volání služeb Azure Communication Services pro UPW.
Název | Popis |
---|---|
CallClient |
Jedná se CallClient o hlavní vstupní bod do klientské knihovny volání. |
CallAgent |
Slouží CallAgent ke spuštění a připojení k voláním. |
CommunicationCall |
Slouží CommunicationCall ke správě umístěných nebo připojených hovorů. |
CommunicationTokenCredential |
Slouží CommunicationTokenCredential jako přihlašovací údaje tokenu k vytvoření instance CallAgent . |
CallAgentOptions |
Obsahuje CallAgentOptions informace pro identifikaci volajícího. |
HangupOptions |
Informuje HangupOptions , jestli má být hovor ukončen všem účastníkům. |
Registrace obslužné rutiny schématu videa
Součást uživatelského rozhraní, jako je MediaElement XAML nebo MediaPlayerElement, potřebujete aplikaci, která registruje konfiguraci pro vykreslování místních a vzdálených video kanálů.
Přidejte následující obsah mezi Package
značky Package.appxmanifest
:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
Inicializace callagentu
Chcete-li vytvořit CallAgent
instanci z CallClient
, musíte použít CallClient.CreateCallAgentAsync
metodu, která asynchronně vrátí CallAgent
objekt po inicializaci.
Chcete-li vytvořit CallAgent
, musíte předat CallTokenCredential
objekt a CallAgentOptions
objekt. Mějte na paměti, že CallTokenCredential
pokud je předán poškozený token.
Do pomocné funkce by se měl přidat následující kód, který se má volat při inicializaci aplikace.
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;
<AUTHENTICATION_TOKEN>
Změňte platný token přihlašovacích údajů pro váš prostředek. Informace o přístupovém tokenu uživatele najdete v dokumentaci, pokud musí být zdrojový token přihlašovacích údajů.
1:1 hovor s videokamerou
Objekty potřebné k vytvoření CallAgent
jsou teď připravené. Je čas asynchronně vytvořit CallAgent
a umístit videohovor.
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 } }
};
}
Náhled místního fotoaparátu
Volitelně můžeme nastavit náhled místního fotoaparátu. Video lze vykreslit prostřednictvím MediaPlayerElement
:
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
Inicializace místního náhledu 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);
}
}
Vykreslení vzdáleného streamu fotoaparátu
Nastavení obslužné rutiny sudé v reakci na OnCallsUpdated
událost:
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;
}
}
Začněte vykreslovat vzdálený stream videa na 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;
}
}
Ukončení hovoru
Po umístění HangupAsync
volání by metoda objektu CommunicationCall
měla být použita k zablokování volání.
Instance HangupOptions
by měla být také použita k informování, zda musí být hovor ukončen všem účastníkům.
Následující kód by měl být přidán dovnitř HangupButton_Click
.
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;
}
}
}
}
Spuštění kódu
Ujistěte se, že Visual Studio sestaví aplikaci pro x64
x86
aplikaci nebo ARM64
a pak stiskněte klávesu a F5
spusťte aplikaci. Potom kliknutím na CommunicationCall
tlačítko umístíte volání do volané.
Mějte na paměti, že při prvním spuštění aplikace systém vyzve uživatele k udělení přístupu k mikrofonu.