Aracılığıyla paylaş


Aramalar sırasında video yönetme

Azure İletişim Hizmetleri SDK'ları ile görüntülü aramaları yönetmeyi öğrenin. Arama içinde video alma ve göndermeyi yönetmeyi öğreneceğiz.

Önkoşullar

SDK’yı yükleyin

npm install JavaScript için Azure İletişim Hizmetleri Common ve Calling SDK'sını yüklemek için komutunu kullanın:

npm install @azure/communication-common --save
npm install @azure/communication-calling --save

Gerekli nesneleri başlatma

CallClient Çoğu çağrı işlemi için bir örnek gereklidir. Yeni CallClient bir örnek oluşturduğunuzda, örneği gibi Logger özel seçeneklerle yapılandırabilirsiniz.

örneğiyleCallClient, çağrısı createCallAgentyaparak bir CallAgent örnek oluşturabilirsiniz. Bu yöntem zaman uyumsuz olarak bir CallAgent örnek nesnesi döndürür.

createCallAgent yöntemi bağımsız değişken olarak kullanırCommunicationTokenCredential. Kullanıcı erişim belirtecini kabul eder.

öğesine erişmek deviceManageriçin örnekteki CallClient yöntemini kullanabilirsinizgetDeviceManager.

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()

Microsoft altyapısına SDK bağlantısını en iyi şekilde yönetme

Örnek, Call Agent çağrıları yönetmenize yardımcı olur (aramalara katılmak veya çağrıları başlatmak için). Arama SDK'nızın çalışması için gelen aramaların bildirimlerini almak ve diğer arama ayrıntılarını koordine etmek için Microsoft altyapısına bağlanması gerekir. Sizin iki olası durumu vardır Call Agent :

Bağlı - Call Agent connectionStatue değeri Connected , istemci SDK'sının bağlı olduğu ve Microsoft altyapısından bildirim alabilen olduğu anlamına gelir.

Bağlantısı kesildi - Call Agent Durumların Disconnected connectionStatue değeri, SDK'nın düzgün bağlanmasını engelleyen bir sorun var. Call Agent yeniden oluşturulmalıdır.

  • invalidToken: Belirtecin süresi dolduysa veya geçersiz Call Agent örnekse bu hatayla bağlantı kesilir.
  • connectionIssue: İstemcinin Microsoft infrascture'a bağlanmasıyla ilgili bir sorun varsa, birçok yeniden denemeden Call Agent sonra hata ortaya connectionIssue çıkar.

Özelliğin geçerli değerini connectionState inceleyerek yerel Call Agent bilgisayarınızın Microsoft altyapısına bağlı olup olmadığını denetleyebilirsiniz. Etkin bir çağrı sırasında, Bağlı durumundan connectionStateChanged Bağlantısız duruma gelen değişikliklerin olup olmadığını Call Agent belirlemek için olayı dinleyebilirsiniz.

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);

Cihaz yönetimi

Arama SDK'sı ile video kullanmaya başlamak için cihazları yönetebilmeniz gerekir. Cihazlar, Ses ve Görüntü'leri aramaya nelerin ilettiğini denetlemenize olanak tanır.

deviceManagerile ses ve video akışlarınızı bir aramada iletebilecek yerel cihazları numaralandırabilirsiniz. Yerel cihazın mikrofonlarına ve kameralarına erişim izni istemek için de kullanabilirsiniz deviceManager .

yöntemini çağırarak callClient.getDeviceManager() erişebilirsinizdeviceManager:

const deviceManager = await callClient.getDeviceManager();

Yerel cihazları alma

Yerel cihazlara erişmek için ve numaralandırma yöntemlerini getCameras() getMicrophoneskullanabilirsinizdeviceManager. Bu yöntemler zaman uyumsuz eylemlerdir.

//  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...]

Varsayılan cihazları ayarlama

Hangi cihazların kullanabildiğini öğrendikte mikrofon, hoparlör ve kamera için varsayılan cihazları ayarlayabilirsiniz. İstemci varsayılanları ayarlanmamışsa, İletişim Hizmetleri SDK'sı işletim sistemi varsayılanlarını kullanır.

Mikrofon

Kullanılan cihaza erişme

// Get the microphone device that is being used.
const defaultMicrophone = deviceManager.selectedMicrophone;

Kullanılacak cihazı ayarlama

// Set the microphone device to use.
await deviceManager.selectMicrophone(localMicrophones[0]);

Hoparlör

Kullanılan cihaza erişme

// Get the speaker device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;

Kullanılacak cihazı ayarlama

// Set the speaker device to use.
await deviceManager.selectSpeaker(localSpeakers[0]);

Kamera

Kullanılan cihaza erişme

// Get the camera device that is being used.
const defaultSpeaker = deviceManager.selectedSpeaker;

Kullanılacak cihazı ayarlama

// Set the speaker device to use.
await deviceManager.selectSpeaker(localCameras[0]);

Her CallAgent biri kendi mikrofonunu ve ilişkili DeviceManagerhoparlörlerini seçebilir. Farklı CallAgents mikrofonlar ve hoparlörler kullanmanızı öneririz. Aynı mikrofonları veya hoparlörleri paylaşmamalıdır. Paylaşım gerçekleşirse, Mikrofon Kullanıcıya Yönelik Tanılama tetiklenebilir ve tarayıcıya / işletim sistemine bağlı olarak mikrofon çalışmayı durdurabilir.

Yerel video akışı

Bir çağrıda video gönderebilmek için bir LocalVideoStreamnesne oluşturmanız gerekir.

const localVideoStream = new LocalVideoStream(camera);

Parametre olarak geçirilen kamera, yöntemi tarafından deviceManager.getCameras()döndürülen nesnelerden biridirVideoDeviceInfo.

A LocalVideoStream aşağıdaki özelliklere sahiptir:

  • source: Cihaz bilgileri.
const source = localVideoStream.source;
  • mediaStreamType: , ScreenSharingveya RawMediaolabilirVideo.
