Mengelola video selama panggilan
Pelajari cara mengelola panggilan dengan Azure Communication Services SDKS. Kami akan belajar bagaimana mengelola menerima dan mengirim video dalam panggilan.
Prasyarat
- Akun Azure dengan langganan aktif. Buat akun secara gratis.
- Sumber daya Communication Services yang disebarkan. Buat sumber daya Azure Communication Services.
- Token akses pengguna untuk mengaktifkan klien panggilan. Untuk informasi selengkapnya, lihat Membuat dan mengelola token akses.
- Opsional: Selesaikan panduan memulai cepat untuk menambahkan panggilan suara ke aplikasi Anda
Pasang SDK
npm install
Gunakan perintah untuk menginstal SDK Umum dan Panggilan Azure Communication Services untuk JavaScript:
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Menginisialisasi objek yang diperlukan
Instans CallClient
diperlukan untuk sebagian besar operasi panggilan. Saat membuat instans baru CallClient
, Anda dapat mengonfigurasinya dengan opsi kustom seperti Logger
instans.
CallClient
Dengan instans, Anda dapat membuat CallAgent
instans dengan memanggil createCallAgent
. Metode ini secara asinkron mengembalikan objek instans CallAgent
.
Metode createCallAgent
menggunakan CommunicationTokenCredential
sebagai argumen. Hal ini menerima token akses pengguna.
Anda dapat menggunakan metode getDeviceManager
pada instans CallClient
untuk mengakses deviceManager
.
const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the logger's log level
setLogLevel('verbose');
// Redirect log output to console, file, buffer, REST API, or whatever location you want
AzureLogger.log = (...args) => {
console.log(...args); // Redirect log output to console
};
const userToken = '<USER_TOKEN>';
callClient = new CallClient(options);
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'optional Azure Communication Services user name'});
const deviceManager = await callClient.getDeviceManager()
Cara terbaik mengelola konektivitas SDK ke infrastruktur Microsoft
Call Agent
Instans ini membantu Anda mengelola panggilan (untuk bergabung atau memulai panggilan). Untuk bekerja, SDK panggilan Anda perlu tersambung ke infrastruktur Microsoft untuk mendapatkan pemberitahuan panggilan masuk dan mengoordinasikan detail panggilan lainnya. Anda Call Agent
memiliki dua kemungkinan status:
Tersambung - Nilai Call Agent
Connected
connectionStatue berarti SDK klien terhubung dan mampu menerima pemberitahuan dari infrastruktur Microsoft.
Terputus - Nilai Call Agent
Disconnected
status connectionStatue ada masalah yang mencegah SDK menyambungkannya dengan benar. Call Agent
harus dibuat ulang.
invalidToken
: Jika token kedaluwarsa atau instans tidak validCall Agent
terputus dengan kesalahan ini.connectionIssue
: Jika ada masalah dengan klien yang terhubung ke microsoft infrascture, setelah banyak percobaanCall Agent
ulang mengeksposconnectionIssue
kesalahan.
Anda dapat memeriksa apakah lokal Call Agent
Anda tersambung ke infrastruktur Microsoft dengan memeriksa nilai connectionState
properti saat ini. Selama panggilan aktif, Anda dapat mendengarkan connectionStateChanged
acara untuk menentukan apakah Call Agent
perubahan dari status Tersambung ke Terputus .
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);
Manajemen perangkat
Untuk mulai menggunakan video dengan SDK Panggilan, Anda harus dapat mengelola perangkat. Perangkat memungkinkan Anda untuk mengontrol apa yang mentransmisikan Audio dan Video ke panggilan.
deviceManager
Dengan , Anda dapat menghitung perangkat lokal yang dapat mengirimkan aliran audio dan video Anda dalam panggilan. Anda juga dapat menggunakan deviceManager
untuk meminta izin untuk mengakses mikrofon dan kamera perangkat lokal.
Anda dapat mengakses deviceManager
dengan memanggil metode callClient.getDeviceManager()
:
const deviceManager = await callClient.getDeviceManager();
Mendapatkan perangkat lokal
Untuk mengakses perangkat lokal, Anda dapat menggunakan deviceManager
metode getCameras()
enumerasi dan getMicrophones
. Metode tersebut adalah tindakan asinkron.
// 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...]
Mengatur perangkat default
Setelah mengetahui perangkat apa yang tersedia untuk digunakan, Anda dapat mengatur perangkat default untuk mikrofon, speaker, dan kamera. Jika default klien tidak diatur, SDK Communication Services menggunakan default sistem operasi.
Mikrofon
Mengakses perangkat yang digunakan
// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;
Mengatur perangkat yang akan digunakan
// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);
Speaker
Mengakses perangkat yang digunakan
// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Mengatur perangkat yang akan digunakan
// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);
Kamera
Mengakses perangkat yang digunakan
// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;
Mengatur perangkat yang akan digunakan
// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);
Masing-masing CallAgent
dapat memilih mikrofon dan speakernya sendiri pada yang terkait DeviceManager
. Sebaiknya gunakan CallAgents
mikrofon dan speaker yang berbeda. Mereka tidak boleh berbagi mikrofon atau speaker yang sama. Jika berbagi terjadi, maka Diagnostik Yang Dihadapi Pengguna Mikrofon mungkin dipicu dan mikrofon berhenti berfungsi tergantung pada browser / os.
Aliran video lokal
Agar dapat mengirim video dalam panggilan, Anda perlu membuat LocalVideoStream
objek.
const localVideoStream = new LocalVideoStream(camera);
Kamera yang diteruskan sebagai parameter adalah salah satu objek yang VideoDeviceInfo
dikembalikan oleh deviceManager.getCameras()
metode .
A LocalVideoStream
memiliki properti berikut:
source
: Informasi perangkat.
const source = localVideoStream.source;
mediaStreamType
: Dapat berupaVideo
,ScreenSharing
, atauRawMedia
.
const type: MediaStreamType = localVideoStream.mediaStreamType;
Pratinjau kamera lokal
Anda dapat menggunakan deviceManager
dan VideoStreamRenderer
untuk mulai merender aliran dari kamera lokal Anda.
LocalVideoStream
Setelah dibuat, gunakan untuk menyiapkannyaVideoStreamRenderer
. VideoStreamRenderer
Setelah dibuat, panggil metodenya createView()
untuk mendapatkan tampilan yang dapat Anda tambahkan sebagai anak ke halaman Anda.
Aliran ini tidak dikirim ke peserta lain; ini adalah umpan pratinjau lokal.
// 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);
Menghentikan pratinjau lokal
Untuk menghentikan panggilan pratinjau lokal, buang tampilan yang berasal dari VideoStreamRenderer
.
Setelah VideoStreamRenderer dibuang, hapus tampilan dari pohon html dengan memanggil removeChild()
metode dari Simpul DOM yang berisi pratinjau Anda.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Minta izin ke kamera dan mikrofon
Aplikasi tidak dapat menggunakan kamera atau mikrofon tanpa izin. Anda dapat menggunakan deviceManager untuk meminta pengguna memberikan izin kamera dan/atau mikrofon:
const result = await deviceManager.askDevicePermission({audio: true, video: true});
Setelah janji diselesaikan, metode akan kembali dengan DeviceAccess
objek yang menunjukkan apakah audio
dan video
izin diberikan:
console.log(result.audio);
console.log(result.video);
Catatan
videoDevicesUpdated
peristiwa diaktifkan saat perangkat video dicolokkan/dilepas.audioDevicesUpdated
peristiwa diaktifkan saat perangkat audio dicolokkan.- Saat DeviceManager dibuat, pada awalnya perangkat tidak tahu tentang perangkat apa pun jika izin belum diberikan, jadi awalnya nama perangkatnya kosong dan tidak berisi informasi perangkat terperinci. Jika kita kemudian memanggil API DeviceManager.askPermission(), pengguna akan dimintai akses perangkat. Saat pengguna memilih 'izinkan' untuk memberikan akses yang dipelajari manajer perangkat tentang perangkat pada sistem, perbarui daftar perangkat dan keluarkan peristiwa 'audioDevicesUpdated' dan 'videoDevicesUpdated'. Jika pengguna me-refresh halaman dan membuat manajer perangkat, manajer perangkat dapat mempelajari tentang perangkat karena pengguna memberikan akses sebelumnya. Ini memiliki daftar perangkat yang diisi awalnya dan tidak memancarkan peristiwa 'audioDevicesUpdated' atau 'videoDevicesUpdated'.
- Enumerasi/pilihan pembicara tidak didukung di Android Chrome, iOS Safari, atau macOS Safari.
Melakukan panggilan dengan kamera video
Penting
Saat ini hanya satu aliran video lokal keluar yang didukung.
Untuk melakukan panggilan video, Anda harus menghitung kamera lokal dengan menggunakan metode getCameras()
di deviceManager
.
Setelah Anda memilih kamera, gunakan untuk membuat instans LocalVideoStream
.
Teruskan dalam videoOptions
sebagai item dalam localVideoStream
array ke CallAgent
startCall
metode .
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);
- Anda juga dapat bergabung dengan panggilan dengan video dengan
CallAgent.join()
API, dan menerima dan memanggil dengan video denganCall.Accept()
API. - Saat panggilan Anda tersambung, secara otomatis mulai mengirim aliran video dari kamera yang dipilih ke peserta lain.
Mulai dan berhenti mengirim video lokal saat melakukan panggilan
Mulai video
Untuk memulai video saat melakukan panggilan, Anda harus menghitung kamera menggunakan getCameras
metode pada deviceManager
objek.
Kemudian buat instans baru LocalVideoStream
dengan kamera yang diinginkan, lalu teruskan objek LocalVideoStream
ke dalam metode startVideo
:
const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);
Hentikan Video
Setelah Anda berhasil mulai mengirim video, LocalVideoStream
instans jenis Video
ditambahkan ke localVideoStreams
koleksi pada instans panggilan.
Menemukan aliran video di objek Panggilan
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );
Hentikan video lokal Untuk menghentikan video lokal saat melakukan panggilan, teruskan localVideoStream
instans yang sedang digunakan untuk video ke metode stopVideo dari Call
:
await call.stopVideo(localVideoStream);
Anda dapat beralih ke perangkat kamera yang berbeda saat memiliki LocalVideoStream aktif dengan memanggil switchSource
instans tersebut LocalVideoStream
:
const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);
Jika perangkat video yang ditentukan tidak tersedia:
- Saat dalam panggilan, jika video Anda nonaktif dan Anda memulai video menggunakan
call.startVideo()
, metode ini melemparSourceUnavailableError
diagnostik dancameraStartFailed
pengguna yang menghadap diatur ke true. - Panggilan ke
localVideoStream.switchSource()
metode menyebabkancameraStartFailed
diatur ke true. Panduan Diagnostik Panggilan kami memberikan informasi tambahan tentang cara mendiagnosis masalah terkait panggilan.
Untuk memverifikasi apakah video lokal aktif atau nonaktif, Anda dapat menggunakan Call
metode isLocalVideoStarted
, yang mengembalikan true atau false:
// Check if local video is on or off
call.isLocalVideoStarted;
Untuk mendengarkan perubahan pada video lokal, Anda dapat berlangganan dan berhenti berlangganan peristiwa isLocalVideoStartedChanged:
// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
// Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
// Callback();
});
Memulai dan menghentikan berbagi layar saat melakukan panggilan
Untuk memulai berbagi layar saat melakukan panggilan, Anda dapat menggunakan metode startScreenSharing()
asinkron pada Call
objek:
Mulai berbagi layar
// Start screen sharing
await call.startScreenSharing();
Catatan: Mengirim screenshare hanya didukung di browser desktop.
Temukan berbagi layar dalam koleksi LocalVideoStream
Setelah Anda berhasil mulai mengirim berbagi layar, LocalVideoStream
instans jenis ScreenSharing
, ditambahkan ke localVideoStreams
koleksi pada instans panggilan.
const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );
Hentikan berbagi layar
Untuk menghentikan berbagi layar saat melakukan panggilan, Anda dapat menggunakan stoptScreenSharing API asinkron:
// Stop screen sharing
await call.stopScreenSharing();
Periksa status berbagi layar
Untuk memverifikasi apakah berbagi layar aktif atau nonaktif, Anda dapat menggunakan ISScreenSharingOn API, yang mengembalikan true atau false:
// Check if screen sharing is on or off
call.isScreenSharingOn;
Untuk mendengarkan perubahan pada berbagi layar, Anda dapat berlangganan dan berhenti berlangganan peristiwa isScreenSharingOnChanged:
// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
// Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
// Callback();
});
Penting
Fitur Azure Communication Services ini saat ini dalam pratinjau.
API pratinjau dan SDK disediakan tanpa perjanjian tingkat layanan. Kami menyarankan agar Anda tidak menggunakannya untuk beban kerja produksi. Beberapa fitur mungkin tidak didukung, atau mungkin memiliki kemampuan yang dibatasi.
Untuk informasi selengkapnya, tinjau Ketentuan Penggunaan Tambahan untuk Pratinjau Microsoft Azure.
Pratinjau berbagi layar lokal berada dalam pratinjau publik dan tersedia sebagai bagian dari versi 1.15.1-beta.1+.
Pratinjau berbagi layar lokal
Anda dapat menggunakan VideoStreamRenderer
untuk mulai merender aliran dari berbagi layar lokal sehingga Anda dapat melihat apa yang Anda kirim sebagai aliran berbagi layar.
// 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);
}
});
Merender streaming video/screensharing peserta jarak jauh
Untuk merender video peserta jarak jauh atau berbagi layar, langkah pertama adalah mendapatkan referensi pada RemoteVideoStream yang ingin Anda render.
Ini dapat dilakukan dengan melalui array atau aliran video (videoStreams
) dari RemoteParticipant
. Koleksi peserta jarak jauh diakses melalui Call
objek .
const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;
Untuk merender RemoteVideoStream
, Anda harus berlangganan acaranya isAvailableChanged
. isAvailable
Jika properti berubah menjadi true
, peserta jarak jauh mengirim aliran video.
Setelah itu terjadi, buat instans baru VideoStreamRenderer
, lalu buat instans VideoStreamRendererView
baru dengan menggunakan metode createView
asinkron.
Anda kemudian dapat melampirkan view.target
ke elemen UI mana pun.
Setiap kali ketersediaan aliran jarak jauh berubah, Anda dapat menghancurkan seluruh VideoStreamRenderer
atau tertentu VideoStreamRendererView
.
Jika Anda memutuskan untuk menyimpannya, tampilan akan menampilkan bingkai video kosong.
// 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 untuk menata spinner pemuatan melalui aliran video jarak jauh.
.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); }
}
Kualitas video jarak jauh
Azure Communication Services WebJS SDK, menyediakan fitur yang disebut Optimal Video Count (OVC), mulai versi 1.15.1.
Fitur ini dapat digunakan untuk menginformasikan aplikasi pada run-time tentang berapa banyak video masuk dari peserta yang berbeda dapat dirender secara optimal pada saat tertentu dalam panggilan grup (2+ peserta).
Fitur ini mengekspos properti optimalVideoCount
yang berubah secara dinamis selama panggilan berdasarkan kemampuan jaringan dan perangkat keras dari titik akhir lokal. Nilai optimalVideoCount
detail berapa banyak video dari aplikasi peserta yang berbeda harus dirender pada saat tertentu. Aplikasi harus menangani perubahan ini dan memperbarui jumlah video yang dirender sesuai dengan rekomendasi. Ada periode debounce (sekitar 10 d) di antara setiap pembaruan.
Penggunaan Fitur optimalVideoCount
ini adalah fitur panggilan. Anda perlu mereferensikan fitur OptimalVideoCount
melalui feature
metode Call
objek. Anda kemudian dapat mengatur pendengar melalui on
metode OptimalVideoCountCallFeature
yang akan diberi tahu saat optimalVideoCount berubah. Untuk berhenti berlangganan dari perubahan, Anda dapat memanggil off
metode . Jumlah maksimum video masuk saat ini yang dapat dirender adalah 16. Untuk mendukung 16 video masuk dengan benar, komputer harus memiliki mimimum RAM 16GB dan CPU 4-core atau lebih besar yang berusia tidak lebih dari 3 tahun.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Contoh penggunaan: Aplikasi harus berlangganan perubahan Jumlah Video Optimal dalam panggilan grup. Perubahan jumlah video optimal dapat ditangani dengan membuat perender baru (createView
metode) atau membuang tampilan (dispose
) dan memperbarui tata letak aplikasi yang sesuai.
Properti aliran video jarak jauh
Aliran video jarak jauh memiliki properti berikut:
const id: number = remoteVideoStream.id;
id
: ID aliran video jarak jauh.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
mediaStreamType
: Dapat berupaVideo
atauScreenSharing
.
const isAvailable: boolean = remoteVideoStream.isAvailable;
isAvailable
: Menentukan apakah titik akhir peserta jarak jauh secara aktif mengirim aliran.
const isReceiving: boolean = remoteVideoStream.isReceiving;
isReceiving
:Menginformasikan aplikasi jika data aliran video jarak jauh diterima atau tidak.
Bendera berpindah ke
false
dalam skenario berikut:- Peserta jarak jauh yang berada di browser seluler membawa aplikasi browser ke latar belakang.
- Peserta jarak jauh atau pengguna yang menerima video memiliki masalah jaringan yang memengaruhi kualitas video secara drastis.
- Peserta jarak jauh yang berada di macOS/iOS Safari memilih "Jeda" dari bilah alamat mereka.
- Peserta jarak jauh mengalami pemutusan jaringan.
- Peserta jarak jauh di ponsel membunuh atau mengakhiri browser.
- Peserta jarak jauh di ponsel atau desktop mengunci perangkatnya. Skenario ini juga berlaku jika peserta jarak jauh berada di komputer desktop dan tidur.
Bendera berpindah ke
true
dalam skenario berikut:- Peserta jarak jauh yang berada di browser seluler dan memiliki latar belakang browsernya membawanya kembali ke latar depan.
- Peserta jarak jauh yang berada di macOS/iOS Safari memilih "Lanjutkan" dari bilah alamat mereka setelah menjeda videonya.
- Peserta jarak jauh tersambung kembali ke jaringan setelah pemutusan sambungan sementara.
- Peserta jarak jauh di ponsel membuka kunci perangkatnya dan kembali ke panggilan di browser selulernya.
Fitur ini meningkatkan pengalaman pengguna untuk merender aliran video jarak jauh.
Anda dapat menampilkan spinner pemuatan melalui aliran video jarak jauh saat bendera isReceiving berubah menjadi false. Anda tidak perlu menerapkan pemuatan spinner, tetapi spinner pemuatan adalah penggunaan paling umum untuk pengalaman pengguna yang lebih baik.
const size: StreamSize = remoteVideoStream.size;
size
: Ukuran streaming dengan informasi tentang lebar dan tinggi video.
Metode dan properti VideoStreamRenderer
await videoStreamRenderer.createView();
Buat VideoStreamRendererView
instans yang dapat dilampirkan di antarmuka pengguna aplikasi untuk merender aliran video jarak jauh, menggunakan metode asinkron createView()
, itu menyelesaikan ketika aliran siap untuk merender dan mengembalikan objek dengan target
properti yang mewakili video
elemen yang dapat dimasukkan di mana saja di pohon DOM.
videoStreamRenderer.dispose();
Buang videoStreamRenderer
dan semua instans terkait VideoStreamRendererView
.
Metode dan properti VideoStreamRendererView
Saat membuat VideoStreamRendererView
, Anda dapat menentukan properti scalingMode
dan isMirrored
. scalingMode
dapat berupa Stretch
, Crop
, atau Fit
. Jika isMirrored
ditentukan, aliran yang dirender dibalik secara vertikal.
const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });
Setiap instans VideoStreamRendererView
memiliki properti target
yang mewakili permukaan penyajian. Melampirkan properti ini di UI aplikasi:
htmlElement.appendChild(view.target);
Anda dapat memperbarui scalingMode
dengan menerapkan metode updateScalingMode
:
view.updateScalingMode('Crop');
Kirim streaming video dari dua kamera berbeda, dalam panggilan yang sama dari perangkat desktop yang sama.
Penting
Fitur Azure Communication Services ini saat ini dalam pratinjau.
API pratinjau dan SDK disediakan tanpa perjanjian tingkat layanan. Kami menyarankan agar Anda tidak menggunakannya untuk beban kerja produksi. Beberapa fitur mungkin tidak didukung, atau mungkin memiliki kemampuan yang dibatasi.
Untuk informasi selengkapnya, tinjau Ketentuan Penggunaan Tambahan untuk Pratinjau Microsoft Azure.
Kirim aliran video dari dua kamera berbeda dalam panggilan yang sama didukung sebagai bagian dari versi 1.17.1-beta.1+ pada browser yang didukung desktop.
- Anda dapat mengirim aliran video dari dua kamera berbeda dari satu tab/aplikasi browser desktop, dalam panggilan yang sama, dengan cuplikan kode berikut:
// 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();
Batasan:
- Ini harus dilakukan dengan dua instans yang berbeda
CallAgent
menggunakan identitas yang berbeda. Cuplikan kode menunjukkan dua agen panggilan yang digunakan, masing-masing dengan objek Panggilannya sendiri. - Dalam contoh kode, kedua CallAgents bergabung dengan panggilan yang sama (ID panggilan yang sama). Anda juga dapat menggabungkan panggilan yang berbeda dengan setiap agen dan mengirim satu video dalam satu panggilan dan video yang berbeda di panggilan lain.
- Mengirim kamera yang sama di kedua CallAgent, tidak didukung. Mereka harus dua kamera yang berbeda.
- Mengirim dua kamera berbeda dengan satu CallAgent saat ini tidak didukung.
- Di macOS Safari, efek video kabur latar belakang (dari @azure/communication-effects), hanya dapat diterapkan ke satu kamera, dan bukan keduanya secara bersamaan.
Pasang SDK
Temukan file tingkat build.gradle
proyek Anda dan tambahkan mavenCentral()
ke daftar repositori di bawah buildscript
dan allprojects
:
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Kemudian, dalam file tingkat build.gradle
modul Anda, tambahkan baris berikut ke bagian dependencies
:
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0'
...
}
Menginisialisasi objek yang diperlukan
Untuk membuat CallAgent
instans, Anda harus memanggil createCallAgent
metode pada CallClient
instans. Panggilan ini secara asinkron mengembalikan objek instans CallAgent
.
Metode ini createCallAgent
mengambil CommunicationUserCredential
sebagai argumen, yang merangkum token akses.
Untuk mengakses DeviceManager
, Anda harus membuat instans terlebih callAgent
dahulu. Kemudian Anda dapat menggunakan CallClient.getDeviceManager
metode untuk mendapatkan 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();
Untuk mengatur nama tampilan penelepon, gunakan metode alternatif ini:
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();
Manajemen perangkat
Untuk mulai menggunakan video dengan Panggilan, Anda perlu mengetahui cara mengelola perangkat. Perangkat memungkinkan Anda untuk mengontrol apa yang mentransmisikan Audio dan Video ke panggilan.
DeviceManager
memungkinkan Anda menghitung perangkat lokal yang dapat digunakan dalam panggilan untuk mengirimkan aliran audio/video Anda. Hal ini juga memungkinkan Anda untuk meminta izin dari pengguna untuk mengakses mikrofon dan kamera mereka menggunakan API browser asli.
Anda dapat mengakses deviceManager
dengan memanggil callClient.getDeviceManager()
metode.
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Hitung perangkat lokal
Untuk mengakses perangkat lokal, Anda dapat menggunakan metode enumerasi di Manajer Perangkat. Enumerasi adalah tindakan sinkron.
// Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]
Pratinjau kamera lokal
Anda dapat menggunakan DeviceManager
dan Renderer
untuk mulai merender aliran dari kamera lokal Anda. Aliran ini tidak akan dikirim ke peserta lain; ini adalah umpan pratinjau lokal. Ini adalah tindakan asinkron.
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);
Lakukan panggilan 1:1 dengan kamera video
Peringatan
Saat ini hanya satu aliran video lokal keluar yang didukung. Untuk melakukan panggilan dengan video, Anda harus menghitung kamera lokal menggunakan API deviceManager
getCameras
.
Setelah Anda memilih kamera yang diinginkan, gunakan untuk membuat instans LocalVideoStream
dan teruskan ke videoOptions
sebagai item dalam array localVideoStream
ke metode call
.
Setelah panggilan tersambung, panggilan akan secara otomatis mulai mengirim stream video dari kamera yang dipilih ke peserta lain.
Catatan
Karena masalah privasi, video tidak akan dibagikan ke panggilan jika tidak dipratinjau secara lokal. Lihat Pratinjau kamera lokal untuk detail selengkapnya.
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);
Mulai dan berhenti mengirim video lokal
Untuk memulai video, Anda harus menghitung kamera menggunakan getCameraList
API pada deviceManager
objek. Kemudian buat instans baru LocalVideoStream
yang meneruskan kamera yang diinginkan, dan meneruskannya di API startVideo
sebagai argumen:
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();
Setelah Anda berhasil memulai mengirim video, instans LocalVideoStream
akan ditambahkan ke localVideoStreams
koleksi pada instans panggilan.
List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).
Untuk menghentikan video lokal, teruskan LocalVideoStream
instans yang tersedia dalam localVideoStreams
koleksi:
call.stopVideo(appContext, currentLocalVideoStream).get();
Anda dapat beralih ke perangkat kamera lain saat video dikirim dengan memanggil switchSource
di LocalVideoStream
instans:
currentLocalVideoStream.switchSource(source).get();
Merender aliran video peserta jarak jauh
Untuk mencantumkan aliran video dan aliran berbagi layar peserta jarak jauh, periksa videoStreams
koleksi:
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
Untuk merender RemoteVideoStream
dari peserta jarak jauh, Anda harus berlangganan ke OnVideoStreamsUpdated
peristiwa.
Dalam peristiwa tersebut, perubahan isAvailable
properti menjadi true menunjukkan bahwa peserta jarak jauh saat ini sedang mengirim aliran. Setelah itu terjadi, buat instans baru Renderer
, lalu buat baru RendererView
menggunakan API createView
asinkron baru dan lampirkan view.target
di mana saja di UI aplikasi Anda.
Setiap kali ketersediaan perubahan aliran jarak jauh, Anda dapat memilih untuk menghancurkan seluruh Renderer, tertentu RendererView
atau menyimpannya, tetapi hal ini akan mengakibatkan menampilkan bingkai video kosong.
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();
}
}
}
Properti aliran video jarak jauh
Aliran video jarak jauh memiliki beberapa properti
Id
- ID aliran video jarak jauh
int id = remoteVideoStream.getId();
MediaStreamType
- Bisa berupa 'Video' atau 'ScreenSharing'
MediaStreamType type = remoteVideoStream.getMediaStreamType();
isAvailable
- Menunjukkan apakah titik akhir peserta jarak jauh secara aktif mengirim aliran
boolean availability = remoteVideoStream.isAvailable();
Metode dan properti renderer
Objek render mengikuti API
- Buat
VideoStreamRendererView
instans yang nantinya dapat dilampirkan di UI aplikasi untuk merender aliran video jarak jauh.
// Create a view for a video stream
VideoStreamRendererView.createView()
- Buang perender dan semua
VideoStreamRendererView
yang terkait dengan perender ini. Untuk dipanggil ketika Anda telah menghapus semua tampilan terkait dari UI.
VideoStreamRenderer.dispose()
StreamSize
- ukuran (lebar/tinggi) aliran video jarak jauh
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();
Metode dan properti RendererView
Saat membuat VideoStreamRendererView
, Anda dapat menentukan properti ScalingMode
dan mirrored
yang akan berlaku untuk tampilan ini: Mode penskalaan dapat berupa salah satu dari 'CROP' | 'FIT'
VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));
RendererView yang dibuat kemudian dapat dilampirkan ke UI aplikasi menggunakan cuplikan berikut:
layout.addView(rendererView);
Anda nantinya dapat memperbarui mode penskalaan dengan memanggil API updateScalingMode
pada objek RendererView dengan salah satu ScalingMode.CROP | ScalingMode.FIT sebagai argumen.
// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)
Siapkan sistem Anda
Ikuti langkah-langkah ini untuk menyiapkan sistem Anda.
Buat proyek Xcode
Di Xcode, buat proyek iOS baru dan pilih templat Aplikasi Tampilan Tunggal. Artikel ini menggunakan kerangka kerja SwiftUI, jadi Anda harus mengatur Bahasa ke Swift dan mengatur Antarmuka ke SwiftUI.
Anda tidak akan membuat pengujian di artikel ini. Jangan ragu untuk menghapus kotak centang Sertakan Pengujian.
Pasang paket dan dependensi dengan menggunakan CocoaPods
Buat Podfile untuk aplikasi Anda, seperti contoh ini:
platform :ios, '13.0' use_frameworks! target 'AzureCommunicationCallingSample' do pod 'AzureCommunicationCalling', '~> 1.0.0' end
Jalankan
pod install
.Buka
.xcworkspace
dengan menggunakan Xcode.
Minta akses ke mikrofon
Untuk mengakses mikrofon perangkat, Anda perlu memperbarui daftar properti informasi aplikasi dengan menggunakan NSMicrophoneUsageDescription
. Atur nilai terkait ke string yang disertakan dalam dialog yang digunakan sistem untuk meminta akses dari pengguna.
Klik kanan entri Info.plist dari pohon proyek, lalu pilih Buka Sebagai>Kode Sumber. Tambahkan baris berikut ke bagian <dict>
tingkat atas, lalu simpan file.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
Menyiapkan kerangka kerja aplikasi
Buka file proyek ContentView.swift
Anda. import
Tambahkan deklarasi ke bagian atas file untuk mengimpor AzureCommunicationCalling
pustaka. Selain itu, impor AVFoundation
. Anda memerlukannya untuk permintaan izin audio dalam kode.
import AzureCommunicationCalling
import AVFoundation
Inisialisasi CallAgent
Untuk membuat CallAgent
instans dari CallClient
, Anda harus menggunakan callClient.createCallAgent
metode yang secara asinkron mengembalikan CallAgent
objek setelah diinisialisasi.
Untuk membuat klien panggilan, berikan CommunicationTokenCredential
objek:
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)
}
Teruskan CommunicationTokenCredential
objek yang Anda buat ke CallClient
, dan atur nama tampilan:
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")
}
})
Kelola perangkat
Untuk mulai menggunakan video dengan Panggilan, Anda perlu mengetahui cara mengelola perangkat. Perangkat memungkinkan Anda untuk mengontrol apa yang mentransmisikan Audio dan Video ke panggilan.
DeviceManager
memungkinkan Anda menghitung perangkat lokal yang dapat digunakan dalam panggilan untuk mengirimkan aliran audio/video Anda. Pengelolaan perangkat juga memungkinkan Anda untuk meminta izin akses dari pengguna untuk mengakses mikrofon atau kamera. Anda dapat mengakses deviceManager
pada callClient
objek.
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")
}
}
Hitung perangkat lokal
Untuk mengakses perangkat lokal, Anda dapat menggunakan metode enumerasi di manajer perangkat. Enumerasi adalah tindakan sinkron.
// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]
Dapatkan pratinjau kamera lokal
Anda dapat menggunakannya Renderer
untuk mulai merender aliran dari kamera lokal Anda. Aliran ini tidak akan dikirim ke peserta lain; ini adalah umpan pratinjau lokal. Ini adalah tindakan asinkron.
let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()
Dapatkan properti pratinjau kamera lokal
Penyaji memiliki sekumpulan properti dan metode yang memungkinkan Anda mengontrol penyajian.
// 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()
Lakukan panggilan 1:1 dengan video
Untuk mendapatkan instans manajer perangkat, lihat bagian tentang mengelola perangkat.
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")
}
}
Merender aliran video peserta jarak jauh
Peserta jarak jauh dapat memulai berbagi video atau layar selama panggilan.
Handel berbagi video atau streaming berbagi layar peserta jarak jauh
Untuk mencantumkan aliran peserta jarak jauh, periksa videoStreams
koleksi.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Dapatkan properti aliran video jarak jauh
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
Render aliran peserta jarak jauh
Untuk mulai merender aliran peserta jarak jauh, gunakan kode berikut.
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)
Dapatkan metode dan properti penyaji video jarak jauh
// [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()
Siapkan sistem Anda
Ikuti langkah-langkah ini untuk menyiapkan sistem Anda.
Membuat proyek Visual Studio
Untuk aplikasi Platform Windows Universal, di Visual Studio 2022, buat proyek Aplikasi Kosong (Universal Windows) baru. Setelah Anda memasukkan nama proyek, jangan ragu untuk memilih Windows SDK apa pun yang lebih baru dari 10.0.17763.0.
Untuk aplikasi WinUI 3, buat proyek baru dengan templat Aplikasi Kosong, Dipaketkan (WinUI 3 di Desktop) untuk menyiapkan aplikasi WinUI 3 satu halaman. SDK Aplikasi Windows versi 1.3 atau yang lebih baru diperlukan.
Instal paket dan dependensi dengan menggunakan NuGet Package Manager
API dan pustaka SDK Panggilan tersedia untuk umum melalui paket NuGet.
Untuk menemukan, mengunduh, dan menginstal paket Calling SDK NuGet:
- Buka Manajer Paket NuGet dengan memilih Alat>Pengelola>Paket NuGet Kelola Paket NuGet untuk Solusi.
- Pilih Telusuri, lalu masukkan Azure.Communication.Calling.WindowsClient di kotak pencarian.
- Pastikan bahwa kotak centang Sertakan prarilis dipilih.
- Pilih paket Azure.Communication.Calling.WindowsClient, lalu pilih Azure.Communication.Calling.WindowsClient 1.4.0-beta.1 atau versi yang lebih baru.
- Pilih kotak centang yang sesuai dengan proyek Azure Communication Services di panel kanan.
- Pilih Instal.
Minta akses ke mikrofon
Aplikasi ini memerlukan akses ke kamera untuk berjalan dengan benar. Di aplikasi UWP, kemampuan kamera harus dideklarasikan dalam file manifes aplikasi.
Langkah-langkah berikut mencontohkan cara mencapainya.
- Di panel
Solution Explorer
, klik dua kali pada file dengan ekstensi.appxmanifest
. - Klik tab
Capabilities
. - Pilih kotak centang
Camera
dari daftar kapabilitas.
Buat tombol UI untuk membuat dan menutup panggilan
Aplikasi sampel sederhana ini berisi dua tombol. Satu untuk membuat panggilan dan satu lagi untuk menutup panggilan. Langkah-langkah berikut menunjukkan contoh cara menambahkan tombol ini ke aplikasi.
- Di panel
Solution Explorer
, klik dua kali pada file bernamaMainPage.xaml
untuk UWP, atauMainWindows.xaml
untuk WinUI 3. - Di panel tengah, cari kode XMAL di bawah pratinjau UI.
- Ubah kode XAML dengan kutipan berikut:
<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>
Menyiapkan aplikasi dengan Calling SDK API
Calling SDK API berada di dua namespace yang berbeda. Langkah-langkah berikut memberikan informasi untuk pengompilasi C# tentang namespace layanan ini yang memungkinkan Intellisense Visual Studio membantu pengembangan kode.
- Di panel
Solution Explorer
, klik panah di sisi kiri file bernamaMainPage.xaml
untuk UWP, atauMainWindows.xaml
untuk WinUI 3. - Klik dua kali pada file bernama
MainPage.xaml.cs
atauMainWindows.xaml.cs
. - Tambahkan perintah berikut di bagian bawah pernyataan
using
saat ini.
using Azure.Communication.Calling.WindowsClient;
Simpan MainPage.xaml.cs
atau MainWindows.xaml.cs
buka. Langkah-langkah berikutnya akan menambahkan lebih banyak kode ke dalamnya.
Mengizinkan interaksi aplikasi
Tombol UI yang sebelumnya ditambahkan perlu dioperasikan di atas CommunicationCall
yang ditempatkan. Ini berarti bahwa CommunicationCall
anggota data harus ditambahkan ke MainPage
kelas atau MainWindow
.
Selain itu, untuk memungkinkan operasi asinkron yang membuat CallAgent
berhasil, data anggota CallAgent
juga harus ditambahkan ke kelas yang sama.
Tambahkan anggota data berikut ke MainPage
kelas atau MainWindow
:
CallAgent callAgent;
CommunicationCall call;
Membuat pengatur tombol
Sebelumnya, dua tombol UI ditambahkan ke kode XAML. Kode berikut menambahkan pengatur untuk dieksekusi saat pengguna memilih tombol. Kode berikut harus ditambahkan setelah anggota data dari bagian sebelumnya.
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 objek
Kelas dan antarmuka berikut menangani beberapa fitur utama dari pustaka klien Azure Communication Services Calling untuk UWP.
Nama | Deskripsi |
---|---|
CallClient |
CallClient adalah titik masuk utama ke pustaka klien Panggilan. |
CallAgent |
CallAgent digunakan untuk memulai dan menggabungkan panggilan. |
CommunicationCall |
CommunicationCall digunakan untuk mengelola panggilan yang ditempatkan atau digabungkan. |
CommunicationTokenCredential |
CommunicationTokenCredential digunakan sebagai kredensial token untuk membuat instans CallAgent . |
CallAgentOptions |
berisi CallAgentOptions informasi untuk mengidentifikasi pemanggil. |
HangupOptions |
Menginformasikan HangupOptions apakah panggilan harus dihentikan kepada semua pesertanya. |
Mendaftarkan handler skema video
Komponen UI, seperti MediaElement XAML atau MediaPlayerElement, Anda memerlukan aplikasi yang mendaftarkan konfigurasi untuk merender umpan video lokal dan jarak jauh.
Tambahkan konten berikut di Package
antara tag Package.appxmanifest
:
<Extensions>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>RtmMvrUap.dll</Path>
<ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
Menginisialisasi CallAgent
Untuk membuat CallAgent
instans dari CallClient
, Anda harus menggunakan CallClient.CreateCallAgentAsync
metode yang secara asinkron mengembalikan CallAgent
objek setelah diinisialisasi.
Untuk membuat CallAgent
, Anda harus melewati objek CallTokenCredential
dan objek CallAgentOptions
. Perlu diingat bahwa CallTokenCredential
melempar jika token cacat dilewati.
Kode berikut harus ditambahkan di dalam dan fungsi pembantu untuk dipanggil dalam inisialisasi aplikasi.
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>
Ubah dengan token kredensial yang valid untuk sumber daya Anda. Lihat dokumentasi token akses pengguna jika token info masuk harus memiliki sumber.
Lakukan panggilan 1:1 dengan kamera video
Objek yang diperlukan untuk membuat CallAgent
sekarang sudah siap. Saatnya membuat dan melakukan panggilan video secara CallAgent
asinkron.
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 } }
};
}
Pratinjau kamera lokal
Kita dapat secara opsional menyiapkan pratinjau kamera lokal. Video dapat dirender melalui MediaPlayerElement
:
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
Untuk menginisialisasi pratinjau MediaPlayerElement
lokal :
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);
}
}
Merender aliran kamera jarak jauh
Siapkan bahkan handler sebagai respons terhadap OnCallsUpdated
peristiwa:
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;
}
}
Mulai merender aliran video jarak jauh pada 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;
}
}
Mengakhiri panggilan
Setelah panggilan dilakukan, metode HangupAsync
objek CommunicationCall
harus digunakan untuk menutup panggilan.
Instans HangupOptions
juga harus digunakan untuk menginformasikan apakah panggilan harus diakhiri kepada semua pesertanya.
Kode berikut harus ditambahkan di dalam 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;
}
}
}
}
Menjalankan kode
Pastikan Visual Studio membuat aplikasi untuk x64
, x86
atau ARM64
, lalu tekan F5
untuk mulai menjalankan aplikasi. Setelah itu, klik tombol CommunicationCall
untuk melakukan panggilan ke penerima panggilan yang ditentukan.
Perlu diingat bahwa pertama kali aplikasi berjalan, sistem meminta pengguna untuk memberikan akses ke mikrofon.