Szybki start: dołączanie aplikacji wywołującej do spotkania usługi Teams
Z tego przewodnika Szybki start dowiesz się, jak dołączyć do spotkania usługi Teams przy użyciu zestawu SDK wywołującego usługi Azure Communication Services dla języka JavaScript.
Przykładowy kod
Znajdź sfinalizowany kod dla tego przewodnika Szybki start w witrynie GitHub.
Wymagania wstępne
- Działająca usługa Communication Services wywołująca aplikację internetową.
- Wdrożenie usługi Teams.
- Minimalna wersja obsługiwana dla identyfikatora spotkania usługi Teams i interfejsu API dołączania kodu dostępu: 1.17.1
- Token dostępu.
Dodawanie kontrolek interfejsu użytkownika usługi Teams
Zastąp kod w index.html poniższym fragmentem kodu. Dołącz do spotkania usługi Teams za pośrednictwem linku spotkania usługi Teams lub identyfikatora spotkania usługi Teams i kodu dostępu. Pola tekstowe służą do wprowadzania kontekstu spotkania usługi Teams, a przycisk służy do dołączania do określonego spotkania:
<!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>
Włączanie kontrolek interfejsu użytkownika usługi Teams
Zastąp zawartość pliku app.js poniższym fragmentem kodu.
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;
});
Pobierz link do spotkania usługi Teams
Link do spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph, które są szczegółowo opisane w dokumentacji programu Graph.
Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams. Ten link jest zwracany jako część onlineMeeting
zasobu dostępnegojoinWebUrl
w ramach właściwości . Możesz również uzyskać wymagane informacje o spotkaniu z adresu URL spotkania dołączenia w zaproszeniu do spotkania w aplikacji Teams.
Uzyskiwanie identyfikatora spotkania i kodu dostępu aplikacji Teams
- Interfejs API programu Graph: użyj interfejsu API programu Graph, aby pobrać informacje o zasobie onlineMeeting i sprawdzić obiekt we właściwości joinMeetingIdSettings.
- Teams: w aplikacji Teams przejdź do aplikacji Kalendarz i otwórz szczegóły spotkania. Spotkania online mają identyfikator spotkania i kod dostępu w definicji spotkania.
- Outlook: Identyfikator spotkania i kod dostępu można znaleźć w wydarzeniach kalendarza lub w zaproszeniach na spotkanie e-mail.
Uruchamianie kodu
Uruchom następujące polecenie, aby utworzyć pakiet hosta aplikacji na lokalnym serwerze internetowym:
npx webpack serve --config webpack.config.js
Otwórz przeglądarkę i przejdź do strony http://localhost:8080/. Powinien zostać wyświetlony następujący ekran:
Wstaw kontekst usługi Teams do pola tekstowego i naciśnij pozycję Dołącz do spotkania usługi Teams, aby dołączyć do spotkania usługi Teams z poziomu aplikacji Communication Services.
W tym przewodniku Szybki start dowiesz się, jak dołączyć do spotkania usługi Teams przy użyciu zestawu SDK wywołującego usługi Azure Communication Services dla systemu Windows.
Przykładowy kod
Znajdź sfinalizowany kod dla tego przewodnika Szybki start w usłudze GitHub dla platform UWP i WinUI 3.
Wymagania wstępne
- Działające usługi komunikacyjne wywołujące aplikację systemu Windows.
- Wdrożenie usługi Teams.
- Minimalna wersja obsługiwana dla identyfikatora spotkania usługi Teams i interfejsu API dołączania kodu dostępu: 1.7.0
- Token dostępu.
Dodawanie kontrolek interfejsu użytkownika usługi Teams i włączanie kontrolek interfejsu użytkownika usługi Teams
Zastąp kod w pliku MainPage.xaml poniższym fragmentem kodu. Pole tekstowe będzie używane do wprowadzania kontekstu spotkania usługi Teams, a przycisk zostanie użyty do dołączenia do określonego spotkania:
<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>
Włączanie kontrolek interfejsu użytkownika usługi Teams
Zastąp zawartość MainPage.xaml.cs
następującym fragmentem kodu:
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(selectedCamerea);
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
}
}
Pobierz link do spotkania usługi Teams
Link do spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph. Jest to szczegółowe informacje w dokumentacji programu Graph.
Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams. Ten link jest zwracany w ramach onlineMeeting
zasobu dostępnego w joinWebUrl
ramach właściwości . Wymagane informacje o spotkaniu można również uzyskać z adresu URL spotkania dołączenia w zaproszeniu spotkania w aplikacji Teams.
Uzyskiwanie identyfikatora spotkania i kodu dostępu aplikacji Teams
- Interfejs API programu Graph: użyj interfejsu API programu Graph, aby pobrać informacje o zasobie onlineMeeting i sprawdzić obiekt we właściwości
joinMeetingIdSettings
. - Teams: w aplikacji Teams przejdź do aplikacji Kalendarz i otwórz szczegóły spotkania. Spotkania online mają identyfikator spotkania i kod dostępu w definicji spotkania.
- Outlook: Identyfikator spotkania i kod dostępu można znaleźć w wydarzeniach kalendarza lub w zaproszeniach na spotkanie e-mail.
Uruchamianie aplikacji i dołączanie do spotkania usługi Teams
Aplikację można skompilować i uruchomić w programie Visual Studio, wybierając pozycję Debuguj>rozpocznij debugowanie lub za pomocą skrótu klawiaturowego (F5).
Wstaw kontekst usługi Teams do pola tekstowego i naciśnij pozycję Dołącz do spotkania usługi Teams, aby dołączyć do spotkania usługi Teams z poziomu aplikacji Communication Services.
W tym przewodniku Szybki start dowiesz się, jak dołączyć do spotkania usługi Teams przy użyciu zestawu SDK wywołującego usługi Azure Communication Services dla systemu Android.
Przykładowy kod
Znajdź sfinalizowany kod dla tego przewodnika Szybki start w witrynie GitHub.
Wymagania wstępne
- Działające usługi komunikacyjne wywołujące aplikację systemu Android.
- Wdrożenie usługi Teams.
- Minimalna wersja obsługiwana dla identyfikatora spotkania aplikacji Teams i interfejsu API dołączania kodu dostępu: 2.9.0
- Token dostępu.
Dodawanie kontrolek interfejsu użytkownika usługi Teams
Zastąp kod w activity_main.xml poniższym fragmentem kodu. Pole tekstowe będzie używane do wprowadzania kontekstu spotkania usługi Teams, a przycisk zostanie użyty do dołączenia do określonego spotkania:
<?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>
Włączanie kontrolek interfejsu użytkownika usługi Teams
Zastąp zawartość MainActivity.java
następującym fragmentem kodu:
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(""));
}
}
}
Pobierz link do spotkania usługi Teams
Link do spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph. Jest to szczegółowe informacje w dokumentacji programu Graph.
Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams. Ten link jest zwracany w ramach onlineMeeting
zasobu dostępnego w joinWebUrl
ramach właściwości . Wymagane informacje o spotkaniu można również uzyskać z adresu URL spotkania dołączenia w zaproszeniu spotkania w aplikacji Teams.
Uzyskiwanie identyfikatora spotkania i kodu dostępu aplikacji Teams
- Interfejs API programu Graph: użyj interfejsu API programu Graph, aby pobrać informacje o zasobie onlineMeeting i sprawdzić obiekt we właściwości joinMeetingIdSettings.
- Teams: w aplikacji Teams przejdź do aplikacji Kalendarz i otwórz szczegóły spotkania. Spotkania online mają identyfikator spotkania i kod dostępu w definicji spotkania.
- Outlook: Identyfikator spotkania i kod dostępu można znaleźć w wydarzeniach kalendarza lub w zaproszeniach na spotkanie e-mail.
Uruchamianie aplikacji i dołączanie do spotkania usługi Teams
Teraz można uruchomić aplikację przy użyciu przycisku "Uruchom aplikację" na pasku narzędzi (Shift+F10). Powinien zostać wyświetlony następujący ekran:
Wstaw kontekst usługi Teams do pola tekstowego i naciśnij Join Meeting , aby dołączyć do spotkania usługi Teams z poziomu aplikacji Communication Services.
W tym przewodniku Szybki start dowiesz się, jak dołączyć do spotkania usługi Teams przy użyciu zestawu SDK wywołującego usługi Azure Communication Services dla systemu iOS.
Wymagania wstępne
- Działające usługi komunikacyjne wywołujące aplikację systemu iOS.
- Wdrożenie usługi Teams.
- Minimalna wersja obsługiwana dla identyfikatora spotkania aplikacji Teams i interfejsu API dołączania kodu dostępu: 2.11.0
- Token dostępu.
W tym przewodniku Szybki start użyjemy wersji beta.12 zestawu AZURECommunicationCalling SDK, abyśmy musieli zaktualizować plik podfile i ponownie zainstalować zasobniki.
Zastąp plik podfile następującym kodem do pliku Podfile i zapisz (upewnij się, że element "target" jest zgodny z nazwą projektu):
platform :ios, '13.0'
use_frameworks!
target 'AzureCommunicationCallingSample' do
pod 'AzureCommunicationCalling', '1.0.0-beta.12'
end
Usuń folder Zasobniki, Podfile.lock i .xcworkspace.
plik.
Uruchom pod install
polecenie i otwórz plik za .xcworkspace
pomocą programu Xcode.
Dodawanie kontrolek interfejsu użytkownika usługi Teams i włączanie kontrolek interfejsu użytkownika usługi Teams
Zastąp kod w pliku ContentView.swift poniższym fragmentem kodu. Pole tekstowe będzie używane do wprowadzania kontekstu spotkania usługi Teams, a przycisk zostanie użyty do dołączenia do określonego spotkania:
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()
}
}
Pobierz link do spotkania usługi Teams
Link do spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph. Jest to szczegółowe informacje w dokumentacji programu Graph.
Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams. Ten link jest zwracany w ramach onlineMeeting
zasobu dostępnego w joinWebUrl
ramach właściwości . Wymagane informacje o spotkaniu można również uzyskać z adresu URL spotkania dołączenia w zaproszeniu spotkania w aplikacji Teams.
Uruchamianie aplikacji i dołączanie do spotkania usługi Teams
Aplikację można skompilować i uruchomić w symulatorze systemu iOS, wybierając pozycję Uruchom produkt>lub za pomocą skrótu klawiaturowego (⌘-R).
Wstaw kontekst usługi Teams do pola tekstowego i naciśnij pozycję Dołącz do spotkania usługi Teams, aby dołączyć do spotkania usługi Teams z poziomu aplikacji Communication Services.
Czyszczenie zasobów
Jeśli chcesz wyczyścić i usunąć subskrypcję usług Komunikacyjnych, możesz usunąć zasób lub grupę zasobów. Usunięcie grupy zasobów powoduje również usunięcie wszelkich innych skojarzonych z nią zasobów. Dowiedz się więcej o czyszczeniu zasobów.
Następne kroki
Aby uzyskać więcej informacji, zobacz następujące artykuły:
- Zapoznaj się z przykładem elementu hero wywołującego
- Wprowadzenie do biblioteki interfejsu użytkownika
- Dowiedz się więcej o możliwościach wywoływania zestawu SDK
- Dowiedz się więcej o tym, jak działa wywołanie