const type: MediaStreamType = localVideoStream.mediaStreamType;

Yerel kamera önizlemesi

yerel kameranızdan akış işlemeye başlamak için ve VideoStreamRenderer kullanabilirsinizdeviceManager. Oluşturulduktan LocalVideoStream sonra, ayarlamakVideoStreamRenderer için bunu kullanın. VideoStreamRendereroluşturulduktan sonra, sayfanıza çocuk olarak ekleyebileceğiniz bir görünüm elde etmek için yöntemini çağırıncreateView().

Bu akış diğer katılımcılara gönderilmez; yerel bir önizleme akışıdır.

// 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);

Yerel önizlemeyi durdurma

Yerel önizleme çağrısını durdurmak için öğesinden türetilen görünüme VideoStreamRendereratın. VideoStreamRenderer atıldıktan sonra, önizlemenizi içeren DOM Düğümünden yöntemini çağırarak removeChild() html ağacından görünümü kaldırın.

// To stop viewing local camera preview
view.dispose();
htmlElement.removeChild(view.target);

Kamera ve mikrofon için izin isteme

Bir uygulama izinler olmadan kamerayı veya mikrofonu kullanamaz. DeviceManager'ı kullanarak bir kullanıcıdan kamera ve/veya mikrofon izinleri vermesini isteyebilirsiniz:

const result = await deviceManager.askDevicePermission({audio: true, video: true});

Söz çözümlendikten sonra yöntemi, ve video izinlerinin verilip verilmediğini audio gösteren bir DeviceAccess nesneyle birlikte döndürür:

console.log(result.audio);
console.log(result.video);

Notlar

  • videoDevicesUpdated olay, video cihazları prize takılı/fişi takılıyken tetiklenir.
  • audioDevicesUpdated ses cihazları takılıyken olay tetiklenir.
  • DeviceManager oluşturulduğunda, ilk başta izinlerin henüz verilip verilmediğini bilmiyor, bu nedenle başlangıçta cihaz adı boştur ve ayrıntılı cihaz bilgileri içermez. Ardından DeviceManager.askPermission() API'sini çağırırsak kullanıcıdan cihaz erişimi istenir. Kullanıcı erişim izni vermek için 'izin ver' seçeneğini belirlediğinizde cihaz yöneticisi sistemdeki cihazlar hakkında bilgi edinir, cihaz listelerini güncelleştirir ve 'audioDevicesUpdated' ve 'videoDevicesUpdated' olaylarını yayar. Kullanıcı sayfayı yeniler ve bir cihaz yöneticisi oluşturursa, kullanıcı daha önce erişim verdiği için cihaz yöneticisi cihazlar hakkında bilgi edinir. Başlangıçta cihaz listeleri doldurulmuş ve 'audioDevicesUpdated' veya 'videoDevicesUpdated' olayları yaymaz.
  • Konuşmacı numaralandırması/seçimi Android Chrome, iOS Safari veya macOS Safari'de desteklenmez.

Görüntülü kamera ile arama yerleştirme

Önemli

Şu anda yalnızca bir giden yerel video akışı desteklenmektedir.

Görüntülü arama yapmak için içindeki yöntemini deviceManagerkullanarak getCameras() yerel kameraları listelemeniz gerekir.

Bir kamera seçtikten sonra örneği oluşturmak LocalVideoStream için bu kamerayı kullanın. bunu videoOptions yöntemine CallAgent startCall dizi içinde localVideoStream bir öğe olarak geçirin.

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);
  • Ayrıca API ile görüntülü aramaya katılabilir ve API ile CallAgent.join() görüntülü Call.Accept() aramayı kabul edebilir ve çağırabilirsiniz.
  • Aramanız bağlandığında, seçili kameradan diğer katılımcıya otomatik olarak bir video akışı göndermeye başlar.

Arama sırasında yerel video göndermeyi başlatma ve durdurma

Video başlatma

Arama sırasında video başlatmak için nesnedeki getCameras deviceManager yöntemini kullanarak kameraları listelemeniz gerekir. Ardından istenen kamerayla yeni bir örneği LocalVideoStream oluşturun ve nesneyi mevcut bir çağrı nesnesinin yöntemine startVideo geçirinLocalVideoStream:

const deviceManager = await callClient.getDeviceManager();
const cameras = await deviceManager.getCameras();
const camera = cameras[0]
const localVideoStream = new LocalVideoStream(camera);
await call.startVideo(localVideoStream);

Video durdur

Video göndermeye başarıyla başladıktan sonra, LocalVideoStream arama örneğindeki localVideoStreams koleksiyona bir tür Video örneği eklenir.

Arama nesnesinde video akışını bulma

const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'Video'} );

Yerel videoyu durdurma Arama sırasında yerel videoyu durdurmak için, video için kullanılan örneği öğesinin stopVideo yöntemine CallgeçirinlocalVideoStream:

await call.stopVideo(localVideoStream);

Bu örneği çağırarak switchSource etkin bir LocalVideoStream'e sahip olurken farklı bir kamera cihazına LocalVideoStream geçebilirsiniz:

const cameras = await callClient.getDeviceManager().getCameras();
const camera = cameras[1];
localVideoStream.switchSource(camera);

Belirtilen video cihazı kullanılamıyorsa:

  • Arama sırasında, videonuz kapalıysa ve kullanarak call.startVideo()video başlatırsanız, bu yöntem bir SourceUnavailableError oluşturur ve cameraStartFailed kullanıcıya yönelik tanılama true olarak ayarlanır.
  • yöntemine yapılan bir çağrı, localVideoStream.switchSource() true olarak ayarlanmasına neden olur cameraStartFailed . Arama Tanılama kılavuzumuz, aramayla ilgili sorunları tanılama hakkında ek bilgiler sağlar.

Yerel videonun açık veya kapalı olduğunu doğrulamak için, true veya false döndüren yöntemini isLocalVideoStartedkullanabilirsinizCall:

// Check if local video is on or off
call.isLocalVideoStarted;

