Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pelajari cara mengelola panggilan video 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 Layanan Komunikasi yang disebarkan. Buat sumber daya 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
Gunakan perintah npm install 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.
Dengan instans CallClient, Anda dapat membuat instans CallAgent dengan melakukan pemanggilan 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()
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 AgentConnected connectionStatue berarti SDK klien terhubung dan mampu menerima pemberitahuan dari infrastruktur Microsoft.
Terputus - Nilai Call AgentDisconnected status connectionStatue ada masalah yang mencegah SDK menyambungkannya dengan benar.
Call Agent harus dibuat ulang.
-
invalidToken: Jika token kedaluwarsa atau tidak valid, instansCall Agentakan terputus dengan kesalahan ini. -
connectionIssue: Jika ada masalah dengan klien yang terhubung ke infrastruktur Microsoft, setelah banyak percobaan ulangCall Agentmengekspos kesalahanconnectionIssue.
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 event connectionStateChanged untuk menentukan apakah Call Agent berubah dari status Terhubung 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 mengontrol apa yang mengirimkan Audio dan Video ke panggilan.
deviceManager Gunakan untuk menghitung perangkat lokal yang dapat mengirimkan streaming 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
Anda dapat menggunakan metode enumerasi deviceManager, getCameras(), dan getMicrophones untuk mengakses perangkat lokal. 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]);
Penyaji
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 Microphone User Facing Diagnostics (UFD) mungkin dipicu dan mikrofon dapat berhenti berfungsi, tergantung pada browser dan OS yang digunakan.
Aliran video lokal
Agar pengguna dapat mengirim video dalam panggilan, Anda harus membuat LocalVideoStream objek.
const localVideoStream = new LocalVideoStream(camera);
Kamera yang diteruskan sebagai parameter adalah objek VideoDeviceInfo yang dikembalikan oleh metode deviceManager.getCameras().
A LocalVideoStream memiliki properti berikut:
sourceadalah informasi perangkat.const source = localVideoStream.source;mediaStreamTypedapat 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.
Setelah membuat LocalVideoStream, gunakan untuk menyiapkanVideoStreamRenderer. Setelah Anda membuat VideoStreamRenderer, panggil metode createView() untuk mendapatkan tampilan yang dapat Anda tambahkan sebagai elemen anak ke halaman Anda.
Aliran ini tidak dikirim ke peserta lain. Umpan pratinjau ini bersifat 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);
Hentikan pratinjau lokal
Untuk menghentikan panggilan pratinjau lokal, buang tampilan yang berasal dari VideoStreamRenderer.
Setelah VideoStreamRenderer diakhiri, hapus tampilan dari pohon HTML dengan memanggil metode removeChild() pada Node DOM yang berisi pratinjau Anda.
// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);
Minta izin untuk 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 terpenuhi, metode akan mengembalikan sebuah objek DeviceAccess yang menunjukkan apakah izin audio dan video telah diberikan.
console.log(result.audio);
console.log(result.video);
Catatan
-
videoDevicesUpdatedacara diaktifkan saat perangkat video dihubungkan/dilepas. -
audioDevicesUpdatedperistiwa terjadi saat perangkat audio dicolokkan. - Ketika Anda pertama kali membuat
DeviceManager, ia tidak mengenali perangkat apa pun jika izin belum diberikan. Awalnya nama perangkatnya kosong dan tidak berisi informasi perangkat terperinci. Anda perlu memanggilDeviceManager.askPermission(), yang meminta pengguna untuk akses perangkat. Saat pengguna mengizinkan akses, manajer perangkat mempelajari perangkat pada sistem, memperbarui daftar perangkat, dan mengirimkan peristiwaaudioDevicesUpdateddanvideoDevicesUpdated. Jika pengguna me-refresh halaman dan membuat manajer perangkat, manajer perangkat mempelajari tentang perangkat karena pengguna sebelumnya memberikan akses. Ini memiliki daftar perangkat yang diisi sejak awal dan tidak memancarkanaudioDevicesUpdatedatauvideoDevicesUpdatedevent. - Enumerasi/pilihan pembicara tidak didukung di Android Chrome, iOS Safari, atau macOS Safari.
Melakukan panggilan dengan kamera video
Penting
Saat ini hanya didukung satu aliran video lokal yang keluar.
Untuk melakukan panggilan video, Anda harus menghitung kamera lokal dengan menggunakan metode getCameras() di deviceManager.
Setelah Anda memilih kamera, gunakan itu untuk membuat instans LocalVideoStream.
Masukkan dalam videoOptions sebagai item dalam array localVideoStream ke metode CallAgentstartCall.
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 dalam panggilan video menggunakan
CallAgent.join()API, serta menerima dan melakukan panggilan 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, sebuah instans tipe LocalVideoStream ditambahkan ke koleksi Video 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 melemparSourceUnavailableErrordiagnostik dancameraStartFailedpengguna yang menghadap diatur ke true. - Panggilan ke
localVideoStream.switchSource()metode menyebabkancameraStartFaileddiatur 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 untuk 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 memantau perubahan pada berbagi layar, Anda dapat berlangganan dan membatalkan langganan ke 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. Fitur dalam pratinjau tersedia untuk umum dan dapat digunakan oleh semua pelanggan Microsoft baru dan yang sudah ada.
API pratinjau dan SDK disediakan tanpa perjanjian tingkat layanan. Kami menyarankan agar Anda tidak menggunakannya untuk beban kerja produksi. Fitur tertentu mungkin tidak didukung atau kemampuan mungkin dibatasi.
Untuk informasi lebih lanjut, lihat Supplemental Terms of Use for Microsoft Azure Previews.
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 stopped 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);
}
});
Menampilkan video dan berbagi layar peserta jarak jauh.
Untuk merender video peserta jarak jauh atau berbagi layar, langkah pertama adalah mendapatkan referensi pada RemoteVideoStream yang ingin Anda render.
Anda hanya dapat merender peserta jarak jauh melalui array atau streaming 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 . Jika properti isAvailable berubah menjadi true, maka peserta jarak jauh mengirim aliran video.
Setelah itu terjadi, buat instans VideoStreamRendererbaru , lalu buat instans baru VideoStreamRendererView menggunakan metode asinkron createView . Anda kemudian dapat melampirkan view.target ke elemen UI mana pun.
Setiap kali ketersediaan aliran jarak jauh berubah, Anda dapat menghancurkan keseluruhan VideoStreamRenderer atau sebuah VideoStreamRendererView tertentu. 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 mengatur loading spinner di atas 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
SDK WebJS Azure Communication Services menyediakan fitur yang disebut Optimal Video Count (OVC), mulai versi 1.15.1.
Gunakan fitur ini untuk menginformasikan aplikasi saat waktu proses berjalan tentang berapa banyak video masuk dari anggota yang berbeda dapat dirender secara optimal pada saat tertentu dalam panggilan grup dengan dua (2) atau lebih peserta.
Fitur ini mengekspos properti optimalVideoCount yang berubah secara dinamis selama panggilan berdasarkan kemampuan jaringan dan perangkat keras dari titik akhir lokal. Nilai optimalVideoCount menunjukkan jumlah video dari berbagai aplikasi peserta yang harus dirender pada waktu tertentu. Aplikasi harus menangani perubahan ini dan memperbarui jumlah video yang dirender sesuai dengan rekomendasi. Ada periode debounce (sekitar sepuluh (10) detik) di antara setiap pembaruan.
Penggunaan
optimalVideoCount adalah sebuah fitur panggilan. Anda perlu mereferensikan fitur OptimalVideoCount melalui feature metode Call objek.
Anda kemudian dapat menetapkan pendengar melalui metode on dari OptimalVideoCountCallFeature untuk diberi tahu ketika 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 membutuhkan RAM minimal 16 GB dan CPU inti empat (4) atau lebih besar yang berusia kurang dari tiga (3) tahun.
const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})
Contoh penggunaan: Aplikasi Anda berlangganan perubahan Jumlah Video Optimal dalam panggilan grup. Perubahan jumlah video optimal ditangani dengan membuat metode perender createView baru 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 berupaVideoatauScreenSharing.
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
falsedalam 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
truedalam 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 video.
- 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, stream 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. Fitur dalam pratinjau tersedia untuk umum dan dapat digunakan oleh semua pelanggan Microsoft baru dan yang sudah ada.
API pratinjau dan SDK disediakan tanpa perjanjian tingkat layanan. Kami menyarankan agar Anda tidak menggunakannya untuk beban kerja produksi. Fitur tertentu mungkin tidak didukung atau kemampuan mungkin dibatasi.
Untuk informasi lebih lanjut, lihat Supplemental Terms of Use for Microsoft Azure Previews.
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:
- Mengirim aliran video harus dilakukan dengan dua instans yang berbeda
CallAgentmenggunakan 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 CallAgents tidak didukung. Mereka pasti 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 instans CallAgent, Anda harus mengaktifkan metode createCallAgent pada instans CallClient. Panggilan ini secara asinkron mengembalikan objek instans CallAgent .
Metode createCallAgent mengambil CommunicationUserCredential sebagai argumen, yang merangkum token akses.
Untuk mengakses DeviceManager, Anda harus terlebih dahulu membuat instans callAgent. 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 menggunakan video dengan Panggilan, Anda perlu mengelola perangkat. Menggunakan perangkat memungkinkan Anda mengontrol apa yang mengirimkan Audio dan Video ke panggilan.
Objek ini DeviceManager memungkinkan Anda menghitung perangkat lokal untuk digunakan dalam panggilan untuk mengirimkan aliran audio/video Anda. Ini juga memungkinkan Anda untuk meminta izin dari pengguna untuk mengakses mikrofon dan kamera mereka menggunakan API browser asli.
Untuk mengakses deviceManager, panggil metode callClient.getDeviceManager().
Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
Hitung perangkat lokal
Untuk mengakses perangkat lokal, gunakan metode enumerasi pada 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 dikirim ke peserta lain. Umpan pratinjau ini bersifat lokal. Merenderkan aliran adalah tindakan yang bersifat 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 didukung satu aliran video lokal yang keluar. Untuk melakukan panggilan dengan video, Anda harus menghitung kamera lokal menggunakan deviceManagergetCameras API.
Setelah Anda memilih kamera, gunakan itu untuk membuat instans LocalVideoStream dan meneruskannya ke dalam array videoOptions sebagai item localVideoStream untuk metode call. Setelah panggilan tersambung, panggilan secara otomatis mulai mengirim aliran video dari kamera yang dipilih ke peserta lain.
Catatan
Karena masalah privasi, video tidak dibagikan ke panggilan jika tidak dipratinjau secara lokal. Untuk informasi selengkapnya, lihat Pratinjau kamera lokal.
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 mengidentifikasi kamera menggunakan operasi getCameraList pada objek deviceManager. 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 mulai mengirim video, LocalVideoStream instans 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, oper instance LocalVideoStream yang tersedia dalam koleksi localVideoStreams.
call.stopVideo(appContext, currentLocalVideoStream).get();
Anda dapat beralih ke perangkat kamera lain saat video dikirim dengan memanggil switchSource di LocalVideoStreaminstans:
currentLocalVideoStream.switchSource(source).get();
Merender aliran video peserta jarak jauh
Untuk mencantumkan aliran video dan aliran berbagi layar dari peserta jarak jauh, periksa kumpulan videoStreams.
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 mengikuti OnVideoStreamsUpdated event.
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 RendererView baru menggunakan API createView asinkron dan lampirkan view.target di UI aplikasi Anda di mana saja.
Setiap kali ketersediaan streaming jarak jauh berubah, Anda dapat memilih untuk menghancurkan seluruh Renderer, sebuah RendererView tertentu, atau menyimpannya, tetapi hal itu akan mengakibatkan tampilan 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 properti berikut:
Id- ID aliran video jarak jauh.int id = remoteVideoStream.getId();MediaStreamType- BisaVideoatauScreenSharing.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 Renderer menggunakan metode berikut.
Untuk merender aliran video jarak jauh, buat
VideoStreamRendererViewinstans yang nantinya dapat dilampirkan di antarmuka pengguna aplikasi.// Create a view for a video stream VideoStreamRendererView.createView()Buang perender dan semua
VideoStreamRendererViewyang terkait dengan perender ini. Panggil setelah Anda menghapus semua tampilan terkait dari antarmuka pengguna.VideoStreamRenderer.dispose()Untuk mengatur ukuran (lebar/tinggi) aliran video jarak jauh, gunakan
StreamSize.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 berlaku untuk tampilan ini.
Mode penskalaan dapat berupa salah satu dari CROP atau 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 menggunakan updateScalingMode operasi pada RendererView objek dengan argumen baik ScalingMode.CROP atau ScalingMode.FIT.
// 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' endJalankan
pod install.Buka
.xcworkspacedengan 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. Tambahkan import deklarasi ke bagian atas file untuk mengimpor pustaka AzureCommunicationCalling. Selain itu, impor AVFoundation. Anda memerlukannya untuk permintaan izin audio dalam kode.
import AzureCommunicationCalling
import AVFoundation
Inisialisasi CallAgent
Untuk membuat instans CallAgent dari CallClient, Anda harus menggunakan metode callClient.createCallAgent yang mengembalikan objek CallAgent secara asinkron 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 tahu cara mengelola perangkat. Perangkat memungkinkan Anda mengontrol apa yang mengirimkan Audio dan Video ke panggilan.
DeviceManager memungkinkan Anda menghitung perangkat lokal yang dapat digunakan dalam panggilan untuk mengirimkan aliran audio/video Anda. Ini juga memungkinkan Anda untuk meminta izin 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 tampilan kamera lokal
Anda dapat menggunakan Renderer untuk mulai memproses aliran dari kamera lokal Anda. Aliran ini tidak ditujukan untuk partisipan 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
Perender mencakup 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.
Tangani streaming video atau streaming berbagi layar peserta jarak jauh
Untuk mencantumkan aliran dari peserta jarak jauh, periksa kumpulan videoStreams.
var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]
Dapatkan properti aliran video dari 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
Menampilkan stream peserta jarak jauh
Untuk mulai merender stream peserta yang terhubung secara 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 template Blank App, Packaged (WinUI 3 di Desktop) untuk membuat 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>Manajer 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.WindowsClient1.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. Di aplikasi Universal Windows Platform (UWP), Anda perlu mendeklarasikan kemampuan kamera dalam file manifes aplikasi.
- Buka proyek di Visual Studio.
- Di panel Penjelajah Solusi , klik dua kali pada file dengan
.appxmanifestekstensi. - Klik tab Kapabilitas .
- Pilih kotak centang
Cameradari daftar kapabilitas.
Buat tombol UI untuk membuat dan menutup panggilan
Aplikasi sampel ini berisi dua tombol. Satu untuk melakukan panggilan dan satu lagi untuk mengakhiri panggilan yang telah dilakukan.
- Di panel Penjelajah Solusi , klik dua kali pada file bernama
MainPage.xamluntuk UWP, atauMainWindows.xamluntuk WinUI 3. - Di panel tengah, cari kode XMAL di bawah pratinjau UI.
- Ubah kode XAML menggunakan 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.
Selesaikan langkah-langkah berikut untuk menginformasikan pengkompilasi C# tentang namespace ini, memungkinkan Intellisense Visual Studio membantu pengembangan kode.
- Di panel Penjelajah Solusi , klik panah di sisi kiri file bernama
MainPage.xamluntuk UWP, atauMainWindows.xamluntuk WinUI 3. - Klik dua kali pada file bernama
MainPage.xaml.csatauMainWindows.xaml.cs. - Tambahkan perintah berikut di bagian bawah pernyataan
usingsaat ini.
using Azure.Communication.Calling.WindowsClient;
Biarkan MainPage.xaml.cs atau MainWindows.xaml.cs tetap terbuka. Langkah berikutnya menambahkan lebih banyak kode.
Mengaktifkan interaksi aplikasi
Tombol UI yang kami tambahkan perlu beroperasi di atas elemen yang sudah ditempatkan CommunicationCall. Ini berarti Bahwa Anda harus menambahkan CommunicationCall anggota data ke MainPage kelas atau MainWindow .
Anda juga perlu mengaktifkan operasi asinkron agar pembuatan CallAgent berhasil.
CallAgent Tambahkan anggota data ke kelas yang sama.
Tambahkan anggota data berikut ke MainPage kelas atau MainWindow :
CallAgent callAgent;
CommunicationCall call;
Membuat pengatur tombol
Sebelumnya, kami menambahkan dua tombol UI ke kode XAML. Kode berikut menambahkan handler untuk dijalankan saat pengguna memilih tombol .
Tambahkan kode berikut setelah anggota-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 perpustakaan 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 menginisialisasi CallAgent. |
CallAgentOptions |
CallAgentOptions berisi informasi untuk mengidentifikasi pemanggil. |
HangupOptions |
Menginformasikan HangupOptions apakah panggilan harus dihentikan kepada semua pesertanya. |
Mendaftarkan pengelola skema video
Komponen UI, seperti XAML MediaElement atau MediaPlayerElement, mengharuskan aplikasi mendaftarkan konfigurasi untuk merender umpan video lokal dan jarak jauh.
Tambahkan konten berikut di antara tag Package dari 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 instans CallAgent dari CallClient, Anda harus menggunakan metode CallClient.CreateCallAgentAsync yang secara asinkron mengembalikan objek CallAgent setelah diinisialisasi.
Untuk membuat CallAgent, Anda harus melewati objek CallTokenCredential dan objek CallAgentOptions. Perlu diingat bahwa CallTokenCredential melempar jika token cacat dilewati.
Tambahkan kode berikut di dalam dan fungsi pembantu sehingga berjalan selama inisialisasi.
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;
Ubah <AUTHENTICATION_TOKEN> dengan token kredensial yang valid untuk sumber daya Anda. Untuk informasi selengkapnya tentang mencari token kredensial, lihat token akses pengguna.
Lakukan panggilan 1:1 dengan kamera video
Objek yang diperlukan untuk membuat CallAgent sekarang sudah siap. Kemudian buat CallAgent dan lakukan panggilan video secara 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 GetStartCallOptionsAsync();
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 LocalOutgoingVideoStream(this.viceManager.Cameras.FirstOrDefault() as VideoDeviceDetails); // Create a default video stream
private async Task<StartCallOptions> GetStartCallOptionsAsync()
{
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. Anda dapat merender video melalui MediaPlayerElement:
<Grid>
<MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>
Untuk memulai 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 selectedCamera = CameraList.SelectedItem as VideoDeviceDetails;
cameraStream = new LocalOutgoingVideoStream(selectedCamera);
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 event handler untuk menangani event OnCallsUpdated.
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, gunakan metode HangupAsync dari objek CommunicationCall untuk menutup panggilan.
Gunakan instans HangupOptions untuk memberi tahu peserta jika panggilan harus dihentikan.
Tambahkan kode berikut 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, ,x86atauARM64. - Tekan F5 untuk mulai menjalankan aplikasi.
- Klik tombol CommunicationCall untuk melakukan panggilan ke penerima yang ditentukan.
Pertama kali aplikasi berjalan, sistem meminta pengguna untuk memberikan akses ke mikrofon.