Hızlı Başlangıç: Arama uygulamanızı Teams toplantısına ekleme
Bu hızlı başlangıçta, JavaScript için Azure İletişim Hizmetleri Arama SDK'sını kullanarak Teams toplantısına katılmayı öğreneceksiniz.
Örnek Kod
GitHub'da bu hızlı başlangıcın son halini alan kodu bulun.
Önkoşullar
- Web uygulamasını çağıran çalışan bir İletişim Hizmetleri.
- Teams dağıtımı.
- Teams toplantı kimliği ve geçiş kodu katılım API'si için desteklenen En Düşük Sürüm: 1.17.1
- Erişim belirteci.
Teams kullanıcı arabirimi denetimlerini ekleme
index.html içindeki kodu aşağıdaki kod parçacığıyla değiştirin. Teams Toplantısı bağlantısı veya Teams Toplantı Kimliği ve Geçiş Kodu aracılığıyla Teams toplantısına katılın. Metin kutuları Teams toplantı bağlamını girmek için kullanılır ve düğme de belirtilen toplantıya katılmak için kullanılır:
<!DOCTYPE html>
<html>
<head>
<title>Communication Client - Calling Sample</title>
</head>
<body>
<h4>Azure Communication Services</h4>
<h1>Teams meeting join quickstart</h1>
<input id="teams-link-input" type="text" placeholder="Teams meeting link"
style="margin-bottom:1em; width: 300px;" />
<p><input id="teams-meetingId-input" type="text" placeholder="Teams meetingId"
style="margin-bottom:1em; width: 300px;" /></p>
<p><input id="teams-passcode-input" type="text" placeholder="Teams meeting Passcode"
style="margin-bottom:1em; width: 300px;" /></p>
<p>Call state <span style="font-weight: bold" id="call-state">-</span></p>
<p><span style="font-weight: bold" id="recording-state"></span></p>
<div>
<button id="join-meeting-button" type="button" disabled="false">
Join Teams Meeting
</button>
<button id="hang-up-button" type="button" disabled="true">
Hang Up
</button>
</div>
<script src="./app.js" type="module"></script>
</body>
</html>
Teams kullanıcı arabirimi denetimlerini etkinleştirme
app.js dosyasının içeriğini aşağıdaki kod parçacığıyla değiştirin.
import { CallClient } from "@azure/communication-calling";
import { Features } from "@azure/communication-calling";
import { AzureCommunicationTokenCredential } from '@azure/communication-common';
let call;
let callAgent;
const meetingLinkInput = document.getElementById('teams-link-input');
const meetingIdInput = document.getElementById('teams-meetingId-input');
const meetingPasscodeInput = document.getElementById('teams-passcode-input');
const hangUpButton = document.getElementById('hang-up-button');
const teamsMeetingJoinButton = document.getElementById('join-meeting-button');
const callStateElement = document.getElementById('call-state');
const recordingStateElement = document.getElementById('recording-state');
async function init() {
const callClient = new CallClient();
const tokenCredential = new AzureCommunicationTokenCredential("<USER ACCESS TOKEN>");
callAgent = await callClient.createCallAgent(tokenCredential, {displayName: 'Test user'});
teamsMeetingJoinButton.disabled = false;
}
init();
hangUpButton.addEventListener("click", async () => {
// end the current call
await call.hangUp();
// toggle button states
hangUpButton.disabled = true;
teamsMeetingJoinButton.disabled = false;
callStateElement.innerText = '-';
});
teamsMeetingJoinButton.addEventListener("click", () => {
// join with meeting link
call = callAgent.join({meetingLink: meetingLinkInput.value}, {});
//(or) to join with meetingId and passcode use the below code snippet.
//call = callAgent.join({meetingId: meetingIdInput.value, passcode: meetingPasscodeInput.value}, {});
call.on('stateChanged', () => {
callStateElement.innerText = call.state;
})
call.api(Features.Recording).on('isRecordingActiveChanged', () => {
if (call.api(Features.Recording).isRecordingActive) {
recordingStateElement.innerText = "This call is being recorded";
}
else {
recordingStateElement.innerText = "";
}
});
// toggle button states
hangUpButton.disabled = false;
teamsMeetingJoinButton.disabled = true;
});
Teams toplantı bağlantısını alma
Teams toplantı bağlantısı, Graph belgelerinde ayrıntılı olarak açıklanan Graph API'leri kullanılarak alınabilir.
İletişim Hizmetleri Arama SDK'sı tam bir Teams toplantı bağlantısını kabul eder. Bu bağlantı kaynağın onlineMeeting
bir parçası olarak döndürülür ve özelliğinden joinWebUrl
erişilebilir. Ayrıca, Teams toplantı davetindeki Toplantıya Katıl URL'sinden gerekli toplantı bilgilerini de alabilirsiniz.
Teams toplantı kimliğini ve geçiş kodunu alma
- Graph API:OnlineMeeting kaynağı hakkında bilgi almak ve joinMeetingIdSettings özelliğindeki nesneyi denetlemek için Graph API'sini kullanın.
- Teams: Teams uygulamanızda Takvim uygulamasına gidin ve toplantının ayrıntılarını açın. Çevrimiçi toplantılar, toplantının tanımında toplantı kimliğine ve geçiş koduna sahiptir.
- Outlook: Toplantı kimliğini ve geçiş kodunu takvim olaylarında veya e-posta toplantı davetlerinde bulabilirsiniz.
Kodu çalıştırma
Uygulama konağınızı yerel bir web sunucusunda 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 http://localhost:8080/. Şunları görmeniz gerekir:
Teams bağlamını metin kutusuna ekleyin ve teams toplantısına İletişim Hizmetleri uygulamanızın içinden katılmak için Teams Toplantısına Katıl'a basın.
Bu hızlı başlangıçta, Windows için Azure İletişim Hizmetleri Arama SDK'sını kullanarak Teams toplantısına katılmayı öğreneceksiniz.
Örnek Kod
UWP ve WinUI 3 için GitHub'da bu hızlı başlangıcın son halini alan kodu bulun.
Önkoşullar
- Windows uygulamasını çağıran çalışan bir İletişim Hizmetleri.
- Teams dağıtımı.
- Teams toplantı kimliği ve geçiş kodu katılım API'si için desteklenen En Düşük Sürüm: 1.7.0
- Erişim belirteci.
Teams kullanıcı arabirimi denetimlerini ekleme ve Teams kullanıcı arabirimi denetimlerini etkinleştirme
MainPage.xaml dosyasındaki kodu aşağıdaki kod parçacığıyla değiştirin. Metin kutusu Teams toplantı bağlamını girmek için kullanılır ve düğme belirtilen toplantıya katılmak için kullanılır:
<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>
<Grid Grid.Row="0" x:Name="AppTitleBar" Background="LightSeaGreen">
<!-- Width of the padding columns is set in LayoutMetricsChanged handler. -->
<!-- Using padding columns instead of Margin ensures that the background paints the area under the caption control buttons (for transparent buttons). -->
<TextBlock x:Name="QuickstartTitle" Text="Calling Quickstart sample title bar" Style="{StaticResource CaptionTextBlockStyle}" Padding="7,7,0,0"/>
</Grid>
<StackPanel Grid.Row="1">
<TextBox x:Name="CalleeTextBox" PlaceholderText="Who would you like to call?" TextWrapping="Wrap" VerticalAlignment="Center" />
<TextBlock Text="or" Padding="7,7,0,0" />
<TextBox x:Name="CalleeMeetingId" PlaceholderText="Teams Meeting Id" TextWrapping="Wrap" VerticalAlignment="Center" />
<TextBox x:Name="CalleeMeetingPasscode" PlaceholderText="Teams Meeting Passcode" TextWrapping="Wrap" VerticalAlignment="Center" />
</StackPanel>
<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"/>
</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>
Teams kullanıcı arabirimi denetimlerini etkinleştirme
öğesinin içeriğini MainPage.xaml.cs
aşağıdaki kod parçacığıyla değiştirin:
using Azure.Communication.Calling.WindowsClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Media.Core;
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 CallAgent callAgent;
private CommunicationCall call;
private LocalOutgoingAudioStream micStream;
private LocalOutgoingVideoStream cameraStream;
#region Page initialization
public MainPage()
{
this.InitializeComponent();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await InitCallAgentAndDeviceManagerAsync();
base.OnNavigatedTo(e);
}
#endregion
#region UI event handlers
private async void CallButton_Click(object sender, RoutedEventArgs e)
{
var callString = CalleeTextBox.Text.Trim();
var meetingId = CalleeMeetingId.Text.Trim();
var passcode = CalleeMeetingPasscode.Text.Trim();
// join with meeting link
if (!string.IsNullOrEmpty(callString))
{
call = await JoinTeamsMeetingByLinkAsync(teamsMeetinglink);
}
// (or) to join with meetingId and passcode use the below code snippet.
// call = await JoinTeamsMeetingByMeetingIdAsync(meetingId, passcode);
if (call != null)
{
call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
call.StateChanged += OnStateChangedAsync;
}
}
private async void HangupButton_Click(object sender, RoutedEventArgs e)
{
var call = this.callAgent?.Calls?.FirstOrDefault();
if (call != null)
{
foreach (var localVideoStream in call.OutgoingVideoStreams)
{
await call.StopVideoAsync(localVideoStream);
}
if (cameraStream != null)
{
await cameraStream.StopPreviewAsync();
}
await call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
}
}
#endregion
#region API event handlers
private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
{
var call = sender as CommunicationCall;
if (call != null)
{
var state = call.State;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
QuickstartTitle.Text = $"{Package.Current.DisplayName} - {state.ToString()}";
Window.Current.SetTitleBar(AppTitleBar);
HangupButton.IsEnabled = state == CallState.Connected || state == CallState.Ringing;
CallButton.IsEnabled = !HangupButton.IsEnabled;
});
switch (state)
{
case CallState.Connected:
{
await call.StartAudioAsync(micStream);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
Stats.Text = $"Call id: {Guid.Parse(call.Id).ToString("D")}, Remote caller id: {call.RemoteParticipants.FirstOrDefault()?.Identifier.RawId}";
});
break;
}
case CallState.Disconnected:
{
call.RemoteParticipantsUpdated -= OnRemoteParticipantsUpdatedAsync;
call.StateChanged -= OnStateChangedAsync;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
Stats.Text = $"Call ended: {call.CallEndReason.ToString()}";
});
call.Dispose();
break;
}
default: break;
}
}
}
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.Stream;
switch (callVideoStream.Direction)
{
case StreamDirection.Outgoing:
OnOutgoingVideoStreamStateChanged(callVideoStream as OutgoingVideoStream);
break;
case StreamDirection.Incoming:
OnIncomingVideoStreamStateChangedAsync(callVideoStream as IncomingVideoStream);
break;
}
}
private async void OnIncomingVideoStreamStateChangedAsync(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);
});
break;
case VideoStreamKind.RawIncoming:
break;
}
break;
case VideoStreamState.Started:
break;
case VideoStreamState.Stopping:
case VideoStreamState.Stopped:
if (incomingVideoStream.Kind == VideoStreamKind.RemoteIncoming)
{
var remoteVideoStream = incomingVideoStream as RemoteIncomingVideoStream;
await remoteVideoStream.StopPreviewAsync();
}
break;
case VideoStreamState.NotAvailable:
break;
}
}
#endregion
#region Helpers
private async Task InitCallAgentAndDeviceManagerAsync()
{
this.callClient = new CallClient(new CallClientOptions() {
Diagnostics = new CallDiagnosticsOptions() {
AppName = "CallingQuickstart",
AppVersion="1.0",
Tags = new[] { "Calling", "ACS", "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();
if (camera != null)
{
cameraStream = new LocalOutgoingVideoStream(selectedCamera);
var localUri = await cameraStream.StartPreviewAsync();
LocalVideo.Source = MediaSource.CreateFromUri(localUri);
if (call != null) {
await call?.StartVideoAsync(cameraStream);
}
}
var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);
var callAgentOptions = new CallAgentOptions()
{
DisplayName = $"{Environment.MachineName}/{Environment.UserName}",
};
this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
// Sets up additional event sinks
}
private async Task<CommunicationCall> JoinTeamsMeetingByLinkAsync(Uri teamsCallLink)
{
var joinCallOptions = GetJoinCallOptions();
var teamsMeetingLinkLocator = new TeamsMeetingLinkLocator(teamsCallLink.AbsoluteUri);
var call = await callAgent.JoinAsync(teamsMeetingLinkLocator, joinCallOptions);
return call;
}
private async Task<CommunicationCall> JoinTeamsMeetingByMeetingIdAsync(String meetingId, String passcode)
{
var joinCallOptions = GetJoinCallOptions();
var teamsMeetingIdLocator = new TeamsMeetingIdLocator(meetingId, passcode);
var call = await callAgent.JoinAsync(teamsMeetingIdLocator, joinCallOptions);
return call;
}
private JoinCallOptions GetJoinCallOptions()
{
return new JoinCallOptions() {
OutgoingAudioOptions = new OutgoingAudioOptions() { IsMuted = true },
OutgoingVideoOptions = new OutgoingVideoOptions() { Streams = new OutgoingVideoStream[] { cameraStream } }
};
}
#endregion
}
}
Teams toplantı bağlantısını alma
Teams toplantı bağlantısı Graph API'leri kullanılarak alınabilir. Bu, Graph belgelerinde ayrıntılı olarak yer alır.
İletişim Hizmetleri Arama SDK'sı tam bir Teams toplantı bağlantısını kabul eder. Bu bağlantı kaynağın onlineMeeting
bir parçası olarak döndürülür ve özelliğinden joinWebUrl
erişilebilir. Ayrıca, Teams toplantı davetinin kendisindeki Toplantıya Katıl URL'sinden de gerekli toplantı bilgilerini alabilirsiniz.
Teams toplantı kimliğini ve geçiş kodunu alma
- Graph API:OnlineMeeting kaynağı hakkındaki bilgileri almak ve özelliğindeki
joinMeetingIdSettings
nesnesini denetlemek için Graph API'sini kullanın. - Teams: Teams uygulamanızda Takvim uygulamasına gidin ve toplantının ayrıntılarını açın. Çevrimiçi toplantılar, toplantının tanımında toplantı kimliğine ve geçiş koduna sahiptir.
- Outlook: Toplantı kimliğini ve geçiş kodunu takvim olaylarında veya e-posta toplantı davetlerinde bulabilirsiniz.
Uygulamayı başlatma ve Teams toplantısına katılma
Hata AyıklamaYı>Başlat Hata Ayıklama'ya tıklayarak veya (F5) klavye kısayolunu kullanarak uygulamanızı Visual Studio'da derleyebilir ve çalıştırabilirsiniz.
Teams bağlamını metin kutusuna ekleyin ve teams toplantısına İletişim Hizmetleri uygulamanızın içinden katılmak için Teams Toplantısına Katıl'a basın.
Bu hızlı başlangıçta, Android için Azure İletişim Hizmetleri Arama SDK'sını kullanarak Teams toplantısına katılmayı öğreneceksiniz.
Örnek Kod
GitHub'da bu hızlı başlangıcın son halini alan kodu bulun.
Önkoşullar
- Android uygulamasını çağıran çalışan bir İletişim Hizmetleri.
- Teams dağıtımı.
- Teams toplantı kimliği ve geçiş kodu katılım API'si için desteklenen En Düşük Sürüm: 2.9.0
- Erişim belirteci.
Teams kullanıcı arabirimi denetimlerini ekleme
activity_main.xml içindeki kodu aşağıdaki kod parçacığıyla değiştirin. Metin kutusu Teams toplantı bağlamını girmek için kullanılır ve düğme belirtilen toplantıya katılmak için kullanılır:
<?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">
<LinearLayout
android:id="@+id/meetingInfoLinearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginTop="100dp">
<EditText
android:id="@+id/teams_meeting_link"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Teams meeting link"
android:inputType="textUri" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="or"
android:textAlignment="center"
android:layout_marginTop="10dp"/>
<EditText
android:id="@+id/teams_meeting_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Teams meeting id"
android:inputType="textUri" />
<EditText
android:id="@+id/teams_meeting_passcode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Teams meeting passcode"
android:inputType="textUri" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="70dp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/join_meeting_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Meeting" />
<Button
android:id="@+id/hangup_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hangup" />
</LinearLayout>
<TextView
android:id="@+id/call_status_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/recording_status_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Teams kullanıcı arabirimi denetimlerini etkinleştirme
öğesinin içeriğini MainActivity.java
aşağıdaki kod parçacığıyla değiştirin:
package com.contoso.acsquickstart;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import com.azure.android.communication.calling.Call;
import com.azure.android.communication.calling.CallAgent;
import com.azure.android.communication.calling.CallClient;
import com.azure.android.communication.calling.HangUpOptions;
import com.azure.android.communication.calling.JoinCallOptions;
import com.azure.android.communication.common.CommunicationTokenCredential;
import com.azure.android.communication.calling.TeamsMeetingLinkLocator;
// import for meeting id and passcode join
// import com.azure.android.communication.calling.TeamsMeetingIdLocator;
public class MainActivity extends AppCompatActivity {
private static final String[] allPermissions = new String[] { Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE };
private static final String UserToken = "<User_Access_Token>";
TextView callStatusBar;
TextView recordingStatusBar;
private CallAgent agent;
private Call call;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getAllPermissions();
createAgent();
Button joinMeetingButton = findViewById(R.id.join_meeting_button);
joinMeetingButton.setOnClickListener(l -> joinTeamsMeeting());
Button hangupButton = findViewById(R.id.hangup_button);
hangupButton.setOnClickListener(l -> leaveMeeting());
callStatusBar = findViewById(R.id.call_status_bar);
recordingStatusBar = findViewById(R.id.recording_status_bar);
}
/**
* Join Teams meeting
*/
private void joinTeamsMeeting() {
if (UserToken.startsWith("<")) {
Toast.makeText(this, "Please enter token in source code", Toast.LENGTH_SHORT).show();
return;
}
EditText calleeIdView = findViewById(R.id.teams_meeting_link);
EditText calleeMeetingId = findViewById(R.id.teams_meeting_id);
EditText calleeMeetingPasscode = findViewById(R.id.teams_meeting_passcode);
String meetingLink = calleeIdView.getText().toString();
String meetingId = calleeMeetingId.getText().toString();
String passcode = calleeMeetingPasscode.getText().toString();
if (meetingLink.isEmpty()) {
Toast.makeText(this, "Please enter Teams meeting link", Toast.LENGTH_SHORT).show();
return;
}
JoinCallOptions options = new JoinCallOptions();
// join with meeting link
TeamsMeetingLinkLocator teamsMeetingLocator = new TeamsMeetingLinkLocator(meetingLink);
// (or) to join with meetingId and passcode use the below code snippet.
//TeamsMeetingIdLocator teamsMeetingIdLocator = new TeamsMeetingIdLocator(meetingId, passcode);
call = agent.join(
getApplicationContext(),
teamsMeetingLocator,
options);
call.addOnStateChangedListener(p -> setCallStatus(call.getState().toString()));
call.addOnIsRecordingActiveChangedListener(p -> setRecordingStatus(call.isRecordingActive()));
}
/**
* Leave from the meeting
*/
private void leaveMeeting() {
try {
call.hangUp(new HangUpOptions()).get();
} catch (ExecutionException | InterruptedException e) {
Toast.makeText(this, "Unable to leave meeting", Toast.LENGTH_SHORT).show();
}
}
/**
* Create the call agent
*/
private void createAgent() {
try {
CommunicationTokenCredential credential = new CommunicationTokenCredential(UserToken);
agent = new CallClient().createCallAgent(getApplicationContext(), credential).get();
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), "Failed to create call agent.", Toast.LENGTH_SHORT).show();
}
}
/**
* Request each required permission if the app doesn't already have it.
*/
private void getAllPermissions() {
ArrayList<String> permissionsToAskFor = new ArrayList<>();
for (String permission : allPermissions) {
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
permissionsToAskFor.add(permission);
}
}
if (!permissionsToAskFor.isEmpty()) {
ActivityCompat.requestPermissions(this, permissionsToAskFor.toArray(new String[0]), 1);
}
}
/**
* Ensure all permissions were granted, otherwise inform the user permissions are missing.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, int[] grantResults) {
boolean allPermissionsGranted = true;
for (int result : grantResults) {
allPermissionsGranted &= (result == PackageManager.PERMISSION_GRANTED);
}
if (!allPermissionsGranted) {
Toast.makeText(this, "All permissions are needed to make the call.", Toast.LENGTH_LONG).show();
finish();
}
}
/**
* Shows call status in status bar
*/
private void setCallStatus(String status) {
runOnUiThread(() -> callStatusBar.setText(status));
}
/**
* Shows recording status bar
*/
private void setRecordingStatus(boolean status) {
if (status == true) {
runOnUiThread(() -> recordingStatusBar.setText("This call is being recorded"));
}
else {
runOnUiThread(() -> recordingStatusBar.setText(""));
}
}
}
Teams toplantı bağlantısını alma
Teams toplantı bağlantısı Graph API'leri kullanılarak alınabilir. Bu, Graph belgelerinde ayrıntılı olarak yer alır.
İletişim Hizmetleri Arama SDK'sı tam bir Teams toplantı bağlantısını kabul eder. Bu bağlantı kaynağın onlineMeeting
bir parçası olarak döndürülür ve özelliğinden joinWebUrl
erişilebilir. Ayrıca, Teams toplantı davetinin kendisindeki Toplantıya Katıl URL'sinden de gerekli toplantı bilgilerini alabilirsiniz.
Teams toplantı kimliğini ve geçiş kodunu alma
- Graph API:OnlineMeeting kaynağı hakkında bilgi almak ve joinMeetingIdSettings özelliğindeki nesneyi denetlemek için Graph API'sini kullanın.
- Teams: Teams uygulamanızda Takvim uygulamasına gidin ve toplantının ayrıntılarını açın. Çevrimiçi toplantılar, toplantının tanımında toplantı kimliğine ve geçiş koduna sahiptir.
- Outlook: Toplantı kimliğini ve geçiş kodunu takvim olaylarında veya e-posta toplantı davetlerinde bulabilirsiniz.
Uygulamayı başlatma ve Teams toplantısına katılma
Uygulama artık araç çubuğundaki "Uygulamayı Çalıştır" düğmesi kullanılarak başlatılabilir (Shift+F10). Şunları görmeniz gerekir:
Teams bağlamını metin kutusuna ekleyin ve İletişim Hizmetleri uygulamanızın içinden Teams toplantısına katılmak için Toplantıya Katıl'a basın.
Bu hızlı başlangıçta, iOS için Azure İletişim Hizmetleri Arama SDK'sını kullanarak Teams toplantısına katılmayı öğreneceksiniz.
Önkoşullar
- iOS uygulamasını çağıran çalışan bir İletişim Hizmetleri.
- Teams dağıtımı.
- Teams toplantı kimliği ve geçiş kodu katılım API'si için desteklenen En Düşük Sürüm: 2.11.0
- Erişim belirteci.
Bu hızlı başlangıç için AzureCommunicationCalling SDK'sının beta.12 sürümünü kullanacağız, bu nedenle pod dosyasını güncelleştirmemiz ve Pod'ları yeniden yüklememiz gerekiyor.
Podfile'ınızı Podfile ile aşağıdaki kodla değiştirin ve kaydedin ("hedefin" projenizin adıyla eşleştiğinden emin olun):
platform :ios, '13.0'
use_frameworks!
target 'AzureCommunicationCallingSample' do
pod 'AzureCommunicationCalling', '1.0.0-beta.12'
end
Pods klasörünüzü, Podfile.lock ve .xcworkspace.
dosyayı silin.
komutunu çalıştırın pod install
ve Xcode ile açın .xcworkspace
.
Teams kullanıcı arabirimi denetimlerini ekleme ve Teams kullanıcı arabirimi denetimlerini etkinleştirme
ContentView.swift dosyasındaki kodu aşağıdaki kod parçacığıyla değiştirin. Metin kutusu Teams toplantı bağlamını girmek için kullanılır ve düğme belirtilen toplantıya katılmak için kullanılır:
import SwiftUI
import AzureCommunicationCalling
import AVFoundation
struct ContentView: View {
@State var meetingLink: String = ""
@State var meetingId: String = ""
@State var meetingPasscode: String = ""
@State var callStatus: String = ""
@State var message: String = ""
@State var recordingStatus: String = ""
@State var callClient: CallClient?
@State var callAgent: CallAgent?
@State var call: Call?
@State var callObserver: CallObserver?
var body: some View {
NavigationView {
Form {
Section {
TextField("Teams meeting link", text: $meetingLink)
TextField("Teams meeting id", text: $meetingId)
TextField("Teams meeting passcode", text: $meetingPasscode)
Button(action: joinTeamsMeeting) {
Text("Join Teams Meeting")
}.disabled(callAgent == nil)
Button(action: leaveMeeting) {
Text("Leave Meeting")
}.disabled(call == nil)
Text(callStatus)
Text(message)
Text(recordingStatus)
}
}
.navigationBarTitle("Calling Quickstart")
}.onAppear {
// Initialize call agent
var userCredential: CommunicationTokenCredential?
do {
userCredential = try CommunicationTokenCredential(token: "<USER ACCESS TOKEN>")
} catch {
print("ERROR: It was not possible to create user credential.")
self.message = "Please enter your token in source code"
return
}
self.callClient = CallClient()
// Creates the call agent
self.callClient?.createCallAgent(userCredential: userCredential!) { (agent, error) in
if error != nil {
self.message = "Failed to create CallAgent."
return
} else {
self.callAgent = agent
self.message = "Call agent successfully created."
}
}
}
}
func joinTeamsMeeting() {
// Ask permissions
AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
if granted {
let joinCallOptions = JoinCallOptions()
// join with meeting link
let teamsMeetingLocator = TeamsMeetingLinkLocator(meetingLink: self.meetingLink)
// (or) to join with meetingId and passcode use the below code snippet.
// let teamsMeetingLocator = TeamsMeetingIdLocator(with: self.meetingId, passcode: self.meetingPasscode)
self.callAgent?.join(with: teamsMeetingLocator, joinCallOptions: joinCallOptions) {(call, error) in
if (error == nil) {
self.call = call
self.callObserver = CallObserver(self)
self.call!.delegate = self.callObserver
self.message = "Teams meeting joined successfully"
} else {
print("Failed to get call object")
return
}
}
}
}
}
func leaveMeeting() {
if let call = call {
call.hangUp(options: nil, completionHandler: { (error) in
if error == nil {
self.message = "Leaving Teams meeting was successful"
} else {
self.message = "Leaving Teams meeting failed"
}
})
} else {
self.message = "No active call to hangup"
}
}
}
class CallObserver : NSObject, CallDelegate {
private var owner:ContentView
init(_ view:ContentView) {
owner = view
}
public func call(_ call: Call, didChangeState args: PropertyChangedEventArgs) {
owner.callStatus = CallObserver.callStateToString(state: call.state)
if call.state == .disconnected {
owner.call = nil
owner.message = "Left Meeting"
} else if call.state == .inLobby {
owner.message = "Waiting in lobby !!"
} else if call.state == .connected {
owner.message = "Joined Meeting !!"
}
}
public func call(_ call: Call, didChangeRecordingState args: PropertyChangedEventArgs) {
if (call.isRecordingActive == true) {
owner.recordingStatus = "This call is being recorded"
}
else {
owner.recordingStatus = ""
}
}
private static func callStateToString(state: CallState) -> String {
switch state {
case .connected: return "Connected"
case .connecting: return "Connecting"
case .disconnected: return "Disconnected"
case .disconnecting: return "Disconnecting"
case .earlyMedia: return "EarlyMedia"
case .none: return "None"
case .ringing: return "Ringing"
case .inLobby: return "InLobby"
default: return "Unknown"
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Teams toplantı bağlantısını alma
Teams toplantı bağlantısı Graph API'leri kullanılarak alınabilir. Bu, Graph belgelerinde ayrıntılı olarak yer alır.
İletişim Hizmetleri Arama SDK'sı tam bir Teams toplantı bağlantısını kabul eder. Bu bağlantı kaynağın onlineMeeting
bir parçası olarak döndürülür ve özelliğinden joinWebUrl
erişilebilir. Ayrıca, Teams toplantı davetinin kendisindeki Toplantıya Katıl URL'sinden de gerekli toplantı bilgilerini alabilirsiniz.
Uygulamayı başlatma ve Teams toplantısına katılma
Ü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.
Teams bağlamını metin kutusuna ekleyin ve teams toplantısına İletişim Hizmetleri uygulamanızın içinden katılmak için Teams Toplantısına Katıl'a basın.
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:
- Çağrı hero örneğimize göz atın
- Kullanıcı Arabirimi Kitaplığı'nı kullanmaya başlama
- SDK'ları çağırma özellikleri hakkında bilgi edinin
- Aramanın nasıl çalıştığı hakkında daha fazla bilgi edinin