Yerel videoda yapılan değişiklikleri dinlemek için isLocalVideoStartedChanged olayına abone olabilir ve aboneliği kaldırabilirsiniz:

// Subscribe to local video event
call.on('isLocalVideoStartedChanged', () => {
    // Callback();
});
// Unsubscribe from local video event
call.off('isLocalVideoStartedChanged', () => {
    // Callback();
});

Arama sırasında ekran paylaşımını başlatma ve durdurma

Çağrı sırasında ekran paylaşımını başlatmak için bir nesnede Call zaman uyumsuz yöntemini startScreenSharing() kullanabilirsiniz:

Ekran paylaşımını başlatma

// Start screen sharing
await call.startScreenSharing();

Not: Ekran paylaşımı gönderme işlemi yalnızca masaüstü tarayıcılarında desteklenir.

LocalVideoStream koleksiyonunda ekran paylaşımını bulma

Ekran paylaşımını başarıyla göndermeye başladıktan sonra, arama örneğindeki koleksiyona localVideoStreams türündeki ScreenSharingbir LocalVideoStream örnek eklenir.

const localVideoStream = call.localVideoStreams.find( (stream) => { return stream.mediaStreamType === 'ScreenSharing'} );

Ekran paylaşımını durdur

Arama sırasında ekran paylaşımını durdurmak için zaman uyumsuz API stoptScreenSharing kullanabilirsiniz:

// Stop screen sharing
await call.stopScreenSharing();

Ekran paylaşımı durumunu denetleme

Ekran paylaşımının açık veya kapalı olduğunu doğrulamak için true veya false döndüren isScreenSharingOn API'sini kullanabilirsiniz:

// Check if screen sharing is on or off
call.isScreenSharingOn;

Ekran paylaşımındaki değişiklikleri dinlemek için isScreenSharingOnChanged olayına abone olabilir ve aboneliği kaldırabilirsiniz:

// Subscribe to screen share event
call.on('isScreenSharingOnChanged', () => {
    // Callback();
});
// Unsubscribe from screen share event
call.off('isScreenSharingOnChanged', () => {
    // Callback();
});

Önemli

Azure İletişim Hizmetleri'nin bu özelliği şu anda önizleme aşamasındadır.

Önizleme API'leri ve SDK'ları hizmet düzeyi sözleşmesi olmadan sağlanır. Bunları üretim iş yükleri için kullanmamanızı öneririz. Bazı özellikler desteklenmeyebilir veya kısıtlı özelliklere sahip olabilir.

Daha fazla bilgi için Microsoft Azure Önizlemeleri için Ek Kullanım Koşulları'nı gözden geçirin.

Yerel ekran paylaşımı önizlemesi genel önizleme aşamasındadır ve sürüm 1.15.1-beta.1+ kapsamında kullanılabilir.

Yerel ekran paylaşımı önizlemesi

Ekran paylaşım akışı olarak ne gönderdiğinizi görebilmek için yerel ekran paylaşımınızdan akışları işlemeye başlamak için bir VideoStreamRenderer kullanabilirsiniz.

// 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);
    }
});

Uzak katılımcı video/ekran paylaşımı akışlarını işleme

Uzak katılımcı videosunu veya ekran paylaşımını işlemek için ilk adım, işlemek istediğiniz RemoteVideoStream üzerinde bir başvuru almaktır. Bu işlem, dizininden veya video akışından RemoteParticipant(videoStreams) geçirilerek yapılabilir. Uzak katılımcılar koleksiyonuna Call nesnesi aracılığıyla erişilir.

const remoteVideoStream = call.remoteParticipants[0].videoStreams[0];
const streamType = remoteVideoStream.mediaStreamType;

işlemek RemoteVideoStreamiçin olayına isAvailableChanged abone olmanız gerekir. isAvailable özelliği olarak truedeğişirse, uzak katılımcı bir video akışı gönderir. Bundan sonra, yeni bir örneği VideoStreamRendereroluşturun ve ardından zaman uyumsuz createView yöntemini kullanarak yeni VideoStreamRendererView bir örnek oluşturun.
Daha sonra herhangi bir kullanıcı arabirimi öğesine ekleyebilirsiniz view.target .

Uzak akışın kullanılabilirliği her değiştiğinde, tamamını VideoStreamRenderer veya belirli VideoStreamRendererViewbir öğesini yok edebilirsiniz. Bunları saklamaya karar verirseniz, görünüm boş bir video çerçevesi görüntüler.

// 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}`);
    });
}

Uzak video akışı üzerinden yükleme değiştiricisini şekillendirmek için CSS.

.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); }
}

Uzak video kalitesi

Azure İletişim Hizmetleri WebJS SDK'sı, 1.15.1 sürümünden başlayarak En İyi Video Sayısı (OVC) adlı bir özellik sağlar. Bu özellik, uygulamaları bir grup çağrısında (2+ katılımcı) belirli bir anda farklı katılımcılardan gelen kaç videoyu en iyi şekilde işleyebileceğiniz konusunda bilgilendirmek için kullanılabilir. Bu özellik, yerel uç noktanın ağ ve donanım özelliklerine göre çağrı sırasında dinamik olarak değişen bir özelliği optimalVideoCount kullanıma sunar. Değerinin optimalVideoCount değeri, belirli bir anda farklı katılımcı uygulamasından kaç videonun işlenmesi gerektiğini açıklar. Uygulamalar bu değişiklikleri işlemeli ve işlenen video sayısını öneriye göre güncelleştirmelidir. Her güncelleştirme arasında bir ayırma süresi (yaklaşık 10 sn) vardır.

Kullanım Bu optimalVideoCount özellik bir arama özelliğidir. Nesnenin yöntemi Call aracılığıyla feature özelliğe OptimalVideoCount başvurmanız gerekir. Ardından optimalVideoCount değiştiğinde on bildirim almak için yöntemini OptimalVideoCountCallFeature kullanarak bir dinleyici ayarlayabilirsiniz. Değişikliklerin aboneliğini kaldırmak için yöntemini çağırabilirsiniz off . İşlenebilen en fazla gelen video sayısı 16'dır. 16 gelen videoyu düzgün bir şekilde desteklemek için bilgisayarda 16 GB RAM'lik bir mimimum ve 3 yaşından eski olmayan 4 çekirdekli veya daha büyük bir CPU olmalıdır.

