Hızlı Başlangıç: Uygulamanıza Teams kullanıcısı olarak 1:1 görüntülü arama ekleme
uygulamanıza 1:1 sesli ve görüntülü arama eklemek için İletişim Hizmetleri çağrı SDK'sını kullanarak Azure İletişim Hizmetleri kullanmaya başlayın. JavaScript için Azure İletişim Hizmetleri Arama SDK'sını kullanarak bir aramayı başlatmayı ve yanıtlamayı öğreneceksiniz.
Örnek Kod
Sonuna atlamak isterseniz bu hızlı başlangıcı GitHub'da örnek olarak indirebilirsiniz.
Önkoşullar
- Etkin aboneliği olan bir Azure hesabı edinin. Ücretsiz hesap oluşturun.
- 18 Node.js olmalı. Msi yükleyicisini kullanarak yükleyebilirsiniz.
- Etkin bir İletişim Hizmetleri kaynağı oluşturun. İletişim Hizmetleri kaynağı oluşturun.
- Çağrı istemcisinin örneğini oluşturmak için bir Kullanıcı Erişim Belirteci oluşturun. Kullanıcı erişim belirteçleri oluşturmayı ve yönetmeyi öğrenin.
- Graph Explorer'ı kullanarak çağrı işlemleri için Teams iş parçacığı kimliğini alın. Sohbet yazışma kimliği oluşturma hakkında daha fazla bilgi edinin.
Ayarlama
Yeni bir Node.js uygulaması oluşturma
Terminalinizi veya komut pencerenizi açın, uygulamanız için yeni bir dizin oluşturun ve dizine gidin.
mkdir calling-quickstart && cd calling-quickstart
Varsayılan ayarlarla bir package.json dosyası oluşturmak için komutunu çalıştırınnpm init -y
.
npm init -y
paketini yükleyin
npm install
JavaScript için Azure İletişim Hizmetleri Çağırma SDK'sını yüklemek için komutunu kullanın.
Önemli
Bu hızlı başlangıçta en son Azure İletişim Hizmetleri Çağırma SDK'sı sürümü kullanılmaktadır.
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Uygulama çerçevesini ayarlama
Bu hızlı başlangıçta uygulama varlıklarını paketlemek için webpack kullanılır. aşağıdaki komutu çalıştırarak webpack
, webpack-cli
ve webpack-dev-server
npm paketlerini yükleyin ve bunları içinde geliştirme bağımlılıkları olarak listeleyin package.json
:
npm install copy-webpack-plugin@^11.0.0 webpack@^5.88.2 webpack-cli@^5.1.4 webpack-dev-server@^4.15.1 --save-dev
Projenizin kök dizininde bir index.html
dosya oluşturun. Bu dosyayı, kullanıcının 1:1 görüntülü aramasına izin verecek temel bir düzen yapılandırmak için kullanacağız.
Kod şu şekildedir:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Azure Communication Services - Teams Calling Web Application</title>
</head>
<body>
<h4>Azure Communication Services - Teams Calling Web Application</h4>
<input id="user-access-token"
type="text"
placeholder="User access token"
style="margin-bottom:1em; width: 500px;"/>
<button id="initialize-teams-call-agent" type="button">Login</button>
<br>
<br>
<input id="callee-teams-user-id"
type="text"
placeholder="Microsoft Teams callee's id (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)"
style="margin-bottom:1em; width: 500px; display: block;"/>
<button id="start-call-button" type="button" disabled="true">Start Call</button>
<button id="hangup-call-button" type="button" disabled="true">Hang up Call</button>
<button id="accept-call-button" type="button" disabled="true">Accept Call</button>
<button id="start-video-button" type="button" disabled="true">Start Video</button>
<button id="stop-video-button" type="button" disabled="true">Stop Video</button>
<br>
<br>
<div id="connectedLabel" style="color: #13bb13;" hidden>Call is connected!</div>
<br>
<div id="remoteVideoContainer" style="width: 40%;" hidden>Remote participants' video streams:</div>
<br>
<div id="localVideoContainer" style="width: 30%;" hidden>Local video stream:</div>
<!-- points to the bundle generated from client.js -->
<script src="./main.js"></script>
</body>
</html>
Web SDK'sı Nesne modelini çağırmayı Azure İletişim Hizmetleri
Aşağıdaki sınıflar ve arabirimler, Azure İletişim Hizmetleri Çağırma SDK'sının bazı ana özelliklerini işler:
Veri Akışı Adı | Açıklama |
---|---|
CallClient |
Çağrı SDK'sının ana giriş noktası. |
AzureCommunicationTokenCredential |
örneğini CommunicationTokenCredential başlatmak için teamsCallAgent kullanılan arabirimini uygular. |
TeamsCallAgent |
Teams çağrılarını başlatmak ve yönetmek için kullanılır. |
DeviceManager |
Medya cihazlarını yönetmek için kullanılır. |
TeamsCall |
Teams Aramasını temsil etmek için kullanılır |
LocalVideoStream |
Yerel sistemdeki bir kamera cihazı için yerel video akışı oluşturmak için kullanılır. |
RemoteParticipant |
Aramada uzak katılımcıyı temsil etmek için kullanılır |
RemoteVideoStream |
Uzak Katılımcıdan uzak bir video akışını temsil etmek için kullanılır. |
Projenizin kök dizininde, bu hızlı başlangıcın uygulama mantığını içerecek şekilde adlı index.js
bir dosya oluşturun. index.js aşağıdaki kodu ekleyin:
// Make sure to install the necessary dependencies
const { CallClient, VideoStreamRenderer, LocalVideoStream } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential } = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the log level and output
setLogLevel('verbose');
AzureLogger.log = (...args) => {
console.log(...args);
};
// Calling web sdk objects
let teamsCallAgent;
let deviceManager;
let call;
let incomingCall;
let localVideoStream;
let localVideoStreamRenderer;
// UI widgets
let userAccessToken = document.getElementById('user-access-token');
let calleeTeamsUserId = document.getElementById('callee-teams-user-id');
let initializeCallAgentButton = document.getElementById('initialize-teams-call-agent');
let startCallButton = document.getElementById('start-call-button');
let hangUpCallButton = document.getElementById('hangup-call-button');
let acceptCallButton = document.getElementById('accept-call-button');
let startVideoButton = document.getElementById('start-video-button');
let stopVideoButton = document.getElementById('stop-video-button');
let connectedLabel = document.getElementById('connectedLabel');
let remoteVideoContainer = document.getElementById('remoteVideoContainer');
let localVideoContainer = document.getElementById('localVideoContainer');
/**
* Create an instance of CallClient. Initialize a TeamsCallAgent instance with a CommunicationUserCredential via created CallClient. TeamsCallAgent enables us to make outgoing calls and receive incoming calls.
* You can then use the CallClient.getDeviceManager() API instance to get the DeviceManager.
*/
initializeCallAgentButton.onclick = async () => {
try {
const callClient = new CallClient();
tokenCredential = new AzureCommunicationTokenCredential(userAccessToken.value.trim());
teamsCallAgent = await callClient.createTeamsCallAgent(tokenCredential)
// Set up a camera device to use.
deviceManager = await callClient.getDeviceManager();
await deviceManager.askDevicePermission({ video: true });
await deviceManager.askDevicePermission({ audio: true });
// Listen for an incoming call to accept.
teamsCallAgent.on('incomingCall', async (args) => {
try {
incomingCall = args.incomingCall;
acceptCallButton.disabled = false;
startCallButton.disabled = true;
} catch (error) {
console.error(error);
}
});
startCallButton.disabled = false;
initializeCallAgentButton.disabled = true;
} catch(error) {
console.error(error);
}
}
/**
* Place a 1:1 outgoing video call to a user
* Add an event listener to initiate a call when the `startCallButton` is selected.
* Enumerate local cameras using the deviceManager `getCameraList` API.
* In this quickstart, we're using the first camera in the collection. Once the desired camera is selected, a
* LocalVideoStream instance will be constructed and passed within `videoOptions` as an item within the
* localVideoStream array to the call method. When the call connects, your application will be sending a video stream to the other participant.
*/
startCallButton.onclick = async () => {
try {
const localVideoStream = await createLocalVideoStream();
const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
call = teamsCallAgent.startCall({ microsoftTeamsUserId: calleeTeamsUserId.value.trim() }, { videoOptions: videoOptions });
// Subscribe to the call's properties and events.
subscribeToCall(call);
} catch (error) {
console.error(error);
}
}
/**
* Accepting an incoming call with a video
* Add an event listener to accept a call when the `acceptCallButton` is selected.
* You can accept incoming calls after subscribing to the `TeamsCallAgent.on('incomingCall')` event.
* You can pass the local video stream to accept the call with the following code.
*/
acceptCallButton.onclick = async () => {
try {
const localVideoStream = await createLocalVideoStream();
const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
call = await incomingCall.accept({ videoOptions });
// Subscribe to the call's properties and events.
subscribeToCall(call);
} catch (error) {
console.error(error);
}
}
// Subscribe to a call obj.
// Listen for property changes and collection udpates.
subscribeToCall = (call) => {
try {
// Inspect the initial call.id value.
console.log(`Call Id: ${call.id}`);
//Subsribe to call's 'idChanged' event for value changes.
call.on('idChanged', () => {
console.log(`Call ID changed: ${call.id}`);
});
// Inspect the initial call.state value.
console.log(`Call state: ${call.state}`);
// Subscribe to call's 'stateChanged' event for value changes.
call.on('stateChanged', async () => {
console.log(`Call state changed: ${call.state}`);
if(call.state === 'Connected') {
connectedLabel.hidden = false;
acceptCallButton.disabled = true;
startCallButton.disabled = true;
hangUpCallButton.disabled = false;
startVideoButton.disabled = false;
stopVideoButton.disabled = false;
} else if (call.state === 'Disconnected') {
connectedLabel.hidden = true;
startCallButton.disabled = false;
hangUpCallButton.disabled = true;
startVideoButton.disabled = true;
stopVideoButton.disabled = true;
console.log(`Call ended, call end reason={code=${call.callEndReason.code}, subCode=${call.callEndReason.subCode}}`);
}
});
call.on('isLocalVideoStartedChanged', () => {
console.log(`isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
});
console.log(`isLocalVideoStarted: ${call.isLocalVideoStarted}`);
call.localVideoStreams.forEach(async (lvs) => {
localVideoStream = lvs;
await displayLocalVideoStream();
});
call.on('localVideoStreamsUpdated', e => {
e.added.forEach(async (lvs) => {
localVideoStream = lvs;
await displayLocalVideoStream();
});
e.removed.forEach(lvs => {
removeLocalVideoStream();
});
});
// Inspect the call's current remote participants and subscribe to them.
call.remoteParticipants.forEach(remoteParticipant => {
subscribeToRemoteParticipant(remoteParticipant);
});
// Subscribe to the call's 'remoteParticipantsUpdated' event to be
// notified when new participants are added to the call or removed from the call.
call.on('remoteParticipantsUpdated', e => {
// Subscribe to new remote participants that are added to the call.
e.added.forEach(remoteParticipant => {
subscribeToRemoteParticipant(remoteParticipant)
});
// Unsubscribe from participants that are removed from the call
e.removed.forEach(remoteParticipant => {
console.log('Remote participant removed from the call.');
});
});
} catch (error) {
console.error(error);
}
}
// Subscribe to a remote participant obj.
// Listen for property changes and collection udpates.
subscribeToRemoteParticipant = (remoteParticipant) => {
try {
// Inspect the initial remoteParticipant.state value.
console.log(`Remote participant state: ${remoteParticipant.state}`);
// Subscribe to remoteParticipant's 'stateChanged' event for value changes.
remoteParticipant.on('stateChanged', () => {
console.log(`Remote participant state changed: ${remoteParticipant.state}`);
});
// Inspect the remoteParticipants's current videoStreams and subscribe to them.
remoteParticipant.videoStreams.forEach(remoteVideoStream => {
subscribeToRemoteVideoStream(remoteVideoStream)
});
// Subscribe to the remoteParticipant's 'videoStreamsUpdated' event to be
// notified when the remoteParticiapant adds new videoStreams and removes video streams.
remoteParticipant.on('videoStreamsUpdated', e => {
// Subscribe to newly added remote participant's video streams.
e.added.forEach(remoteVideoStream => {
subscribeToRemoteVideoStream(remoteVideoStream)
});
// Unsubscribe from newly removed remote participants' video streams.
e.removed.forEach(remoteVideoStream => {
console.log('Remote participant video stream was removed.');
})
});
} catch (error) {
console.error(error);
}
}
/**
* Subscribe to a remote participant's remote video stream obj.
* You have to subscribe to the 'isAvailableChanged' event to render the remoteVideoStream. If the 'isAvailable' property
* changes to 'true' a remote participant is sending a stream. Whenever the availability of a remote stream changes
* you can choose to destroy the whole 'Renderer' a specific 'RendererView' or keep them. Displaying RendererView without a video stream will result in a blank video frame.
*/
subscribeToRemoteVideoStream = async (remoteVideoStream) => {
// Create a video stream renderer for the remote video stream.
let videoStreamRenderer = new VideoStreamRenderer(remoteVideoStream);
let view;
const renderVideo = async () => {
try {
// Create a renderer view for the remote video stream.
view = await videoStreamRenderer.createView();
// Attach the renderer view to the UI.
remoteVideoContainer.hidden = false;
remoteVideoContainer.appendChild(view.target);
} catch (e) {
console.warn(`Failed to createView, reason=${e.message}, code=${e.code}`);
}
}
remoteVideoStream.on('isAvailableChanged', async () => {
// Participant has switched video on.
if (remoteVideoStream.isAvailable) {
await renderVideo();
// Participant has switched video off.
} else {
if (view) {
view.dispose();
view = undefined;
}
}
});
// Participant has video on initially.
if (remoteVideoStream.isAvailable) {
await renderVideo();
}
}
// Start your local video stream.
// This will send your local video stream to remote participants so they can view it.
startVideoButton.onclick = async () => {
try {
const localVideoStream = await createLocalVideoStream();
await call.startVideo(localVideoStream);
} catch (error) {
console.error(error);
}
}
// Stop your local video stream.
// This will stop your local video stream from being sent to remote participants.
stopVideoButton.onclick = async () => {
try {
await call.stopVideo(localVideoStream);
} catch (error) {
console.error(error);
}
}
/**
* To render a LocalVideoStream, you need to create a new instance of VideoStreamRenderer, and then
* create a new VideoStreamRendererView instance using the asynchronous createView() method.
* You may then attach view.target to any UI element.
*/
// Create a local video stream for your camera device
createLocalVideoStream = async () => {
const camera = (await deviceManager.getCameras())[0];
if (camera) {
return new LocalVideoStream(camera);
} else {
console.error(`No camera device found on the system`);
}
}
// Display your local video stream preview in your UI
displayLocalVideoStream = async () => {
try {
localVideoStreamRenderer = new VideoStreamRenderer(localVideoStream);
const view = await localVideoStreamRenderer.createView();
localVideoContainer.hidden = false;
localVideoContainer.appendChild(view.target);
} catch (error) {
console.error(error);
}
}
// Remove your local video stream preview from your UI
removeLocalVideoStream = async() => {
try {
localVideoStreamRenderer.dispose();
localVideoContainer.hidden = true;
} catch (error) {
console.error(error);
}
}
// End the current call
hangUpCallButton.addEventListener("click", async () => {
// end the current call
await call.hangUp();
});
Webpack yerel sunucu kodunu ekleme
Bu hızlı başlangıcın yerel sunucu mantığını içermesi için projenizin kök dizininde webpack.config.js adlı bir dosya oluşturun. webpack.config.js aşağıdaki kodu ekleyin:
const path = require('path');
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
static: {
directory: path.join(__dirname, './')
},
},
plugins: [
new CopyPlugin({
patterns: [
'./index.html'
]
}),
]
};
Kodu çalıştırma
Uygulamanızı derlemek ve çalıştırmak için öğesini webpack-dev-server
kullanın. Uygulama konağını yerel bir web sunucusu içinde paketlemek için aşağıdaki komutu çalıştırın:
`npx webpack serve --config webpack.config.js`
Tarayıcınızı açın ve iki sekmede http://localhost:8080/. Sekmelerde aşağıdaki görüntüye benzer bir sonuç gösterilmelidir:
İlk sekmede geçerli bir kullanıcı erişim belirteci girin. İkinci sekmede başka bir geçerli kullanıcı erişim belirteci girin. Kullanılabilecek erişim belirteçleriniz yoksa kullanıcı erişim belirteci belgelerine bakın. Her iki sekmede de "Çağrı Aracısını Başlat" düğmelerine tıklayın. Sekmelerde aşağıdaki görüntüye benzer bir sonuç gösterilmelidir:
İlk sekmede, ikinci sekmenin Azure İletişim Hizmetleri kullanıcı kimliğini girin ve "Aramayı Başlat" düğmesini seçin. İlk sekme, ikinci sekmeye giden çağrıyı başlatır ve ikinci sekmenin "Aramayı Kabul Et" düğmesi etkinleştirilir:
İkinci sekmeden "Aramayı Kabul Et" düğmesini seçin. Arama yanıtlanır ve bağlanır. Sekmelerde aşağıdaki görüntüye benzer bir sonuç gösterilmelidir:
Her iki sekme de artık 1:1 görüntülü aramasında başarılı bir şekilde sağlanır. Her iki kullanıcı da birbirlerinin sesini duyabilir ve birbirlerinin video akışını görebilir.
uygulamanıza 1:1 sesli ve görüntülü arama eklemek için İletişim Hizmetleri çağrı SDK'sını kullanarak Azure İletişim Hizmetleri kullanmaya başlayın. Windows için Azure İletişim Hizmetleri Arama SDK'sını kullanarak bir aramayı başlatmayı ve yanıtlamayı öğrenirsiniz.
Örnek Kod
Sonuna atlamak isterseniz bu hızlı başlangıcı GitHub'da örnek olarak indirebilirsiniz.
Önkoşullar
Bu öğreticiyi tamamlamak için aşağıdaki önkoşulları karşılamanız gerekir:
- Etkin aboneliği olan bir Azure hesabı. Ücretsiz hesap oluşturun.
- Evrensel Windows Platformu geliştirme iş yüküyle Visual Studio 2022'yi yükleyin.
- Dağıtılan bir İletişim Hizmetleri kaynağı. İletişim Hizmetleri kaynağı oluşturun. Bu hızlı başlangıç için bağlantı dizesi kaydetmeniz gerekir.
- Azure İletişim Hizmetiniz için Kullanıcı Erişim Belirteci.
- Graph Explorer'ı kullanarak çağrı işlemleri için Teams iş parçacığı kimliğini alın. Sohbet yazışma kimliği oluşturma hakkında daha fazla bilgi edinin.
Ayarlama
Projeyi oluşturma
Visual Studio'da, tek sayfalı bir Evrensel Windows Platformu (UWP) uygulaması ayarlamak için Boş Uygulama (Evrensel Windows) şablonuyla yeni bir proje oluşturun.
paketini yükleyin
Sağ projenizi seçin ve 1.2.0-beta.1 veya üzerini yüklemeye Azure.Communication.Calling.WindowsClient
gidinManage Nuget Packages
. Önceden Dahil Et'in işaretli olduğundan emin olun.
Erişim isteğinde bulunma
adresine Package.appxmanifest
gidin ve öğesini seçin Capabilities
.
Internet (Client & Server)
İnternet'e gelen ve giden erişim elde etmek için ve öğesini denetleyinInternet (Client)
. Mikrofonun ses akışına erişmek ve Webcam
kameranın video akışına erişmek için kontrol edinMicrophone
.
Uygulama çerçevesini ayarlama
Mantığımızı eklemek için temel bir düzen yapılandırmamız gerekir. Giden arama yapmak için, arayanın Kullanıcı Kimliğini sağlamamız gerekir TextBox
. Ayrıca bir Start/Join call
düğmeye ve bir düğmeye Hang up
de ihtiyacımız var. Ses durumlarını ve BackgroundBlur
video efektlerini açma/kapatma özelliklerini göstermek için bu örneğe A Mute
ve onay kutuları da dahildir.
Projenizin öğesini MainPage.xaml
açın ve düğümünü Grid
öğesininize Page
ekleyin:
<Page
x:Class="CallingQuickstart.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CallingQuickstart"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Width="800" Height="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="16*"/>
<RowDefinition Height="30*"/>
<RowDefinition Height="200*"/>
<RowDefinition Height="60*"/>
<RowDefinition Height="16*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="1" x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="10,10,10,10" />
<Grid x:Name="AppTitleBar" Background="LightSeaGreen">
<TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="7,7,0,0"/>
</Grid>
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<MediaPlayerElement x:Name="LocalVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="0" VerticalAlignment="Center" AutoPlay="True" />
<MediaPlayerElement x:Name="RemoteVideo" HorizontalAlignment="Center" Stretch="UniformToFill" Grid.Column="1" VerticalAlignment="Center" AutoPlay="True" />
</Grid>
<StackPanel Grid.Row="3" Orientation="Vertical" Grid.RowSpan="2">
<StackPanel Orientation="Horizontal">
<Button x:Name="CallButton" Content="Start/Join call" Click="CallButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<Button x:Name="HangupButton" Content="Hang up" Click="HangupButton_Click" VerticalAlignment="Center" Margin="10,0,0,0" Height="40" Width="123"/>
<CheckBox x:Name="MuteLocal" Content="Mute" Margin="10,0,0,0" Click="MuteLocal_Click" Width="74"/>
</StackPanel>
</StackPanel>
<TextBox Grid.Row="5" x:Name="Stats" Text="" TextWrapping="Wrap" VerticalAlignment="Center" Height="30" Margin="0,2,0,0" BorderThickness="2" IsReadOnly="True" Foreground="LightSlateGray" />
</Grid>
</Page>
MainPage.xaml.cs
öğesini açın ve içeriğini aşağıdaki uygulamayla değiştirin:
using Azure.Communication.Calling.WindowsClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Media.Core;
using Windows.Networking.PushNotifications;
using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace CallingQuickstart
{
public sealed partial class MainPage : Page
{
private const string authToken = "<AUTHENTICATION_TOKEN>";
private CallClient callClient;
private CallTokenRefreshOptions callTokenRefreshOptions = new CallTokenRefreshOptions(false);
private TeamsCallAgent teamsCallAgent;
private TeamsCommunicationCall teamsCall;
private LocalOutgoingAudioStream micStream;
private LocalOutgoingVideoStream cameraStream;
#region Page initialization
public MainPage()
{
this.InitializeComponent();
// Additional UI customization code goes here
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
}
#endregion
#region UI event handlers
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
// Start a call
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
// Hang up a call
}
private async void MuteLocal_Click(object sender, RoutedEventArgs e)
{
// Toggle mute/unmute audio state of a call
}
#endregion
#region API event handlers
private async void OnIncomingCallAsync(object sender, TeamsIncomingCallReceivedEventArgs args)
{
// Handle incoming call event
}
private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
{
// Handle connected and disconnected state change of a call
}
#endregion
}
}
Nesne modeli
Sonraki tabloda sınıflar ve arabirimler, Azure İletişim Hizmetleri Çağırma SDK'sının bazı önemli özelliklerini işler:
Veri Akışı Adı | Açıklama |
---|---|
CallClient |
CallClient , Çağrı SDK'sının ana giriş noktasıdır. |
TeamsCallAgent |
TeamsCallAgent , çağrıları başlatmak ve yönetmek için kullanılır. |
TeamsCommunicationCall |
TeamsCommunicationCall , devam eden bir çağrıyı yönetmek için kullanılır. |
CallTokenCredential |
, CallTokenCredential örneğini TeamsCallAgent başlatmak için belirteç kimlik bilgisi olarak kullanılır. |
CallIdentifier |
CallIdentifier , kullanıcının kimliğini temsil etmek için kullanılır. Bu, aşağıdaki seçeneklerden biri olabilir: MicrosoftTeamsUserCallIdentifier , UserCallIdentifier , PhoneNumberCallIdentifier vb. |
İstemcinin kimliğini doğrulama
Çağrı yapmamıza ve almamıza olanak tanıyan bir Kullanıcı Erişim Belirteci ile bir TeamsCallAgent
örnek başlatın ve isteğe bağlı olarak istemci cihaz yapılandırmalarını sorgulamak için bir DeviceManager örneği alın.
kodunda değerini bir Kullanıcı Erişim Belirteci ile değiştirin <AUTHENTICATION_TOKEN>
. Henüz kullanılabilir bir belirteciniz yoksa kullanıcı erişim belirteci belgelerine bakın.
SDK'yı önyükleyen işlev ekleyin InitCallAgentAndDeviceManagerAsync
. Bu yardımcı, uygulamanızın gereksinimlerini karşılayacak şekilde özelleştirilebilir.
private async Task InitCallAgentAndDeviceManagerAsync()
{
this.callClient = new CallClient(new CallClientOptions() {
Diagnostics = new CallDiagnosticsOptions() {
AppName = "CallingQuickstart",
AppVersion="1.0",
Tags = new[] { "Calling", "CTE", "Windows" }
}
});
// Set up local video stream using the first camera enumerated
var deviceManager = await this.callClient.GetDeviceManagerAsync();
var camera = deviceManager?.Cameras?.FirstOrDefault();
var mic = deviceManager?.Microphones?.FirstOrDefault();
micStream = new LocalOutgoingAudioStream();
var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);
this.teamsCallAgent = await this.callClient.CreateTeamsCallAgentAsync(tokenCredential);
this.teamsCallAgent.IncomingCallReceived += OnIncomingCallAsync;
}
Arama başlatma
Oluşturduğumuz nesneyle teamsCallAgent
çeşitli çağrı türlerini başlatmak ve nesne üzerinde bağlama RemoteParticipantsUpdated
ve StateChanged
olay işleyicileri oluşturmak için uygulamasına CallButton_Click
TeamsCommunicationCall
ekleyin.
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
var callString = CalleeTextBox.Text.Trim();
teamsCall = await StartCteCallAsync(callString);
if (teamsCall != null)
{
teamsCall.StateChanged += OnStateChangedAsync;
}
}
Aramayı sonlandırma
Düğmeye tıklandığında Hang up
geçerli aramayı sonlandırın. Bir çağrıyı sonlandırmak ve önizleme ile video akışlarını durdurmak için uygulamayı HangupButton_Click ekleyin.
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
var teamsCall = this.teamsCallAgent?.Calls?.FirstOrDefault();
if (teamsCall != null)
{
await teamsCall.HangUpAsync(new HangUpOptions() { ForEveryone = false });
}
}
Seste sesi kapatma/açma arasında geçiş
Düğmeye tıklandığında Mute
giden sesin sesini kapat. Çağrının sesini kapatmak için uygulamayı MuteLocal_Click ekleyin.
private async void MuteLocal_Click(object sender, RoutedEventArgs e)
{
var muteCheckbox = sender as CheckBox;
if (muteCheckbox != null)
{
var teamsCall = this.teamsCallAgent?.Calls?.FirstOrDefault();
if (teamsCall != null)
{
if ((bool)muteCheckbox.IsChecked)
{
await teamsCall.MuteOutgoingAudioAsync();
}
else
{
await teamsCall.UnmuteOutgoingAudioAsync();
}
}
// Update the UI to reflect the state
}
}
Aramayı başlatma
Bir StartTeamsCallOptions
nesne elde edildikten sonra Teams TeamsCallAgent
çağrısını başlatmak için kullanılabilir:
private async Task<TeamsCommunicationCall> StartCteCallAsync(string cteCallee)
{
var options = new StartTeamsCallOptions();
var teamsCall = await this.teamsCallAgent.StartCallAsync( new MicrosoftTeamsUserCallIdentifier(cteCallee), options);
return call;
}
Gelen aramayı kabul etme
TeamsIncomingCallReceived
olay havuzu SDK bootstrap yardımcısında InitCallAgentAndDeviceManagerAsync
ayarlanır.
this.teamsCallAgent.IncomingCallReceived += OnIncomingCallAsync;
Uygulama, video ve ses akışı türleri gibi gelen çağrının nasıl kabul edilmesi gerektiğini yapılandırma fırsatına sahiptir.
private async void OnIncomingCallAsync(object sender, TeamsIncomingCallReceivedEventArgs args)
{
var teamsIncomingCall = args.IncomingCall;
var acceptteamsCallOptions = new AcceptTeamsCallOptions() { };
teamsCall = await teamsIncomingCall.AcceptAsync(acceptteamsCallOptions);
teamsCall.StateChanged += OnStateChangedAsync;
}
Teams Çağrısına Katılma
Kullanıcı ayrıca bir bağlantı geçirerek mevcut bir aramaya katılabilir
TeamsMeetingLinkLocator link = new TeamsMeetingLinkLocator("meetingLink");
JoinTeamsCallOptions options = new JoinTeamsCallOptions();
TeamsCall call = await teamsCallAgent.JoinAsync(link, options);
Çağrı durumu değişiklik olayını izleme ve yanıtlama
StateChanged
devam eden bir çağrı işlemi bir durumdan diğerine yapıldığında nesnedeki TeamsCommunicationCall
olay tetiklenir. Uygulamaya kullanıcı arabirimindeki durum değişikliklerini yansıtma veya iş mantığı ekleme fırsatları sunulur.
private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
{
var teamsCall = sender as TeamsCommunicationCall;
if (teamsCall != null)
{
var state = teamsCall.State;
// Update the UI
switch (state)
{
case CallState.Connected:
{
await teamsCall.StartAudioAsync(micStream);
break;
}
case CallState.Disconnected:
{
teamsCall.StateChanged -= OnStateChangedAsync;
teamsCall.Dispose();
break;
}
default: break;
}
}
}
Kodu çalıştırma
Kodu Visual Studio'da derleyebilir ve çalıştırabilirsiniz. Çözüm platformları için , ve x86
'yi x64
destekliyoruzARM64
.
Metin alanında bir kullanıcı kimliği sağlayarak ve düğmeye tıklayarak Start Call/Join
giden arama yapabilirsiniz. Arama 8:echo123
sizi bir yankı botuyla bağlar. Bu özellik, ses cihazlarınızın çalıştığını doğrulamak ve kullanmaya başlamak için harika bir özelliktir.
uygulamanıza 1:1 sesli ve görüntülü arama eklemek için İletişim Hizmetleri çağrı SDK'sını kullanarak Azure İletişim Hizmetleri kullanmaya başlayın. Java için Azure İletişim Hizmetleri Arama SDK'sını kullanarak aramayı başlatmayı ve yanıtlamayı öğreneceksiniz.
Örnek Kod
Sonuna atlamak isterseniz bu hızlı başlangıcı GitHub'da örnek olarak indirebilirsiniz.
Önkoşullar
- Etkin aboneliği olan bir Azure hesabı. Ücretsiz hesap oluşturun.
- Android uygulamanızı oluşturmak için Android Studio.
- Dağıtılan bir İletişim Hizmetleri kaynağı. İletişim Hizmetleri kaynağı oluşturun. Bu hızlı başlangıç için bağlantı dizesi kaydetmeniz gerekir.
- Azure İletişim Hizmetiniz için Kullanıcı Erişim Belirteci.
- Graph Explorer'ı kullanarak çağrı işlemleri için Teams iş parçacığı kimliğini alın. Sohbet yazışma kimliği oluşturma hakkında daha fazla bilgi edinin.
Ayarlama
Boş etkinlik içeren bir Android uygulaması oluşturma
Android Studio'dan Yeni bir Android Studio projesi başlat'ı seçin.
"Telefon ve Tablet" altında "Boş Etkinlik" proje şablonunu seçin.
En Düşük "API 26: Android 8.0 (Oreo)" veya üzeri SDK'sı seçin.
paketini yükleyin
Build.gradle proje düzeyinizi bulun ve ve altındaki buildscript
depolar listesine eklediğinizden mavenCentral()
emin olunallprojects
buildscript {
repositories {
...
mavenCentral()
...
}
}
allprojects {
repositories {
...
mavenCentral()
...
}
}
Ardından, modül düzeyinizde build.gradle bağımlılıklara ve android bölümlerine aşağıdaki satırları ekleyin
android {
...
packagingOptions {
pickFirst 'META-INF/*'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
...
implementation 'com.azure.android:azure-communication-calling:1.0.0-beta.8'
...
}
Uygulama bildirimine izin ekleme
Çağrı yapmak için gerekli izinleri istemek için, uygulama bildiriminde (app/src/main/AndroidManifest.xml
) bildirilmelidir. Dosyanın içeriğini aşağıdaki kodla değiştirin:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.contoso.ctequickstart">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--Our Calling SDK depends on the Apache HTTP SDK.
When targeting Android SDK 28+, this library needs to be explicitly referenced.
See https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p-->
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Uygulamanın düzenini ayarlama
İki giriş gereklidir: arayan kimliği için bir metin girişi ve çağrıyı yerleştirmek için bir düğme. Bu girişler tasarımcı aracılığıyla veya düzen xml'i düzenlenerek eklenebilir. kimliği call_button
ve metin girişi callee_id
olan bir düğme oluşturun. adresine gidin (app/src/main/res/layout/activity_main.xml
) ve dosyanın içeriğini aşağıdaki kodla değiştirin:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/call_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Call"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="@+id/callee_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Callee Id"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/call_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Ana etkinlik iskelesi ve bağlamaları oluşturma
Oluşturulan düzen ile bağlamaların yanı sıra etkinliğin temel iskelesi eklenebilir. Etkinlik, çalışma zamanı izinleri isteme, teams çağrı aracısını oluşturma ve düğmeye basıldığında aramayı yerleştirme işlemlerini işler. Her biri kendi bölümünde ele alınmıştır. ve onCreate
çağrısı getAllPermissions
düğmesinin bağlamalarını eklemek için yöntemi createTeamsAgent
geçersiz kılınmış. Bu olay, etkinlik oluşturulduğunda yalnızca bir kez gerçekleşir. Daha fazla bilgi için, üzerinde onCreate
Etkinlik Yaşam Döngüsünü Anlama kılavuzuna bakın.
MainActivity.java gidin ve içeriği aşağıdaki kodla değiştirin:
package com.contoso.ctequickstart;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.media.AudioManager;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.azure.android.communication.common.CommunicationUserIdentifier;
import com.azure.android.communication.common.CommunicationTokenCredential;
import com.azure.android.communication.calling.TeamsCallAgent;
import com.azure.android.communication.calling.CallClient;
import com.azure.android.communication.calling.StartTeamsCallOptions;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TeamsCallAgent teamsCallAgent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getAllPermissions();
createTeamsAgent();
// Bind call button to call `startCall`
Button callButton = findViewById(R.id.call_button);
callButton.setOnClickListener(l -> startCall());
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
}
/**
* Request each required permission if the app doesn't already have it.
*/
private void getAllPermissions() {
// See section on requesting permissions
}
/**
* Create the call agent for placing calls
*/
private void createTeamsAgent() {
// See section on creating the call agent
}
/**
* Place a call to the callee id provided in `callee_id` text input.
*/
private void startCall() {
// See section on starting the call
}
}
Çalışma zamanında izin isteme
Android 6.0 ve üzeri (API düzeyi 23) ve targetSdkVersion
23 veya üzeri için, uygulama yüklendiğinde değil çalışma zamanında izinler verilir. Bunu desteklemek için çağrı getAllPermissions
yapmak ActivityCompat.checkSelfPermission
ve ActivityCompat.requestPermissions
gerekli her izin için uygulanabilir.
/**
* Request each required permission if the app doesn't already have it.
*/
private void getAllPermissions() {
String[] requiredPermissions = new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE};
ArrayList<String> permissionsToAskFor = new ArrayList<>();
for (String permission : requiredPermissions) {
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
permissionsToAskFor.add(permission);
}
}
if (!permissionsToAskFor.isEmpty()) {
ActivityCompat.requestPermissions(this, permissionsToAskFor.toArray(new String[0]), 1);
}
}
Not
Uygulamanızı tasarlarken bu izinlerin ne zaman istenmesi gerektiğini göz önünde bulundurun. İzinler önceden değil, gerektiğinde istenmelidir. Daha fazla bilgi için bkz . Android İzinleri Kılavuzu.
Nesne modeli
Aşağıdaki sınıflar ve arabirimler, Azure İletişim Hizmetleri Çağırma SDK'sının bazı önemli özelliklerini işler:
Veri Akışı Adı | Açıklama |
---|---|
CallClient |
CallClient , Çağrı SDK'sının ana giriş noktasıdır. |
TeamsCallAgent |
TeamsCallAgent , çağrıları başlatmak ve yönetmek için kullanılır. |
TeamsCall |
TeamsCall Teams Çağrısını temsil etmek için kullanılan. |
CommunicationTokenCredential |
, CommunicationTokenCredential örneğini TeamsCallAgent başlatmak için belirteç kimlik bilgisi olarak kullanılır. |
CommunicationIdentifier |
CommunicationIdentifier , bir çağrının parçası olabilecek farklı bir katılımcı türü olarak kullanılır. |
Kullanıcı erişim belirtecinden aracı oluşturma
Kullanıcı belirteci ile kimliği doğrulanmış bir çağrı aracısı örneği oluşturulabilir. Bu belirteç genellikle uygulamaya özgü kimlik doğrulamasına sahip bir hizmetten oluşturulur. Kullanıcı erişim belirteçleri hakkında daha fazla bilgi için Kullanıcı Erişim Belirteçleri kılavuzuna bakın.
Hızlı başlangıç için değerini Azure İletişim Hizmeti kaynağınız için oluşturulan bir kullanıcı erişim belirteci ile değiştirin <User_Access_Token>
.
/**
* Create the teams call agent for placing calls
*/
private void createAgent() {
String userToken = "<User_Access_Token>";
try {
CommunicationTokenCredential credential = new CommunicationTokenCredential(userToken);
teamsCallAgent = new CallClient().createTeamsCallAgent(getApplicationContext(), credential).get();
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), "Failed to create teams call agent.", Toast.LENGTH_SHORT).show();
}
}
Arama aracısını kullanarak arama başlatma
Aramanın yerleştirilmesi, ekipler arama aracısı aracılığıyla yapılabilir ve yalnızca arayan kimliklerinin ve arama seçeneklerinin bir listesinin sağlanmasını gerektirir. Hızlı başlangıç için, video içermeyen varsayılan arama seçenekleri ve metin girişinden tek bir çağrı kimliği kullanılır.
/**
* Place a call to the callee id provided in `callee_id` text input.
*/
private void startCall() {
EditText calleeIdView = findViewById(R.id.callee_id);
String calleeId = calleeIdView.getText().toString();
StartTeamsCallOptions options = new StartTeamsCallOptions();
teamsCallAgent.startCall(
getApplicationContext(),
new MicrosoftTeamsUserCallIdentifier(calleeId),
options);
}
Aramayı Yanıtlama
Bir çağrıyı kabul etmek, yalnızca geçerli bağlama yönelik bir başvuru kullanılarak teams çağrı aracısı kullanılarak yapılabilir.
public void acceptACall(TeamsIncomingCall teamsIncomingCall){
teamsIncomingCall.accept(this);
}
Teams Çağrısına Katılma
Kullanıcı, bir bağlantı geçirerek mevcut bir aramaya katılabilir.
/**
* Join a call using a teams meeting link.
*/
public TeamsCall joinTeamsCall(TeamsCallAgent teamsCallAgent){
TeamsMeetingLinkLocator link = new TeamsMeetingLinkLocator("meetingLink");
TeamsCall call = teamsCallAgent.join(this, link);
}
Teams Çağrısına seçeneklerle katılma
Ayrıca sessize alma gibi önceden ayarlanmış seçeneklerle mevcut bir çağrıya da katılabiliriz.
/**
* Join a call using a teams meeting link while muted.
*/
public TeamsCall joinTeamsCall(TeamsCallAgent teamsCallAgent){
TeamsMeetingLinkLocator link = new TeamsMeetingLinkLocator("meetingLink");
OutgoingAudioOptions audioOptions = new OutgoingAudioOptions().setMuted(true);
JoinTeamsCallOptions options = new JoinTeamsCallOptions().setAudioOptions(audioOptions);
TeamsCall call = teamsCallAgent.join(this, link, options);
}
Gelen Arama Dinleyicisi Kurulumu
Gelen çağrıları ve bu kullanıcı tarafından yapılmayan diğer eylemleri algılayabilmek için dinleyicilerin ayarlanması gerekir.
private TeamsIncomingCall teamsincomingCall;
teamsCallAgent.addOnIncomingCallListener(this::handleIncomingCall);
private void handleIncomingCall(TeamsIncomingCall incomingCall) {
this.teamsincomingCall = incomingCall;
}
Uygulamayı başlatın ve yankı botunu çağırın
Uygulama artık araç çubuğundaki "Uygulamayı Çalıştır" düğmesi kullanılarak başlatılabilir (Shift+F10). çağrısı 8:echo123
yaparak aramalar yapabildiğinizi doğrulayın. Önceden kaydedilmiş bir ileti yürütülür ve ardından iletinizi size tekrar tekrarlayın.
Uygulamanıza tek bir görüntülü arama eklemek için İletişim Hizmetleri çağrı SDK'sını kullanarak Azure İletişim Hizmetleri kullanmaya başlayın. Teams kimliğini kullanarak iOS için arama SDK'sını Azure İletişim Hizmetleri kullanarak görüntülü arama başlatmayı ve yanıtlamayı öğrenirsiniz.
Örnek Kod
Sonuna atlamak isterseniz bu hızlı başlangıcı GitHub'da örnek olarak indirebilirsiniz.
Önkoşullar
- Etkin aboneliği olan bir Azure hesabı edinin. Ücretsiz hesap oluşturun.
- Anahtar zincirinize yüklenmiş geçerli bir geliştirici sertifikasının yanı sıra Xcode çalıştıran bir Mac.
- Etkin bir İletişim Hizmetleri kaynağı oluşturun. İletişim Hizmetleri kaynağı oluşturun. Bu hızlı başlangıç için bağlantı dizesi kaydetmeniz gerekir.
- Azure İletişim Hizmetiniz için Kullanıcı Erişim Belirteci.
- Graph Explorer'ı kullanarak çağrı işlemleri için Teams iş parçacığı kimliğini alın. Sohbet yazışma kimliği oluşturma hakkında daha fazla bilgi edinin
Ayarlama
Xcode projesi oluşturma
Xcode'da yeni bir iOS projesi oluşturun ve Tek Görünüm Uygulaması şablonunu seçin. Bu öğreticide SwiftUI çerçevesi kullanılır, bu nedenle Dili Swift olarak ve Kullanıcı Arabirimini SwiftUI olarak ayarlamanız gerekir. Bu hızlı başlangıç sırasında test oluşturmayacaksınız. Testleri Dahil Et seçeneğinin işaretini kaldırabilirsiniz.
CocoaPods'u yükleme
Mac bilgisayarınıza CocoaPods yüklemek için bu kılavuzu kullanın.
CocoaPods ile paketi ve bağımlılıkları yükleme
Uygulamanız için bir
Podfile
oluşturmak için terminali açın ve proje klasörüne gidin ve pod init komutunu çalıştırın.öğesine aşağıdaki kodu
Podfile
ekleyin ve kaydedin. Bkz. SDK destek sürümleri.
platform :ios, '13.0'
use_frameworks!
target 'VideoCallingQuickstart' do
pod 'AzureCommunicationCalling', '~> 2.10.0'
end
Pod yüklemesini çalıştırın.
Xcode ile dosyasını
.xcworkspace
açın.
Mikrofona ve kameraya erişim isteme
Cihazın mikrofon ve kamerasına erişmek için, uygulamanızın Bilgi Özellik Listesi'ni ve NSMicrophoneUsageDescription
NSCameraUsageDescription
ile güncelleştirmeniz gerekir. İlişkili değeri, sistemin kullanıcıdan erişim istemek için kullandığı iletişim kutusunu içeren bir dizeye ayarlarsınız.
Proje ağacının girdisine Info.plist
sağ tıklayın ve Kaynak Kodu Olarak > Aç'ı seçin. Aşağıdaki satırları en üst düzey <dict>
bölüme ekleyin ve dosyayı kaydedin.
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>
<key>NSCameraUsageDescription</key>
<string>Need camera access for video calling</string>
Uygulama çerçevesini ayarlama
Projenizin ContentView.swift
dosyasını açın ve ve kitaplığını AVFoundation
içeri aktarmak için dosyanın en üstüne bir içeri aktarma AzureCommunicationCalling
bildirimi ekleyin. AVFoundation, koddan ses izni yakalamak için kullanılır.
import AzureCommunicationCalling
import AVFoundation
Nesne modeli
Aşağıdaki sınıflar ve arabirimler, iOS için Azure İletişim Hizmetleri Çağırma SDK'sının bazı önemli özelliklerini işler.
Veri Akışı Adı | Açıklama |
---|---|
CallClient |
CallClient , Çağrı SDK'sının ana giriş noktasıdır. |
TeamsCallAgent |
TeamsCallAgent , çağrıları başlatmak ve yönetmek için kullanılır. |
TeamsIncomingCall |
TeamsIncomingCall , gelen ekip çağrısını kabul etmek veya reddetmek için kullanılır. |
CommunicationTokenCredential |
, CommunicationTokenCredential örneğini TeamsCallAgent başlatmak için belirteç kimlik bilgisi olarak kullanılır. |
CommunicationIdentifier |
CommunicationIdentifier , kullanıcının kimliğini temsil etmek için kullanılır. Bu, aşağıdaki seçeneklerden biri olabilir: CommunicationUserIdentifier , PhoneNumberIdentifier veya CallingApplication . |
Teams Arama Aracısı oluşturma
ContentView struct
uygulamasını, kullanıcının çağrı başlatmasını ve sonlandırmasını sağlayan bazı basit kullanıcı arabirimi denetimleriyle değiştirin. Bu hızlı başlangıçta bu denetimlere iş mantığı ekleyeceğiz.
struct ContentView: View {
@State var callee: String = ""
@State var callClient: CallClient?
@State var teamsCallAgent: TeamsCallAgent?
@State var teamsCall: TeamsCall?
@State var deviceManager: DeviceManager?
@State var localVideoStream:[LocalVideoStream]?
@State var teamsIncomingCall: TeamsIncomingCall?
@State var sendingVideo:Bool = false
@State var errorMessage:String = "Unknown"
@State var remoteVideoStreamData:[Int32:RemoteVideoStreamData] = [:]
@State var previewRenderer:VideoStreamRenderer? = nil
@State var previewView:RendererView? = nil
@State var remoteRenderer:VideoStreamRenderer? = nil
@State var remoteViews:[RendererView] = []
@State var remoteParticipant: RemoteParticipant?
@State var remoteVideoSize:String = "Unknown"
@State var isIncomingCall:Bool = false
@State var callObserver:CallObserver?
@State var remoteParticipantObserver:RemoteParticipantObserver?
var body: some View {
NavigationView {
ZStack{
Form {
Section {
TextField("Who would you like to call?", text: $callee)
Button(action: startCall) {
Text("Start Teams Call")
}.disabled(teamsCallAgent == nil)
Button(action: endCall) {
Text("End Teams Call")
}.disabled(teamsCall == nil)
Button(action: toggleLocalVideo) {
HStack {
Text(sendingVideo ? "Turn Off Video" : "Turn On Video")
}
}
}
}
// Show incoming call banner
if (isIncomingCall) {
HStack() {
VStack {
Text("Incoming call")
.padding(10)
.frame(maxWidth: .infinity, alignment: .topLeading)
}
Button(action: answerIncomingCall) {
HStack {
Text("Answer")
}
.frame(width:80)
.padding(.vertical, 10)
.background(Color(.green))
}
Button(action: declineIncomingCall) {
HStack {
Text("Decline")
}
.frame(width:80)
.padding(.vertical, 10)
.background(Color(.red))
}
}
.frame(maxWidth: .infinity, alignment: .topLeading)
.padding(10)
.background(Color.gray)
}
ZStack{
VStack{
ForEach(remoteViews, id:\.self) { renderer in
ZStack{
VStack{
RemoteVideoView(view: renderer)
.frame(width: .infinity, height: .infinity)
.background(Color(.lightGray))
}
}
Button(action: endCall) {
Text("End Call")
}.disabled(teamsCall == nil)
Button(action: toggleLocalVideo) {
HStack {
Text(sendingVideo ? "Turn Off Video" : "Turn On Video")
}
}
}
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
VStack{
if(sendingVideo)
{
VStack{
PreviewVideoStream(view: previewView!)
.frame(width: 135, height: 240)
.background(Color(.lightGray))
}
}
}.frame(maxWidth:.infinity, maxHeight:.infinity,alignment: .bottomTrailing)
}
}
.navigationBarTitle("Video Calling Quickstart")
}.onAppear{
// Authenticate the client
// Initialize the TeamsCallAgent and access Device Manager
// Ask for permissions
}
}
}
//Functions and Observers
struct PreviewVideoStream: UIViewRepresentable {
let view:RendererView
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
struct RemoteVideoView: UIViewRepresentable {
let view:RendererView
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
İstemcinin kimliğini doğrulama
Bir TeamsCallAgent
örneği başlatmak için, çağrı yapmasını ve almasını sağlayan bir Kullanıcı Erişim Belirteci gerekir. Kullanılabilir bir belirteciniz yoksa kullanıcı erişim belirteci belgelerine bakın.
Belirteciniz olduktan sonra, içindeki geri ContentView.swift
çağırmaya onAppear
aşağıdaki kodu ekleyin. değerini kaynağınız için geçerli bir kullanıcı erişim belirteci ile değiştirmeniz <USER ACCESS TOKEN>
gerekir:
var userCredential: CommunicationTokenCredential?
do {
userCredential = try CommunicationTokenCredential(token: "<USER ACCESS TOKEN>")
} catch {
print("ERROR: It was not possible to create user credential.")
return
}
Teams CallAgent'ı başlatma ve Aygıt Yöneticisi erişme
bir öğesinden örnek oluşturmak TeamsCallAgent
için, başlatıldıktan sonra zaman uyumsuz olarak bir TeamsCallAgent
nesne döndüren yöntemini kullanıncallClient.createTeamsCallAgent
.CallClient
DeviceManager
, ses/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/kameraya erişim izni istemenizi sağlar.
self.callClient = CallClient()
let options = TeamsCallAgentOptions()
// Enable CallKit in the SDK
options.callKitOptions = CallKitOptions(with: createCXProvideConfiguration())
self.callClient?.createTeamsCallAgent(userCredential: userCredential, options: options) { (agent, error) in
if error != nil {
print("ERROR: It was not possible to create a Teams call agent.")
return
} else {
self.teamsCallAgent = agent
print("Teams Call agent successfully created.")
self.teamsCallAgent!.delegate = teamsIncomingCallHandler
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")
}
}
}
}
İzin iste
Ses ve görüntü izinlerini istemek için geri çağırmaya aşağıdaki kodu onAppear
eklememiz gerekir.
AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
if granted {
AVCaptureDevice.requestAccess(for: .video) { (videoGranted) in
/* NO OPERATION */
}
}
}
Giden arama yerleştirme
yöntemi, startCall
Aramayı Başlat düğmesine dokunulduğunda gerçekleştirilen eylem olarak ayarlanır. Bu hızlı başlangıçta, giden aramalar yalnızca varsayılan olarak seslidir. Görüntülü arama başlatmak için ile ayarlamamız VideoOptions
LocalVideoStream
ve aramanın ilk seçeneklerini ayarlamak için ile geçirmemiz startCallOptions
gerekir.
let startTeamsCallOptions = StartTeamsCallOptions()
if sendingVideo {
if self.localVideoStream == nil {
self.localVideoStream = [LocalVideoStream]()
}
let videoOptions = VideoOptions(localVideoStreams: localVideoStream!)
startTeamsCallOptions.videoOptions = videoOptions
}
let callees: [CommunicationIdentifier] = [CommunicationUserIdentifier(self.callee)]
self.teamsCallAgent?.startCall(participants: callees, options: startTeamsCallOptions) { (call, error) in
// Handle call object if successful or an error.
}
Teams toplantısına katılma
join
yöntemi, kullanıcının teams toplantısına katılmasını sağlar.
let joinTeamsCallOptions = JoinTeamsCallOptions()
if sendingVideo
{
if self.localVideoStream == nil {
self.localVideoStream = [LocalVideoStream]()
}
let videoOptions = VideoOptions(localVideoStreams: localVideoStream!)
joinTeamsCallOptions.videoOptions = videoOptions
}
// Join the Teams meeting muted
if isMuted
{
let outgoingAudioOptions = OutgoingAudioOptions()
outgoingAudioOptions.muted = true
joinTeamsCallOptions.outgoingAudioOptions = outgoingAudioOptions
}
let teamsMeetingLinkLocator = TeamsMeetingLinkLocator(meetingLink: "https://meeting_link")
self.teamsCallAgent?.join(with: teamsMeetingLinkLocator, options: joinTeamsCallOptions) { (call, error) in
// Handle call object if successful or an error.
}
TeamsCallObserver
ve RemotePariticipantObserver
arama ortası olaylarını ve uzak katılımcıları yönetmek için kullanılır. İşlevdeki gözlemcileri ayarladık setTeamsCallAndObserver
.
func setTeamsCallAndObserver(call:TeamsCall, error:Error?) {
if (error == nil) {
self.teamsCall = call
self.teamsCallObserver = TeamsCallObserver(self)
self.teamsCall!.delegate = self.teamsCallObserver
// Attach a RemoteParticipant observer
self.remoteParticipantObserver = RemoteParticipantObserver(self)
} else {
print("Failed to get teams call object")
}
}
Gelen aramayı yanıtlama
Gelen aramayı yanıtlamak için, aramayı yanıtlamak veya reddetmek için gelen arama başlığını görüntülemek için bir TeamsIncomingCallHandler
uygulayın. Aşağıdaki uygulamayı içine TeamsIncomingCallHandler.swift
yerleştirin.
final class TeamsIncomingCallHandler: NSObject, TeamsCallAgentDelegate, TeamsIncomingCallDelegate {
public var contentView: ContentView?
private var teamsIncomingCall: TeamsIncomingCall?
private static var instance: TeamsIncomingCallHandler?
static func getOrCreateInstance() -> TeamsIncomingCallHandler {
if let c = instance {
return c
}
instance = TeamsIncomingCallHandler()
return instance!
}
private override init() {}
func teamsCallAgent(_ teamsCallAgent: TeamsCallAgent, didRecieveIncomingCall incomingCall: TeamsIncomingCall) {
self.teamsIncomingCall = incomingCall
self.teamsIncomingCall.delegate = self
contentView?.showIncomingCallBanner(self.teamsIncomingCall!)
}
func teamsCallAgent(_ teamsCallAgent: TeamsCallAgent, didUpdateCalls args: TeamsCallsUpdatedEventArgs) {
if let removedCall = args.removedCalls.first {
contentView?.callRemoved(removedCall)
self.teamsIncomingCall = nil
}
}
}
içindeki geri ContentView.swift
çağırmaya aşağıdaki kodu onAppear
ekleyerek örneğini TeamsIncomingCallHandler
oluşturmamız gerekir:
Başarıyla oluşturulduktan sonra TeamsCallAgent
için TeamsCallAgent
bir temsilci ayarlayın:
self.teamsCallAgent!.delegate = incomingCallHandler
Gelen bir çağrı olduğunda işlevi TeamsIncomingCallHandler
çağırarak showIncomingCallBanner
ve decline
düğmesini görüntüleranswer
.
func showIncomingCallBanner(_ incomingCall: TeamsIncomingCall) {
self.teamsIncomingCall = incomingCall
}
ve decline
öğesine answer
eklenen eylemler aşağıdaki kod olarak uygulanır. Aramayı görüntülü olarak yanıtlamak için yerel videoyu açmamız ve ile localVideoStream
seçeneklerini AcceptCallOptions
ayarlamamız gerekir.
func answerIncomingCall() {
let options = AcceptTeamsCallOptions()
guard let teamsIncomingCall = self.teamsIncomingCall else {
print("No active incoming call")
return
}
guard let deviceManager = deviceManager else {
print("No device manager instance")
return
}
if self.localVideoStreams == nil {
self.localVideoStreams = [LocalVideoStream]()
}
if sendingVideo
{
guard let camera = deviceManager.cameras.first else {
// Handle failure
return
}
self.localVideoStreams?.append( LocalVideoStream(camera: camera))
let videoOptions = VideoOptions(localVideoStreams: localVideosStreams!)
options.videoOptions = videoOptions
}
teamsIncomingCall.accept(options: options) { (call, error) in
// Handle call object if successful or an error.
}
}
func declineIncomingCall() {
self.teamsIncomingCall?.reject { (error) in
// Handle if rejection was successfully or not.
}
}
Olaylara Abone Olma
Çağrı sırasında değerler değiştiğinde bildirim almak üzere bir olay koleksiyonuna abone olmak için bir sınıf uygulayabiliriz TeamsCallObserver
.
public class TeamsCallObserver: NSObject, TeamsCallDelegate, TeamsIncomingCallDelegate {
private var owner: ContentView
init(_ view:ContentView) {
owner = view
}
public func teamsCall(_ teamsCall: TeamsCall, didChangeState args: PropertyChangedEventArgs) {
if(teamsCall.state == CallState.connected) {
initialCallParticipant()
}
}
// render remote video streams when remote participant changes
public func teamsCall(_ teamsCall: TeamsCall, didUpdateRemoteParticipant args: ParticipantsUpdatedEventArgs) {
for participant in args.addedParticipants {
participant.delegate = self.remoteParticipantObserver
}
}
// Handle remote video streams when the call is connected
public func initialCallParticipant() {
for participant in owner.teamsCall.remoteParticipants {
participant.delegate = self.remoteParticipantObserver
for stream in participant.videoStreams {
renderRemoteStream(stream)
}
owner.remoteParticipant = participant
}
}
}
Kodu çalıştırma
Ürün > Çalıştır'ı seçerek veya (⌘-R) klavye kısayolunu kullanarak uygulamanızı iOS simülatöründe derleyebilir ve çalıştırabilirsiniz.
Kaynakları temizleme
İletişim Hizmetleri aboneliğini temizlemek ve kaldırmak istiyorsanız, kaynağı veya kaynak grubunu silebilirsiniz. Kaynak grubunun silinmesi, kaynak grubuyla ilişkili diğer tüm kaynakları da siler. Kaynakları temizleme hakkında daha fazla bilgi edinin.
Sonraki adımlar
Daha fazla bilgi için aşağıdaki makaleleri inceleyin:
- Web arama örneğimize göz atın
- SDK'ları çağırma özellikleri hakkında bilgi edinin
- Aramanın nasıl çalıştığı hakkında daha fazla bilgi edinin