const optimalVideoCountFeature = call.feature(Features.OptimalVideoCount);
optimalVideoCountFeature.on('optimalVideoCountChanged', () => {
    const localOptimalVideoCountVariable = optimalVideoCountFeature.optimalVideoCount;
})

Örnek kullanım: Uygulama, grup çağrılarında En uygun Video Sayısı değişikliklerine abone olmalıdır. En uygun video sayısındaki bir değişiklik, yeni işleyici (createView yöntem) oluşturularak veya görünümleri atarak (dispose) ve uygulama düzenini uygun şekilde güncelleştirerek işlenebilir.

Uzak video akışı özellikleri

Uzak video akışları aşağıdaki özelliklere sahiptir:

const id: number = remoteVideoStream.id;
  • id: Uzak video akışının kimliği.
const type: MediaStreamType = remoteVideoStream.mediaStreamType;
  • mediaStreamType: veya ScreenSharingolabilirVideo.
const isAvailable: boolean = remoteVideoStream.isAvailable;
  • isAvailable: Uzak katılımcı uç noktasının etkin bir şekilde akış gönderip göndermediğini tanımlar.
const isReceiving: boolean = remoteVideoStream.isReceiving;
  • isReceiving:
    • Uzak video akışı verilerinin alındığını veya alınmadığını uygulamaya bildirir.

    • Bayrağı aşağıdaki senaryolarda 'a false taşınır:

      • Mobil tarayıcıdaki uzak katılımcı, tarayıcı uygulamasını arka plana getirir.
      • Uzak bir katılımcı veya videoyu alan kullanıcının video kalitesini önemli ölçüde etkileyen ağ sorunu vardır.
      • MacOS/iOS Safari'de olan uzak bir katılımcı, adres çubuğundan "Duraklat" seçeneğini seçer.
      • Uzak katılımcının ağ bağlantısı kesiliyor.
      • Mobil cihazlardaki uzak bir katılımcı tarayıcıyı öldürür veya sonlandırır.
      • Mobil veya masaüstündeki uzak katılımcı cihazını kilitler. Bu senaryo, uzak katılımcı bir masaüstü bilgisayardaysa ve uyku moduna geçtiğinde de geçerlidir.
    • Bayrağı aşağıdaki senaryolarda 'a true taşınır:

      • Mobil tarayıcıda olan ve tarayıcısı arka planına sahip uzak bir katılımcı onu ön plana geri getirir.
      • MacOS/iOS Safari'de olan uzak bir katılımcı, videosunu duraklatdıktan sonra adres çubuğundan "Sürdür"ü seçer.
      • Uzak katılımcı, geçici bir bağlantı kesildikten sonra ağa yeniden bağlanır.
      • Mobil cihazlardaki uzak bir katılımcı cihazının kilidini açar ve mobil tarayıcıdan aramaya geri döner.
    • Bu özellik, uzak video akışlarını işlemeye yönelik kullanıcı deneyimini geliştirir.

    • Bayrağı false olarak değiştirirse uzak video akışı üzerinden bir yükleme değiştirici görüntüleyebilirsiniz. Yükleme değiştiricisi uygulamanız gerekmez, ancak daha iyi bir kullanıcı deneyimi için en yaygın kullanım yük değiştiricidir.

const size: StreamSize = remoteVideoStream.size;
  • size: Videonun genişliği ve yüksekliği hakkında bilgi içeren akış boyutu.

VideoStreamRenderer yöntemleri ve özellikleri

await videoStreamRenderer.createView();

Uzak video akışını işlemek için uygulama kullanıcı arabirimine eklenebilen createView() bir VideoStreamRendererView örnek oluşturun, zaman uyumsuz yöntemi kullanın, akış işlemeye hazır olduğunda çözümleniyor ve DOM ağacında herhangi bir yere eklenebilen öğeyi temsil video eden özelliğe sahip target bir nesne döndürüyor.

videoStreamRenderer.dispose();

videoStreamRenderer ve tüm ilişkili VideoStreamRendererView örnekleri atın.

VideoStreamRendererView yöntemleri ve özellikleri

Oluşturduğunuzda VideoStreamRendererViewve isMirrored özelliklerini belirtebilirsinizscalingMode. scalingMode, Cropveya FitolabilirStretch. Belirtilirse isMirrored , işlenen akış dikey olarak çevrilmiş olur.

const videoStreamRendererView: VideoStreamRendererView = await videoStreamRenderer.createView({ scalingMode, isMirrored });

Her VideoStreamRendererView örneğin işleme yüzeyini temsil eden bir target özelliği vardır. Bu özelliği uygulama kullanıcı arabirimine ekleyin:

htmlElement.appendChild(view.target);

Yöntemini çağırarak updateScalingMode güncelleştirebilirsinizscalingMode:

view.updateScalingMode('Crop');

Aynı masaüstü cihazından aynı aramada iki farklı kameradan video akışları gönderin.

Önemli

Azure İletişim Hizmetleri'nin bu özelliği şu anda önizleme aşamasındadır.

Önizleme API'leri ve SDK'ları hizmet düzeyi sözleşmesi olmadan sağlanır. Bunları üretim iş yükleri için kullanmamanızı öneririz. Bazı özellikler desteklenmeyebilir veya kısıtlı özelliklere sahip olabilir.

Daha fazla bilgi için Microsoft Azure Önizlemeleri için Ek Kullanım Koşulları'nı gözden geçirin.

Aynı çağrıda iki farklı kameradan video akışı gönderme, masaüstü tarafından desteklenen tarayıcılarda sürüm 1.17.1-beta.1+ kapsamında desteklenir.

  • Aynı çağrıda, aşağıdaki kod parçacığıyla tek bir masaüstü tarayıcı sekmesinden/uygulamasından iki farklı kameradan video akışı gönderebilirsiniz:
// 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();

Sınırlamalar:

  • Bunun farklı kimlikler kullanılarak iki farklı CallAgent örnekle yapılması gerekir. Kod parçacığı, her biri kendi Call nesnesine sahip iki çağrı aracısının kullanıldığını gösterir.
  • Kod örneğinde, her iki CallAgents da aynı çağrıya (aynı çağrı kimlikleri) katılıyor. Ayrıca her aracıyla farklı aramalara katılabilir ve bir aramada bir video, diğer aramada ise farklı bir video gönderebilirsiniz.
  • Aynı kamerayı her iki CallAgent'da da gönderme desteklenmez. İki farklı kamera olmalı.
  • Bir CallAgent ile iki farklı kamera göndermek şu anda desteklenmiyor.
  • macOS Safari'de, arka plan bulanıklaştırma video efektleri (uygulamasından @azure/communication-effects), hem aynı anda hem de tek bir kameraya uygulanabilir.

SDK’yı yükleyin

Proje düzeyi build.gradle dosyanızı bulun ve ve allprojectsaltındaki buildscript depolar listesine ekleyinmavenCentral():

buildscript {
    repositories {
    ...
        mavenCentral()
    ...
    }
}
allprojects {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

Ardından modül düzeyi build.gradle dosyanıza aşağıdaki satırları dependencies bölümüne ekleyin:

dependencies {
    ...
    implementation 'com.azure.android:azure-communication-calling:1.0.0'
    ...
}

Gerekli nesneleri başlatma

Örnek CallAgent oluşturmak için bir örnekte yöntemini CallClient çağırmanız createCallAgent gerekir. Bu çağrı zaman uyumsuz olarak bir CallAgent örnek nesnesi döndürür.

createCallAgent yöntemi, bir erişim belirtecini kapsülleyen bir bağımsız değişken olarak alırCommunicationUserCredential.

öğesine erişmek DeviceManageriçin önce bir callAgent örnek oluşturmanız gerekir. Ardından almak için DeviceManageryöntemini kullanabilirsinizCallClient.getDeviceManager.

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();

Çağıranın görünen adını ayarlamak için şu alternatif yöntemi kullanın:

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();

Cihaz yönetimi

Arama ile video kullanmaya başlamak için cihazları yönetmeyi bilmeniz gerekir. Cihazlar, Ses ve Görüntü'leri aramaya nelerin ilettiğini denetlemenize olanak tanır.

DeviceManager , ses/video akışlarınızı iletmek için bir aramada kullanılabilecek yerel cihazları listelemenize olanak tanır. Ayrıca yerel tarayıcı API'sini kullanarak bir kullanıcıdan mikrofon ve kameraya erişim izni istemenizi sağlar.

yöntemini çağırarak callClient.getDeviceManager() erişebilirsinizdeviceManager.

Context appContext = this.getApplicationContext();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();

Yerel cihazları listeleme

Yerel cihazlara erişmek için Aygıt Yöneticisi numaralandırma yöntemlerini kullanabilirsiniz. Numaralandırma zaman uyumlu bir eylemdir.

//  Get a list of available video devices for use.
List<VideoDeviceInfo> localCameras = deviceManager.getCameras(); // [VideoDeviceInfo, VideoDeviceInfo...]

Yerel kamera önizlemesi

yerel kameranızdan akış işlemeye başlamak için ve Renderer kullanabilirsinizDeviceManager. Bu akış diğer katılımcılara gönderilmez; yerel bir önizleme akışıdır. Bu, zaman uyumsuz bir eylemdir.

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);

Video kamera ile 1:1 araması yerleştirme

Uyarı

Şu anda yalnızca bir giden yerel video akışı desteklenmektedir Görüntülü arama yapmak için API'yi kullanarak deviceManager getCameras yerel kameraları listelemeniz gerekir. İstediğiniz kamerayı seçtikten sonra bir örnek oluşturmak LocalVideoStream ve bunu dizideki localVideoStream bir öğe olarak bir call yönteme videoOptions geçirmek için kullanın. Arama bağlandıktan sonra, seçilen kameradan diğer katılımcılara otomatik olarak bir video akışı göndermeye başlar.

Not

Gizlilikle ilgili endişelerden dolayı, yerel olarak önizlemesi yapılmadığı takdirde aramada video paylaşılmaz. Diğer ayrıntılar için bkz . Yerel kamera önizlemesi .

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);

Yerel video göndermeyi başlatma ve durdurma

Video başlatmak için nesne üzerindeki deviceManager API'yi kullanarak getCameraList kameraları listelemeniz gerekir. Ardından istenen kamerayı geçirmenin LocalVideoStream yeni bir örneğini oluşturun ve api'de startVideo bağımsız değişken olarak geçirin:

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();

Video göndermeye başarıyla başladıktan sonra, çağrı örneğindeki localVideoStreams koleksiyona bir LocalVideoStream örnek eklenir.

List<LocalVideoStream> videoStreams = call.getLocalVideoStreams();
LocalVideoStream currentLocalVideoStream = videoStreams.get(0); // Please make sure there are VideoStreams in the list before calling get(0).

Yerel videoyu durdurmak için koleksiyonda LocalVideoStream localVideoStreams bulunan örneği geçirin:

call.stopVideo(appContext, currentLocalVideoStream).get();

Bir örneği çağırarak switchSource video gönderilirken farklı bir LocalVideoStream kamera cihazına geçebilirsiniz:

currentLocalVideoStream.switchSource(source).get();

Uzak katılımcı video akışlarını işleme

Uzak katılımcıların video akışlarını ve ekran paylaşım akışlarını listelemek için koleksiyonları videoStreams inceleyin:

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

Uzak katılımcıdan RemoteVideoStream bir iş oluşturmak için bir OnVideoStreamsUpdated olaya abone olmanız gerekir.

Olay içinde özelliğin isAvailable true olarak değiştirilmesi, uzak katılımcının şu anda bir akış gönderdiğini gösterir. Bu durumda, yeni bir Rendererörneği oluşturun ve zaman uyumsuz API kullanarak yeni RendererView bir oluşturun ve uygulamanızın createView kullanıcı arabiriminde herhangi bir yere ekleyin view.target .

Bir uzak akış kullanılabilirliği değiştiğinde, işleyicinin tamamını, belirli RendererView bir veya bunları saklamayı seçebilirsiniz, ancak bu boş video çerçevesi görüntülenmesine neden olur.

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();
        }
    }
}

Uzak video akışı özellikleri

Uzak video akışının birkaç özelliği vardır

  • Id - Uzak video akışının kimliği
int id = remoteVideoStream.getId();
  • MediaStreamType - 'Video' veya 'ScreenSharing' olabilir
MediaStreamType type = remoteVideoStream.getMediaStreamType();
  • isAvailable - Uzak katılımcı uç noktasının etkin bir şekilde akış gönderip göndermediğini gösterir
boolean availability = remoteVideoStream.isAvailable();

oluşturucu yöntemleri ve özellikleri

API'leri izleyen işleyici nesnesi

  • Uzak video akışını işlemek için daha sonra uygulama kullanıcı arabirimine eklenebilen bir VideoStreamRendererView örnek oluşturun.
// Create a view for a video stream
VideoStreamRendererView.createView()
  • Işleyiciyi ve bu işleyiciyle ilişkili tümünü VideoStreamRendererView at. Kullanıcı arabiriminden tüm ilişkili görünümleri kaldırdığınızda çağrılmak için.
VideoStreamRenderer.dispose()
  • StreamSize - uzak video akışının boyutu (genişlik/yükseklik)
StreamSize renderStreamSize = VideoStreamRenderer.getSize();
int width = renderStreamSize.getWidth();
int height = renderStreamSize.getHeight();

RendererView yöntemleri ve özellikleri

OluştururkenVideoStreamRendererView, bu görünüme uygulanacak ve mirrored özelliklerini belirtebilirsinizScalingMode: Ölçeklendirme modu 'CROP' modundan biri olabilir | 'FIT'

VideoStreamRenderer remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream, appContext);
VideoStreamRendererView rendererView = remoteVideoRenderer.createView(new CreateViewOptions(ScalingMode.Fit));

Oluşturulan RendererView daha sonra aşağıdaki kod parçacığı kullanılarak uygulama kullanıcı arabirimine eklenebilir:

layout.addView(rendererView);

Daha sonra ScalingMode.CROP | öğesinden biriyle RendererView nesnesindeki API'yi çağırarak updateScalingMode ölçeklendirme modunu güncelleştirebilirsiniz Bağımsız değişken olarak ScalingMode.FIT.

// Update the scale mode for this view.
rendererView.updateScalingMode(ScalingMode.CROP)

Sisteminizi ayarlama

Xcode projesini oluşturma

Xcode'da yeni bir iOS projesi oluşturun ve Tek Görünüm Uygulaması şablonunu seçin. Bu hızlı başlangıçta SwiftUI çerçevesi kullanılır, bu nedenle Dil'i Swift olarak ve Arabirim'i SwiftUI olarak ayarlamanız gerekir.

Bu hızlı başlangıç sırasında test oluşturacaksınız. Testleri Dahil Et onay kutusunu temizleyebilirsiniz.

Xcode içinde proje oluşturma penceresini gösteren ekran görüntüsü.

CocoaPods kullanarak paketi ve bağımlılıkları yükleme

  1. Uygulamanız için aşağıdaki örnekte olduğu gibi bir Podfile oluşturun:

    platform :ios, '13.0'
    use_frameworks!
    target 'AzureCommunicationCallingSample' do
        pod 'AzureCommunicationCalling', '~> 1.0.0'
    end
    
  2. pod install'i çalıştırın.

  3. Xcode kullanarak açın .xcworkspace .

Mikrofona erişim isteme

Cihazın mikrofona erişmek için kullanarak uygulamanızın bilgi özellik listesini NSMicrophoneUsageDescriptiongüncelleştirmeniz gerekir. İlişkili değeri, sistemin kullanıcıdan erişim istemek için kullandığı iletişim kutusuna eklenecek bir dizeye ayarlarsınız.

Proje ağacının Info.plist girdisine sağ tıklayın ve Kaynak Kodu Olarak>Aç'ı seçin. Üst düzey <dict> bölüme aşağıdaki satırları ekleyin ve dosyayı kaydedin.

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>

Uygulama çerçevesini ayarlama

Projenizin ContentView.swift dosyasını açın. Kitaplığı içeri aktarmak AzureCommunicationCalling için dosyanın en üstüne bir import bildirim ekleyin. Buna ek olarak, içeri aktar.AVFoundation Koddaki ses izni istekleri için buna ihtiyacınız olacaktır.

import AzureCommunicationCalling
import AVFoundation

CallAgent'ı başlatma

öğesinden CallClientbir CallAgent örnek oluşturmak için, başlatıldıktan sonra zaman uyumsuz olarak bir nesne döndüren bir CallAgent yöntem kullanmanız callClient.createCallAgent gerekir.

Çağrı istemcisi oluşturmak için bir CommunicationTokenCredential nesne geçirin:

import AzureCommunication

let tokenString = "token_string"
var userCredential: CommunicationTokenCredential?
do {
    let options = CommunicationTokenRefreshOptions(initialToken: token, refreshProactively: true, tokenRefresher: self.fetchTokenSync)
    userCredential = try CommunicationTokenCredential(withOptions: options)
} catch {
    updates("Couldn't created Credential object", false)
    initializationDispatchGroup!.leave()
    return
}

// tokenProvider needs to be implemented by Contoso, which fetches a new token
public func fetchTokenSync(then onCompletion: TokenRefreshOnCompletion) {
    let newToken = self.tokenProvider!.fetchNewToken()
    onCompletion(newToken, nil)
}

CommunicationTokenCredential Oluşturduğunuz nesneyi öğesine CallClientgeçirin ve görünen adı ayarlayın:

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")
        }
})

Cihazları yönetme

Arama ile video kullanmaya başlamak için cihazları yönetmeyi bilmeniz gerekir. Cihazlar, Ses ve Görüntü'leri aramaya nelerin ilettiğini denetlemenize olanak tanır.

DeviceManager , ses veya video akışlarını iletmek için bir çağrıda kullanılabilecek yerel cihazları listelemenize olanak tanır. Ayrıca bir kullanıcıdan mikrofona veya kameraya erişim izni istemenizi sağlar. Nesneye callClient erişebilirsinizdeviceManager.

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")
        }
    }

Yerel cihazları listeleme

Yerel cihazlara erişmek için cihaz yöneticisinde numaralandırma yöntemlerini kullanabilirsiniz. Numaralandırma zaman uyumlu bir eylemdir.

// enumerate local cameras
var localCameras = deviceManager.cameras // [VideoDeviceInfo, VideoDeviceInfo...]

Yerel kamera önizlemesi alma

Yerel kameranızdan bir akışı işlemeye başlamak için kullanabilirsiniz Renderer . Bu akış diğer katılımcılara gönderilmez; yerel bir önizleme akışıdır. Bu, zaman uyumsuz bir eylemdir.

let camera: VideoDeviceInfo = self.deviceManager!.cameras.first!
let localVideoStream = LocalVideoStream(camera: camera)
let localRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream)
self.view = try! localRenderer.createView()

Yerel kamera önizleme özelliklerini alma

oluşturucu, işlemeyi denetlemenize olanak sağlayan özellikler ve yöntemler kümesine sahiptir.

// 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()

Görüntülü 1:1 araması yerleştirme

Cihaz yöneticisi örneği almak için cihazları yönetme bölümüne bakın.

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")
    }
}

Uzak katılımcı video akışlarını işleme

Uzak katılımcılar arama sırasında video veya ekran paylaşımı başlatabilir.

Uzak katılımcıların video paylaşımı veya ekran paylaşımı akışlarını işleme

Uzak katılımcıların akışlarını listelemek için koleksiyonları videoStreams inceleyin.

var remoteParticipantVideoStream = call.remoteParticipants[0].videoStreams[0]

Uzak video akışı özelliklerini alma

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

Uzak katılımcı akışlarını işleme

Uzak katılımcı akışlarını işlemeye başlamak için aşağıdaki kodu kullanın.

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)

Uzak video işleyici yöntemlerini ve özelliklerini alma

// [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()

Sisteminizi ayarlama

Visual Studio projesini oluşturma

UWP uygulaması için Visual Studio 2022'de yeni bir Boş Uygulama (Evrensel Windows) projesi oluşturun. Proje adını girdikten sonra, 10.0.17763.0'dan sonraki bir Windows SDK'sını seçebilirsiniz.

WinUI 3 uygulaması için, tek sayfalı bir WinUI 3 uygulaması ayarlamak için Boş Uygulama, Paketlenmiş (Masaüstünde WinUI 3) şablonuyla yeni bir proje oluşturun. Windows Uygulama SDK'sı sürüm 1.3 veya üzeri gereklidir.

NuGet Paket Yöneticisi kullanarak paketi ve bağımlılıkları yükleme

Arama SDK'sı API'leri ve kitaplıkları bir NuGet paketi aracılığıyla genel kullanıma sunulur.

Aşağıdaki adımlar, Çağırma SDK'sı NuGet paketini bulma, indirme ve yükleme adımlarını açıklar:

  1. Araçlar>NuGet Paket Yöneticisi Çözüm için NuGet Paketlerini Yönet'i seçerek NuGet Paket Yöneticisi> açın.
  2. Gözat'ı seçin ve arama kutusuna yazınAzure.Communication.Calling.WindowsClient.
  3. Ön sürümü dahil et onay kutusunun seçili olduğundan emin olun.
  4. Azure.Communication.Calling.WindowsClient Paketi seçin ve ardından 1.4.0-beta.1 veya daha yeni bir sürüm seçin Azure.Communication.Calling.WindowsClient .
  5. Sağ taraftaki sekmede İletişim Hizmetleri projesine karşılık gelen onay kutusunu seçin.
  6. Yükle düğmesini seçin.

Mikrofona erişim isteme

Uygulamanın düzgün çalışması için kameraya erişim gerekir. UWP uygulamalarında kamera özelliği, uygulama bildirim dosyasında bildirilmelidir.

Aşağıdaki adımlar bunun nasıl başarıldığını gösterir.

  1. Panelde Solution Explorer uzantılı .appxmanifest dosyaya çift tıklayın.
  2. Sekmeye Capabilities tıklayın.
  3. Camera Yetenekler listesinden onay kutusunu seçin.

Aramayı yerleştirmek ve kapatmak için kullanıcı arabirimi düğmeleri oluşturma

Bu basit örnek uygulama iki düğme içerir. Biri aramayı yapmak için, diğeri ise aramayı kapatmak için. Aşağıdaki adımlar, bu düğmelerin uygulamaya nasıl ekleneceğini gösterir.

  1. Panelde Solution Explorer UWP veya MainWindows.xaml WinUI 3 için adlı MainPage.xaml dosyaya çift tıklayın.
  2. Merkezi panelde kullanıcı arabirimi önizlemesi altında XAML kodunu arayın.
  3. XAML kodunu aşağıdaki alıntıyla değiştirin:
<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>

Uygulamayı SDK API'lerini çağırma ile ayarlama

Çağrı SDK'sı API'leri iki farklı ad alanındadır. Aşağıdaki adımlar, Visual Studio'nun IntelliSense'inin kod geliştirmeye yardımcı olmasını sağlayan bu ad alanları hakkında C# derleyicisini bilgilendirmektedir.

  1. PaneldeSolution Explorer, dosyanın sol tarafındaki UWP veya MainWindows.xaml WinUI 3 için adlı MainPage.xaml oka tıklayın.
  2. veya MainWindows.xaml.csadlı MainPage.xaml.cs dosyaya çift tıklayın.
  3. Geçerli using deyimlerin en altına aşağıdaki komutları ekleyin.
using Azure.Communication.Calling.WindowsClient;

Açık veya MainWindows.xaml.cs açık tutunMainPage.xaml.cs. Sonraki adımlarda bu koda daha fazla kod eklenir.

Uygulama etkileşimlerine izin ver

Daha önce eklenen kullanıcı arabirimi düğmelerinin yerleştirilen CommunicationCallüzerinde çalışması gerekir. Bu, bir CommunicationCall veri üyesinin veya MainWindow sınıfına MainPage eklenmesi gerektiği anlamına gelir. Ayrıca, zaman uyumsuz işlemin başarılı CallAgent olması için veri CallAgent üyesinin de aynı sınıfa eklenmesi gerekir.

veya MainWindow sınıfına aşağıdaki veri üyelerini MainPage ekleyin:

CallAgent callAgent;
CommunicationCall call;

Düğme işleyicileri oluşturma

Daha önce XAML koduna iki kullanıcı arabirimi düğmesi eklendi. Aşağıdaki kod, kullanıcı düğmeyi seçtiğinde yürütülecek işleyicileri ekler. Aşağıdaki kod, önceki bölümdeki veri üyelerinden sonra eklenmelidir.

private async void CallButton_Click(object sender, RoutedEventArgs e)
{
    // Start call
}

private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
    // End the current call
}

Nesne modeli

Aşağıdaki sınıflar ve arabirimler Azure İletişim Hizmetleri UWP için istemci kitaplığını çağırmanın bazı önemli özelliklerini işler.

Veri Akışı Adı Açıklama
CallClient CallClient, çağrı istemci kitaplığının ana giriş noktasıdır.
CallAgent CallAgent çağrıları başlatmak ve katılmak için kullanılır.
CommunicationCall CommunicationCall, yerleştirilen veya birleştirilen çağrıları yönetmek için kullanılır.
CommunicationTokenCredential , CommunicationTokenCredential örneğini CallAgentbaşlatmak için belirteç kimlik bilgisi olarak kullanılır.
CallAgentOptions , CallAgentOptions çağıranı tanımlamak için bilgileri içerir.
HangupOptions Aramanın HangupOptions tüm katılımcılarına sonlandırılıp sonlandırılmadığını bildirir.

Video şeması işleyicisini kaydetme

XAML'nin MediaElement veya MediaPlayerElement gibi bir UI bileşeni, uygulamanın yerel ve uzak video akışlarını işlemek için bir yapılandırma kaydetmesi gerekir. etiketleri Package.appxmanifestarasına aşağıdaki içeriği Package ekleyin:

<Extensions>
    <Extension Category="windows.activatableClass.inProcessServer">
        <InProcessServer>
            <Path>RtmMvrUap.dll</Path>
            <ActivatableClass ActivatableClassId="VideoN.VideoSchemeHandler" ThreadingModel="both" />
        </InProcessServer>
    </Extension>
</Extensions>

CallAgent'ı başlatma

öğesinden CallClientbir CallAgent örnek oluşturmak için, başlatıldıktan sonra bir nesneyi zaman uyumsuz olarak döndüren yöntemi CallAgent kullanmanız CallClient.CreateCallAgentAsync gerekir.

oluşturmak CallAgentiçin bir CallTokenCredential nesne ve CallAgentOptions bir nesne geçirmeniz gerekir. Hatalı biçimlendirilmiş bir belirteç geçirilirse atıldığını unutmayın CallTokenCredential .

Aşağıdaki kod içine eklenmelidir ve yardımcı işlevi uygulama başlatmada çağrılmalıdır.

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> değerini kaynağınız için geçerli bir kimlik bilgisi belirteci ile değiştirin. Kimlik bilgisi belirtecinin kaynaklanması gerekiyorsa kullanıcı erişim belirteci belgelerine bakın.

Video kamera ile 1:1 araması yerleştirme

oluşturmak CallAgent için gereken nesneler artık hazır. Zaman uyumsuz olarak görüntülü arama oluşturma CallAgent ve yerleştirme zamanı geldi.

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 } }
    };
}

Yerel kamera önizlemesi

İsteğe bağlı olarak yerel kamera önizlemesini ayarlayabiliriz. Video aracılığıyla işlenebilir MediaPlayerElement:

<Grid>
    <MediaPlayerElement x:Name="LocalVideo" AutoPlay="True" />
    <MediaPlayerElement x:Name="RemoteVideo" AutoPlay="True" />
</Grid>

Yerel önizlemeyi MediaPlayerElementbaşlatmak için:

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);
    }
}

Uzak kamera akışını işleme

Olaya yanıt olarak çift işleyici ayarlayın 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;
    }
}

uzak video akışını üzerinde MediaPlayerElementişlemeye başlayın:

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;
    }
}

Aramayı sonlandırma

Bir çağrı yerleştirildikten sonra, HangupAsync çağrıyı CommunicationCall kapatmak için nesnesinin yöntemi kullanılmalıdır.

Çağrısının HangupOptions tüm katılımcılarına sonlandırılıp sonlandırılmaması gerektiğini bildirmek için bir örneği de kullanılmalıdır.

aşağıdaki kod içine HangupButton_Clickeklenmelidir.

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;
            }
        }
    }
}

Kodu çalıştırma

Visual Studio'da uygulamasının , x86 veya ARM64için derlediğinden emin olun, ardından uygulamayı çalıştırmaya başlamak için x64hit tuşuna basınF5. Bundan sonra, tanımlanan çağrıyı aramak için düğmeye tıklayın CommunicationCall .

Uygulama ilk kez çalıştırıldığında sistemin kullanıcıdan mikrofona erişim izni vermesi istendiğini unutmayın.

Sonraki adımlar