Dela via


Snabbstart: Ansluta din samtalsapp till en automatisk Teams-dirigering

I den här snabbstarten får du lära dig hur du startar ett samtal från Azure Communication Services-användare till Automatisk teams-dirigering. Du kommer att uppnå det med följande steg:

  1. Aktivera federation av Azure Communication Services-resurs med Teams-klientorganisation.
  2. Välj eller skapa automatisk teams-dirigering via Administrationscenter för Teams.
  3. Hämta e-postadressen för automatisk dirigering via Administrationscenter för Teams.
  4. Hämta objekt-ID för den automatiska dirigering via Graph API.
  5. Starta ett samtal med Azure Communication Services Calling SDK.

Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.

Aktivera samverkan i din Teams-klientorganisation

Microsoft Entra-användare med Teams-administratörsroll kan köra PowerShell-cmdlet med MicrosoftTeams-modulen för att aktivera Communication Services-resursen i klientorganisationen.

1. Förbered Microsoft Teams-modulen

Öppna först PowerShell och verifiera förekomsten av Teams-modulen med följande kommando:

Get-module *teams* 

Om du inte ser modulen installerar du den MicrosoftTeams först. Om du vill installera modulen måste du köra PowerShell som administratör. Kör följande kommando:

	Install-Module -Name MicrosoftTeams

Du får information om de moduler som kommer att installeras, vilket du kan bekräfta med ett Y eller A svar. Om modulen är installerad men inaktuell kan du köra följande kommando för att uppdatera modulen:

	Update-Module MicrosoftTeams

2. Ansluta till Microsoft Teams-modulen

När modulen är installerad och klar kan du ansluta till MicrosftTeams-modulen med följande kommando. Du uppmanas att logga in med ett interaktivt fönster. Det användarkonto som du ska använda måste ha behörighet som Teams-administratör. Annars kan du få ett access denied svar i nästa steg.

Connect-MicrosoftTeams

3. Aktivera klientkonfiguration

Samverkan med Communication Services-resurser styrs via klientkonfiguration och tilldelad princip. Teams klientorganisation har en enda klientkonfiguration och Teams-användare har tilldelat global princip eller anpassad princip. Mer information finns i Tilldela principer i Teams.

När inloggningen har slutförts kan du köra cmdleten Set-CsTeamsAcsFederationConfiguration för att aktivera Communication Services-resursen i klientorganisationen. Ersätt texten IMMUTABLE_RESOURCE_ID med ett oföränderligt resurs-ID i kommunikationsresursen. Mer information om hur du hämtar den här informationen finns här.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Aktivera klientprincip

Varje Teams-användare har tilldelats en External Access Policy som avgör om Communication Services-användare kan anropa den här Teams-användaren. Använd cmdleten Set-CsExternalAccessPolicy för att säkerställa att principen som tilldelats Teams-användaren har angetts EnableAcsFederationAccess till $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Skapa eller välj Automatisk teams-dirigering

Automatisk dirigering i Teams är ett system som tillhandahåller ett automatiserat samtalshanteringssystem för inkommande samtal. Det fungerar som en virtuell receptionist, vilket gör det möjligt för uppringare att automatiskt dirigeras till lämplig person eller avdelning utan behov av en mänsklig operatör. Du kan välja befintlig eller skapa ny automatisk dirigering via Administrationscenter för Teams.

Läs mer om hur du skapar automatisk dirigering med Hjälp av Administrationscenter för Teams här.

Hitta objekt-ID för automatisk dirigering

När automatisk dirigering har skapats måste vi hitta korrelerat objekt-ID för att kunna använda det senare för anrop. Objekt-ID är anslutet till resurskonto som har kopplats till automatisk dirigering – öppna fliken Resurskonton i Teams-administratör och hitta e-post för kontot. Skärmbild av resurskonton i Teams administratörsportal. All nödvändig information för resurskontot finns i Microsoft Graph Explorer med det här e-postmeddelandet i sökningen.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

I resultat kan vi hitta fältet "ID"

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

Förutsättningar

Konfigurera

Skapa ett nytt Node.js-program

Öppna terminalen eller kommandofönstret skapa en ny katalog för din app och navigera till katalogen.

mkdir calling-quickstart && cd calling-quickstart

Installera -paketet

npm install Använd kommandot för att installera Azure Communication Services Calling SDK för JavaScript.

Viktigt!

Den här snabbstarten använder Azure Communication Services Calling SDK-versionen next.

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

Konfigurera appramverket

Den här snabbstarten använder webpack för att paketera programtillgångarna. Kör följande kommando för att installera , webpack-cli och webpack-dev-server npm-paketen webpackoch lista dem som utvecklingsberoenden i :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

Skapa en index.html fil i rotkatalogen för projektet. Vi använder den här filen för att konfigurera en grundläggande layout som gör att användaren kan ringa ett 1:1-videosamtal.

Här är koden:

<!-- index.html -->
<!DOCTYPE html>
<html>
    <head>
        <title>Azure Communication Services - Calling Web SDK</title>
    </head>
    <body>
        <h4>Azure Communication Services - Calling Web SDK</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">Initialize Call Agent</button>
        <br>
        <br>
        <input id="application-object-id"
            type="text"
            placeholder="Enter application objectId identity in format: 'APP_GUID'"
            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>

Azure Communication Services Anropar web-SDK-objektmodell

Följande klasser och gränssnitt hanterar några av huvudfunktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient Huvudinmatningspunkten till anropande SDK.
CallAgent Används för att starta och hantera anrop.
DeviceManager Används för att hantera medieenheter.
Call Används för att representera ett samtal.
LocalVideoStream Används för att skapa en lokal videoström för en kameraenhet i det lokala systemet.
RemoteParticipant Används för att representera en fjärrdeltagare i samtalet.
RemoteVideoStream Används för att representera en fjärrvideoström från en fjärrdeltagare.

Skapa en fil i rotkatalogen för projektet som anropas client.js för att innehålla programlogik för den här snabbstarten. Lägg till följande kod i client.js:

// 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 callAgent;
let deviceManager;
let call;
let incomingCall;
let localVideoStream;
let localVideoStreamRenderer;
// UI widgets
let userAccessToken = document.getElementById('user-access-token');
let applicationObjectId = document.getElementById('application-object-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 CallAgent instance with a AzureCommunicationTokenCredential via created CallClient. CallAgent 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());
        callAgent = await callClient.createCallAgent(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.
        callAgent.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 an Teams Auto attendant
 * 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 = callAgent.startCall([{ teamsAppId: applicationObjectId.value.trim(), cloud:"public" }], { 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 `CallAgent.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();
});

Lägg till den lokala serverkoden för webpack

Skapa en fil i rotkatalogen i projektet med namnet webpack.config.js för att innehålla den lokala serverlogik som finns i den här snabbstarten. Lägg till följande kod i webpack.config.js:

const path = require('path');
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
    mode: 'development',
    entry: './client.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
    },
    devServer: {
        static: {
            directory: path.join(__dirname, './')
        },
    },
    plugins: [
        new CopyPlugin({
            patterns: [
                './index.html'
            ]
        }),
    ]
};

Kör koden

Använd för webpack-dev-server att skapa och köra din app. Kör följande kommando för att paketa programvärden i en lokal webbserver:

npx webpack serve --config webpack.config.js

Manuella steg för att konfigurera anropet:

  1. Öppna webbläsaren och navigera till http://localhost:8080/.
  2. Ange en giltig användaråtkomsttoken. Se dokumentationen för användaråtkomsttoken om du inte redan har åtkomsttoken att använda.
  3. Klicka på knapparna "Initiera samtalsagent".
  4. Ange objekt-ID för automatisk dirigering och välj knappen "Starta samtal". Programmet startar det utgående anropet till den automatiska dirigering med angivet objekt-ID.
  5. Samtalet är anslutet till den automatiska dirigering.
  6. Communication Services-användaren dirigeras via automatisk dirigering baserat på dess konfiguration.

Viktigt!

Den här funktionen i Azure Communication Services är för närvarande i förhandsversion.

Förhandsversions-API:er och SDK:er tillhandahålls utan ett serviceavtal. Vi rekommenderar att du inte använder dem för produktionsarbetsbelastningar. Vissa funktioner kanske inte stöds, eller så kan de ha begränsade funktioner.

Mer information finns i Kompletterande användningsvillkor för Förhandsversioner av Microsoft Azure.

I den här snabbstarten får du lära dig hur du startar ett samtal från Azure Communication Services-användare till Automatisk teams-dirigering. Du kommer att uppnå det med följande steg:

  1. Aktivera federation av Azure Communication Services-resurs med Teams-klientorganisation.
  2. Välj eller skapa automatisk teams-dirigering via Administrationscenter för Teams.
  3. Hämta e-postadressen för automatisk dirigering via Administrationscenter för Teams.
  4. Hämta objekt-ID för den automatiska dirigering via Graph API.
  5. Starta ett samtal med Azure Communication Services Calling SDK.

Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.

Aktivera samverkan i din Teams-klientorganisation

Microsoft Entra-användare med Teams-administratörsroll kan köra PowerShell-cmdlet med MicrosoftTeams-modulen för att aktivera Communication Services-resursen i klientorganisationen.

1. Förbered Microsoft Teams-modulen

Öppna först PowerShell och verifiera förekomsten av Teams-modulen med följande kommando:

Get-module *teams* 

Om du inte ser modulen installerar du den MicrosoftTeams först. Om du vill installera modulen måste du köra PowerShell som administratör. Kör följande kommando:

	Install-Module -Name MicrosoftTeams

Du får information om de moduler som kommer att installeras, vilket du kan bekräfta med ett Y eller A svar. Om modulen är installerad men inaktuell kan du köra följande kommando för att uppdatera modulen:

	Update-Module MicrosoftTeams

2. Ansluta till Microsoft Teams-modulen

När modulen är installerad och klar kan du ansluta till MicrosftTeams-modulen med följande kommando. Du uppmanas att logga in med ett interaktivt fönster. Det användarkonto som du ska använda måste ha behörighet som Teams-administratör. Annars kan du få ett access denied svar i nästa steg.

Connect-MicrosoftTeams

3. Aktivera klientkonfiguration

Samverkan med Communication Services-resurser styrs via klientkonfiguration och tilldelad princip. Teams klientorganisation har en enda klientkonfiguration och Teams-användare har tilldelat global princip eller anpassad princip. Mer information finns i Tilldela principer i Teams.

När inloggningen har slutförts kan du köra cmdleten Set-CsTeamsAcsFederationConfiguration för att aktivera Communication Services-resursen i klientorganisationen. Ersätt texten IMMUTABLE_RESOURCE_ID med ett oföränderligt resurs-ID i kommunikationsresursen. Mer information om hur du hämtar den här informationen finns här.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Aktivera klientprincip

Varje Teams-användare har tilldelats en External Access Policy som avgör om Communication Services-användare kan anropa den här Teams-användaren. Använd cmdleten Set-CsExternalAccessPolicy för att säkerställa att principen som tilldelats Teams-användaren har angetts EnableAcsFederationAccess till $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Skapa eller välj Automatisk teams-dirigering

Automatisk dirigering i Teams är ett system som tillhandahåller ett automatiserat samtalshanteringssystem för inkommande samtal. Det fungerar som en virtuell receptionist, vilket gör det möjligt för uppringare att automatiskt dirigeras till lämplig person eller avdelning utan behov av en mänsklig operatör. Du kan välja befintlig eller skapa ny automatisk dirigering via Administrationscenter för Teams.

Läs mer om hur du skapar automatisk dirigering med Hjälp av Administrationscenter för Teams här.

Hitta objekt-ID för automatisk dirigering

När automatisk dirigering har skapats måste vi hitta korrelerat objekt-ID för att kunna använda det senare för anrop. Objekt-ID är anslutet till resurskonto som har kopplats till automatisk dirigering – öppna fliken Resurskonton i Teams-administratör och hitta e-post för kontot. Skärmbild av resurskonton i Teams administratörsportal. All nödvändig information för resurskontot finns i Microsoft Graph Explorer med det här e-postmeddelandet i sökningen.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

I resultat kan vi hitta fältet "ID"

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

För att kunna använda den anropande appen måste vi lägga till ett prefix i det här ID:t. För närvarande stöds följande:

  • Automatisk dirigering för offentliga moln: 28:orgid:<id>
  • Automatisk dirigering för myndighetsmoln: 28:gcch:<id>

Förutsättningar

Konfigurera

Skapa en Android-app med en tom aktivitet

Från Android Studio väljer du Starta ett nytt Android Studio-projekt.

Skärmbild som visar knappen Starta ett nytt Android Studio-projekt valt i Android Studio.

Välj projektmallen "Tom visningsaktivitet" under "Telefon och surfplatta".

Skärmbild som visar alternativet

Välj Minsta SDK för "API 26: Android 8.0 (Oreo)" eller senare.

Skärmbild som visar alternativet

Installera -paketet

Leta upp projektet settings.gradle.kts och se till att se mavenCentral() i listan över lagringsplatser under pluginManagement och dependencyResolutionManagement

pluginManagement {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
    ...
        mavenCentral()
    }
}

I modulnivån build.gradle lägger du sedan till följande rader i avsnitten beroenden och Android

android {
    ...
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    ...
    implementation ("com.azure.android:azure-communication-calling:2.6.0")
    ...
}

Lägga till behörigheter i programmanifestet

För att kunna begära behörigheter som krävs för att göra ett anrop måste de deklareras i programmanifestet (app/src/main/AndroidManifest.xml). Ersätt innehållet i filen med följande kod:

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.contoso.acsquickstart">

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

Konfigurera layouten för appen

Två indata behövs: en textinmatning för samtals-ID:t och en knapp för att ringa samtalet. Dessa indata kan läggas till via designern eller genom att redigera xml-layouten. Skapa en knapp med ett ID call_button för och en textinmatning på callee_id. Gå till (app/src/main/res/layout/activity_main.xml) och ersätt innehållet i filen med följande kod:

<?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="${launchApp}">

    <EditText
        android:id="@+id/callee_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Callee Id"
        android:inputType="textPersonName"
        android:layout_marginTop="100dp"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="46dp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <Button
            android:id="@+id/call_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Call" />

        <Button
            android:id="@+id/hangup_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hangup" />

    </LinearLayout>

    <TextView
        android:id="@+id/status_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Skapa huvudaktivitetens byggnadsställningar och bindningar

När layouten har skapats kan bindningarna läggas till samt den grundläggande scaffoldingen för aktiviteten. Aktiviteten hanterar begäran om körningsbehörigheter, skapar samtalsagenten och anropar när knappen trycks ned. Metoden onCreate åsidosättas för att anropa getAllPermissions och createAgent lägga till bindningar för anropsknappen. Den här händelsen inträffar bara en gång när aktiviteten skapas. Mer information onCreatefinns i guiden Förstå aktivitetslivscykeln.

Gå till MainActivity.java och ersätt innehållet med följande kod:

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.media.AudioManager;
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.common.CommunicationIdentifier;
import com.azure.android.communication.common.CommunicationUserIdentifier;
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.common.CommunicationTokenCredential;
import com.azure.android.communication.calling.StartCallOptions;

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

    private CallAgent agent;
    private Call call;
    private Button callButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        callButton = findViewById(R.id.call_button);

        getAllPermissions();
        createAgent();
        callButton.setOnClickListener(l -> startCall());

        Button hangupButton = findViewById(R.id.hangup_button);
        hangupButton.setOnClickListener(l -> endCall());

        statusBar = findViewById(R.id.status_bar);
        
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
    }

    /**
     * Start a call
     */
    private void startCall() {
        if (UserToken.startsWith("<")) {
            Toast.makeText(this, "Please enter token in source code", Toast.LENGTH_SHORT).show();
            return;
        }

        EditText calleeIdView = findViewById(R.id.callee_id);
        String calleeId = calleeIdView.getText().toString();
        if (calleeId.isEmpty()) {
            Toast.makeText(this, "Please enter callee", Toast.LENGTH_SHORT).show();
            return;
        }
        ArrayList<CommunicationIdentifier> participants = new ArrayList<>();
        participants.add(new MicrosoftTeamsAppIdentifier(calleeId));
        StartCallOptions options = new StartCallOptions();
        call = agent.startCall(
                getApplicationContext(),
                participants,
                options);
        call.addOnStateChangedListener(p -> setStatus(call.getState().toString()));
    }

    /**
     * Ends the call previously started
     */
    private void endCall() {
        try {
            call.hangUp(new HangUpOptions()).get();
        } catch (ExecutionException | InterruptedException e) {
            Toast.makeText(this, "Unable to hang up call", 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();
        }
    }

    /**
     * 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 message in the status bar
     */
    private void setStatus(String status) {
        runOnUiThread(() -> statusBar.setText(status));
    }
}

Begär behörigheter vid körning

För Android 6.0 och senare (API-nivå 23) och targetSdkVersion 23 eller senare beviljas behörigheter vid körning i stället för när appen installeras. För att stödja det getAllPermissions kan implementeras för att anropa ActivityCompat.checkSelfPermission och ActivityCompat.requestPermissions för varje nödvändig behörighet.

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

Kommentar

När du utformar din app bör du tänka på när dessa behörigheter ska begäras. Behörigheter bör begäras när de behövs, inte i förväg. Mer information finns i Android-behörighetsguiden.

Objektmodell

Följande klasser och gränssnitt hanterar några av de viktigaste funktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient CallClient är den viktigaste startpunkten för anropande SDK.
CallAgent CallAgent Används för att starta och hantera anrop.
CommunicationTokenCredential CommunicationTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent.
CommunicationIdentifier CommunicationIdentifier Används som en annan typ av deltagare som kan ingå i ett anrop.

Skapa en agent från användarens åtkomsttoken

Med en användartoken kan en autentiserad samtalsagent instansieras. Vanligtvis genereras denna token från en tjänst med autentisering som är specifik för programmet. Mer information om token för användaråtkomst finns i guiden Användaråtkomsttoken .

För snabbstarten ersätter du <User_Access_Token> med en användaråtkomsttoken som genererats för din Azure Communication Service-resurs.


/**
 * Create the call agent for placing calls
 */
private void createAgent() {
    String userToken = "<User_Access_Token>";

    try {
            CommunicationTokenCredential credential = new CommunicationTokenCredential(userToken);
            callAgent = new CallClient().createCallAgent(getApplicationContext(), credential).get();
    } catch (Exception ex) {
        Toast.makeText(getApplicationContext(), "Failed to create call agent.", Toast.LENGTH_SHORT).show();
    }
}

Kör koden

Appen kan nu startas med knappen "Kör app" i verktygsfältet.

Manuella steg för att konfigurera anropet:

  1. Starta appen med Android Studio.
  2. Ange objekt-ID för automatisk dirigering (med prefix) och välj knappen "Starta anrop". Programmet startar det utgående anropet till den automatiska dirigering med angivet objekt-ID.
  3. Samtalet är anslutet till den automatiska dirigering.
  4. Communication Services-användaren dirigeras via automatisk dirigering baserat på dess konfiguration.

Viktigt!

Den här funktionen i Azure Communication Services är för närvarande i förhandsversion.

Förhandsversions-API:er och SDK:er tillhandahålls utan ett serviceavtal. Vi rekommenderar att du inte använder dem för produktionsarbetsbelastningar. Vissa funktioner kanske inte stöds, eller så kan de ha begränsade funktioner.

Mer information finns i Kompletterande användningsvillkor för Förhandsversioner av Microsoft Azure.

I den här snabbstarten får du lära dig hur du startar ett samtal från Azure Communication Services-användare till Automatisk teams-dirigering. Du kommer att uppnå det med följande steg:

  1. Aktivera federation av Azure Communication Services-resurs med Teams-klientorganisation.
  2. Välj eller skapa automatisk teams-dirigering via Administrationscenter för Teams.
  3. Hämta e-postadressen för automatisk dirigering via Administrationscenter för Teams.
  4. Hämta objekt-ID för den automatiska dirigering via Graph API.
  5. Starta ett samtal med Azure Communication Services Calling SDK.

Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.

Aktivera samverkan i din Teams-klientorganisation

Microsoft Entra-användare med Teams-administratörsroll kan köra PowerShell-cmdlet med MicrosoftTeams-modulen för att aktivera Communication Services-resursen i klientorganisationen.

1. Förbered Microsoft Teams-modulen

Öppna först PowerShell och verifiera förekomsten av Teams-modulen med följande kommando:

Get-module *teams* 

Om du inte ser modulen installerar du den MicrosoftTeams först. Om du vill installera modulen måste du köra PowerShell som administratör. Kör följande kommando:

	Install-Module -Name MicrosoftTeams

Du får information om de moduler som kommer att installeras, vilket du kan bekräfta med ett Y eller A svar. Om modulen är installerad men inaktuell kan du köra följande kommando för att uppdatera modulen:

	Update-Module MicrosoftTeams

2. Ansluta till Microsoft Teams-modulen

När modulen är installerad och klar kan du ansluta till MicrosftTeams-modulen med följande kommando. Du uppmanas att logga in med ett interaktivt fönster. Det användarkonto som du ska använda måste ha behörighet som Teams-administratör. Annars kan du få ett access denied svar i nästa steg.

Connect-MicrosoftTeams

3. Aktivera klientkonfiguration

Samverkan med Communication Services-resurser styrs via klientkonfiguration och tilldelad princip. Teams klientorganisation har en enda klientkonfiguration och Teams-användare har tilldelat global princip eller anpassad princip. Mer information finns i Tilldela principer i Teams.

När inloggningen har slutförts kan du köra cmdleten Set-CsTeamsAcsFederationConfiguration för att aktivera Communication Services-resursen i klientorganisationen. Ersätt texten IMMUTABLE_RESOURCE_ID med ett oföränderligt resurs-ID i kommunikationsresursen. Mer information om hur du hämtar den här informationen finns här.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Aktivera klientprincip

Varje Teams-användare har tilldelats en External Access Policy som avgör om Communication Services-användare kan anropa den här Teams-användaren. Använd cmdleten Set-CsExternalAccessPolicy för att säkerställa att principen som tilldelats Teams-användaren har angetts EnableAcsFederationAccess till $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Skapa eller välj Automatisk teams-dirigering

Automatisk dirigering i Teams är ett system som tillhandahåller ett automatiserat samtalshanteringssystem för inkommande samtal. Det fungerar som en virtuell receptionist, vilket gör det möjligt för uppringare att automatiskt dirigeras till lämplig person eller avdelning utan behov av en mänsklig operatör. Du kan välja befintlig eller skapa ny automatisk dirigering via Administrationscenter för Teams.

Läs mer om hur du skapar automatisk dirigering med Hjälp av Administrationscenter för Teams här.

Hitta objekt-ID för automatisk dirigering

När automatisk dirigering har skapats måste vi hitta korrelerat objekt-ID för att kunna använda det senare för anrop. Objekt-ID är anslutet till resurskonto som har kopplats till automatisk dirigering – öppna fliken Resurskonton i Teams-administratör och hitta e-post för kontot. Skärmbild av resurskonton i Teams administratörsportal. All nödvändig information för resurskontot finns i Microsoft Graph Explorer med det här e-postmeddelandet i sökningen.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

I resultat kan vi hitta fältet "ID"

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

För att kunna använda den anropande appen måste vi lägga till ett prefix i det här ID:t. För närvarande stöds följande:

  • Automatisk dirigering för offentliga moln: 28:orgid:<id>
  • Automatisk dirigering för myndighetsmoln: 28:gcch:<id>

Förutsättningar

  • Skaffa ett Azure-konto med en aktiv prenumeration. Skapa ett konto utan kostnad.

  • En Mac som kör Xcode, tillsammans med ett giltigt utvecklarcertifikat installerat i nyckelringen.

  • En distribuerad Communication Services-resurs. Skapa en Communication Services-resurs. Du måste registrera anslutningssträng för den här snabbstarten.

  • En användaråtkomsttoken för azure-kommunikationstjänsten. Du kan också använda Azure CLI och köra kommandot med din anslutningssträng för att skapa en användare och en åtkomsttoken.

    az communication identity token issue --scope voip --connection-string "yourConnectionString"
    

    Mer information finns i Använda Azure CLI för att skapa och hantera åtkomsttoken.

  • Lägsta stöd för Teams-samtalsprogram: 2.14.0-beta.1

Konfigurera

Skapa Xcode-projektet

I Xcode skapar du ett nytt iOS-projekt och väljer appmallen. I den här självstudien används SwiftUI-ramverket, så du bör ange Språket till Swift och användargränssnittet till SwiftUI. Du kommer inte att skapa tester under den här snabbstarten. Avmarkera Inkludera tester.

Skärmbild som visar fönstret Nytt projekt i Xcode.

Installera paketet och beroenden med CocoaPods

  1. Om du vill skapa en Podfile för ditt program öppnar du terminalen och navigerar till projektmappen och kör:

    pod init

  2. Lägg till följande kod i Podfile och spara (se till att "målet" matchar namnet på projektet):

    platform :ios, '13.0'
    use_frameworks!
    
    target 'AzureCommunicationCallingSample' do
      pod 'AzureCommunicationCalling', '~> 2.14.0-beta.1'
    end
    
  3. Kör pod install.

  4. .xcworkspace Öppna med Xcode.

Begär åtkomst till mikrofonen

För att få åtkomst till enhetens mikrofon måste du uppdatera appens informationsegenskapslista med en NSMicrophoneUsageDescription. Du anger det associerade värdet till en string som ingick i den dialogruta som systemet använder för att begära åtkomst från användaren.

Högerklicka på posten i Info.plist projektträdet och välj Öppna som>källkod. Lägg till följande rader i avsnittet på den översta nivån <dict> och spara sedan filen.

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

Konfigurera appramverket

Öppna projektets ContentView.swift-fil och lägg till en import deklaration överst i filen för att importera AzureCommunicationCalling library. Dessutom behöver vi den AVFoundationhär koden för begäran om ljudbehörighet i koden.

import AzureCommunicationCalling
import AVFoundation

Ersätt implementeringen av ContentView struct med några enkla användargränssnittskontroller som gör att en användare kan initiera och avsluta ett anrop. Vi kopplar affärslogik till dessa kontroller i den här snabbstarten.

struct ContentView: View {
    @State var callee: String = ""
    @State var callClient: CallClient?
    @State var callAgent: CallAgent?
    @State var call: Call?

    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Who would you like to call?", text: $callee)
                    Button(action: startCall) {
                        Text("Start Call")
                    }.disabled(callAgent == nil)
                    Button(action: endCall) {
                        Text("End Call")
                    }.disabled(call == nil)
                }
            }
            .navigationBarTitle("Calling Quickstart")
        }.onAppear {
            // Initialize call agent
        }
    }

    func startCall() {
        // Ask permissions
        AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
            if granted {
                // Add start call logic
            }
        }
    }

    func endCall() {
        // Add end call logic
    }
}

Objektmodell

Följande klasser och gränssnitt hanterar några av de viktigaste funktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient CallClient är den viktigaste startpunkten för anropande SDK.
CallAgent CallAgent Används för att starta och hantera anrop.
CommunicationTokenCredential CommunicationTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent.
CommunicationUserIdentifier CommunicationUserIdentifier Används för att representera användarens identitet, vilket kan vara något av följande alternativ: CommunicationUserIdentifier,PhoneNumberIdentifier ellerCallingApplication.

Autentisera klienten

Initiera en CallAgent instans med en användaråtkomsttoken, vilket gör att vi kan ringa och ta emot samtal.

I följande kod måste du ersätta <USER ACCESS TOKEN> med en giltig användaråtkomsttoken för din resurs. Se dokumentationen för användaråtkomsttoken om du inte redan har en tillgänglig token.

Lägg till följande kod i återanropet onAppear i ContentView.swift:

var userCredential: CommunicationTokenCredential?
do {
    userCredential = try CommunicationTokenCredential(token: "<USER ACCESS TOKEN>")
} catch {
    print("ERROR: It was not possible to create user credential.")
    return
}

self.callClient = CallClient()

// Creates the call agent
self.callClient?.createCallAgent(userCredential: userCredential!) { (agent, error) in
    if error != nil {
        print("ERROR: It was not possible to create a call agent.")
        return
    }
    else {
        self.callAgent = agent
        print("Call agent successfully created.")
    }
}

Starta ett samtal

Metoden startCall anges som den åtgärd som utförs när knappen Starta samtal knackas. Uppdatera implementeringen för att starta ett anrop med ASACallAgent:

func startCall()
{
    // Ask permissions
    AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
        if granted {
            // start call logic
            let callees:[CommunicationIdentifier] = [MicrosoftTeamsAppIdentifier(self.callee)]
            self.callAgent?.startCall(participants: callees, options: StartCallOptions()) { (call, error) in
                if (error == nil) {
                    self.call = call
                } else {
                    print("Failed to get call object")
                }
            }
        }
    }
}

Du kan också använda egenskaperna i StartCallOptions för att ange de första alternativen för anropet (det vill säga att det tillåter att samtalet startas med mikrofonen avstängd).

Avsluta samtal

endCall Implementera metoden för att avsluta det aktuella anropet när knappen Avsluta samtal knackas.

func endCall()
{    
    self.call!.hangUp(options: HangUpOptions()) { (error) in
        if (error != nil) {
            print("ERROR: It was not possible to hangup the call.")
        }
    }
}

Kör koden

Du kan skapa och köra appen i iOS-simulatorn genom att välja Produktkörning> eller med hjälp av kortkommandot (⌘-R).

Kommentar

Första gången du ringer ett anrop uppmanar systemet dig att få åtkomst till mikrofonen. I ett produktionsprogram bör du använda API:et AVAudioSession för att kontrollera behörighetsstatusen och korrekt uppdatera programmets beteende när behörighet inte beviljas.

Manuella steg för att konfigurera anropet:

  1. Starta appen med Xcode
  2. Ange objekt-ID för automatisk dirigering (med prefix) och välj knappen "Starta anrop". Programmet startar det utgående anropet till den automatiska dirigering med angivet objekt-ID.
  3. Samtalet är anslutet till den automatiska dirigering.
  4. Communication Services-användaren dirigeras via automatisk dirigering baserat på dess konfiguration.

Viktigt!

Den här funktionen i Azure Communication Services är för närvarande i förhandsversion.

Förhandsversions-API:er och SDK:er tillhandahålls utan ett serviceavtal. Vi rekommenderar att du inte använder dem för produktionsarbetsbelastningar. Vissa funktioner kanske inte stöds, eller så kan de ha begränsade funktioner.

Mer information finns i Kompletterande användningsvillkor för Förhandsversioner av Microsoft Azure.

I den här snabbstarten får du lära dig hur du startar ett samtal från Azure Communication Services-användare till Automatisk teams-dirigering. Du kommer att uppnå det med följande steg:

  1. Aktivera federation av Azure Communication Services-resurs med Teams-klientorganisation.
  2. Välj eller skapa automatisk teams-dirigering via Administrationscenter för Teams.
  3. Hämta e-postadressen för automatisk dirigering via Administrationscenter för Teams.
  4. Hämta objekt-ID för den automatiska dirigering via Graph API.
  5. Starta ett samtal med Azure Communication Services Calling SDK.

Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.

Aktivera samverkan i din Teams-klientorganisation

Microsoft Entra-användare med Teams-administratörsroll kan köra PowerShell-cmdlet med MicrosoftTeams-modulen för att aktivera Communication Services-resursen i klientorganisationen.

1. Förbered Microsoft Teams-modulen

Öppna först PowerShell och verifiera förekomsten av Teams-modulen med följande kommando:

Get-module *teams* 

Om du inte ser modulen installerar du den MicrosoftTeams först. Om du vill installera modulen måste du köra PowerShell som administratör. Kör följande kommando:

	Install-Module -Name MicrosoftTeams

Du får information om de moduler som kommer att installeras, vilket du kan bekräfta med ett Y eller A svar. Om modulen är installerad men inaktuell kan du köra följande kommando för att uppdatera modulen:

	Update-Module MicrosoftTeams

2. Ansluta till Microsoft Teams-modulen

När modulen är installerad och klar kan du ansluta till MicrosftTeams-modulen med följande kommando. Du uppmanas att logga in med ett interaktivt fönster. Det användarkonto som du ska använda måste ha behörighet som Teams-administratör. Annars kan du få ett access denied svar i nästa steg.

Connect-MicrosoftTeams

3. Aktivera klientkonfiguration

Samverkan med Communication Services-resurser styrs via klientkonfiguration och tilldelad princip. Teams klientorganisation har en enda klientkonfiguration och Teams-användare har tilldelat global princip eller anpassad princip. Mer information finns i Tilldela principer i Teams.

När inloggningen har slutförts kan du köra cmdleten Set-CsTeamsAcsFederationConfiguration för att aktivera Communication Services-resursen i klientorganisationen. Ersätt texten IMMUTABLE_RESOURCE_ID med ett oföränderligt resurs-ID i kommunikationsresursen. Mer information om hur du hämtar den här informationen finns här.

$allowlist = @('IMMUTABLE_RESOURCE_ID')
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $True -AllowedAcsResources $allowlist

4. Aktivera klientprincip

Varje Teams-användare har tilldelats en External Access Policy som avgör om Communication Services-användare kan anropa den här Teams-användaren. Använd cmdleten Set-CsExternalAccessPolicy för att säkerställa att principen som tilldelats Teams-användaren har angetts EnableAcsFederationAccess till $true

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

Skapa eller välj Automatisk teams-dirigering

Automatisk dirigering i Teams är ett system som tillhandahåller ett automatiserat samtalshanteringssystem för inkommande samtal. Det fungerar som en virtuell receptionist, vilket gör det möjligt för uppringare att automatiskt dirigeras till lämplig person eller avdelning utan behov av en mänsklig operatör. Du kan välja befintlig eller skapa ny automatisk dirigering via Administrationscenter för Teams.

Läs mer om hur du skapar automatisk dirigering med Hjälp av Administrationscenter för Teams här.

Hitta objekt-ID för automatisk dirigering

När automatisk dirigering har skapats måste vi hitta korrelerat objekt-ID för att kunna använda det senare för anrop. Objekt-ID är anslutet till resurskonto som har kopplats till automatisk dirigering – öppna fliken Resurskonton i Teams-administratör och hitta e-post för kontot. Skärmbild av resurskonton i Teams administratörsportal. All nödvändig information för resurskontot finns i Microsoft Graph Explorer med det här e-postmeddelandet i sökningen.

https://graph.microsoft.com/v1.0/users/lab-test2-cq-@contoso.com

I resultat kan vi hitta fältet "ID"

    "userPrincipalName": "lab-test2-cq@contoso.com",
    "id": "31a011c2-2672-4dd0-b6f9-9334ef4999db"

För att kunna använda den anropande appen måste vi lägga till ett prefix i det här ID:t. För närvarande stöds följande:

  • Automatisk dirigering för offentliga moln: 28:orgid:<id>
  • Automatisk dirigering för myndighetsmoln: 28:gcch:<id>

Förutsättningar

För att slutföra den här självstudien, finns följande förhandskrav:

Konfigurera

Skapa projektet

I Visual Studio skapar du ett nytt projekt med mallen Tom app (Universell Windows) för att konfigurera en enkelsidig Universell Windows-plattform-app (UWP).

Skärmbild som visar fönstret Nytt UWP-projekt i Visual Studio.

Installera -paketet

Välj projektet och gå till för att Manage Nuget Packages installera Azure.Communication.Calling.WindowsClient 1.4.0 eller superior. Kontrollera att Include Prerelease är markerat om du vill se versionerna för offentlig förhandsversion.

Begär åtkomst

Gå till Package.appxmanifest och välj Capabilities. Kontrollera Internet (Client) och Internet (Client & Server) för att få inkommande och utgående åtkomst till Internet. Kontrollera Microphone om du vill komma åt mikrofonens ljudflöde och Webcam få åtkomst till kamerans videoflöde.

Skärmbild som visar begäran om åtkomst till Internet och mikrofon i Visual Studio.

Konfigurera appramverket

Vi måste konfigurera en grundläggande layout för att koppla vår logik. För att kunna ringa ett utgående samtal behöver vi ett TextBox för att ange användar-ID:t för den anropade. Vi behöver också en Start/Join call knapp och en Hang up knapp. En Mute och en BackgroundBlur kryssrutor ingår också i det här exemplet för att demonstrera funktionerna i att växla ljudtillstånd och videoeffekter.

MainPage.xaml Öppna projektet och lägg till noden i Grid :Page

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

        <!-- Don't forget to replace ‘CallingQuickstart’ with your project’s name -->


    <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 Öppna och ersätt innehållet med följande implementering:

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 CallAgent callAgent;
        private CommunicationCall call;

        private LocalOutgoingAudioStream micStream;

        #region Page initialization
        public MainPage()
        {
            this.InitializeComponent();
            // Additional UI customization code goes here
        }

        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)
        {
            // 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, IncomingCallReceivedEventArgs args)
        {
            // Handle incoming call event
        }

        private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
        {
            // Handle connected and disconnected state change of a call
        }
        #endregion

        #region Helper methods

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            //Initialize the call agent and search for devices
        }


        private async Task<CommunicationCall> StartCallAsync(string acsCallee)
        {
            // Start a call to an Azure Communication Services user using the CallAgent and the callee id
        }

        #endregion
    }
}

Objektmodell

I nästa tabell visas klasserna och gränssnitten som hanterar några av de viktigaste funktionerna i Azure Communication Services Calling SDK:

Name beskrivning
CallClient CallClient är den viktigaste startpunkten för anropande SDK.
CallAgent CallAgent Används för att starta och hantera anrop.
CommunicationCall CommunicationCall Används för att hantera ett pågående anrop.
CallTokenCredential CallTokenCredential Används som tokenautentiseringsuppgifter för att instansiera CallAgent.
CallIdentifier CallIdentifier Används för att representera användarens identitet, vilket kan vara något av följande alternativ: UserCallIdentifier, PhoneNumberCallIdentifier osv.

Autentisera klienten

Initiera en CallAgent instans med en användaråtkomsttoken som gör att vi kan göra och ta emot anrop och eventuellt hämta en DeviceManager-instans för att fråga efter klientenhetskonfigurationer.

I koden ersätter du <AUTHENTICATION_TOKEN> med en användaråtkomsttoken. Se dokumentationen för användaråtkomsttoken om du inte redan har en tillgänglig token.

Lägg till InitCallAgentAndDeviceManagerAsync funktion, som startar SDK:t. Den här hjälpen kan anpassas för att uppfylla kraven för ditt program.

        private async Task InitCallAgentAndDeviceManagerAsync()
        {
            this.callClient = new CallClient(new CallClientOptions() {
                Diagnostics = new CallDiagnosticsOptions() { 
                    
                    // make sure to put your project AppName
                    AppName = "CallingQuickstart",

                    AppVersion="1.0",

                    Tags = new[] { "Calling", "ACS", "Windows" }
                    }

                });

            // Set up local audio stream using the first mic enumerated
            var deviceManager = await this.callClient.GetDeviceManagerAsync();
            var mic = deviceManager?.Microphones?.FirstOrDefault();

            micStream = new LocalOutgoingAudioStream();

            var tokenCredential = new CallTokenCredential(authToken, callTokenRefreshOptions);

            var callAgentOptions = new CallAgentOptions()
            {
                DisplayName = $"{Environment.MachineName}/{Environment.UserName}",
            };

            this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);

            this.callAgent.IncomingCallReceived += OnIncomingCallAsync;
        }

Starta samtalet

När ett StartCallOptions objekt har hämtats CallAgent kan användas för att initiera Azure Communication Services-anropet:

        private async Task<CommunicationCall> StartCallAsync(string acsCallee)
        {
            var options = new StartCallOptions();
            var call = await this.callAgent.StartCallAsync( new [] { new MicrosoftTeamsAppCallIdentifier(acsCallee) }, options);
            return call;
        }

Avsluta samtal

Avsluta det aktuella samtalet när Hang up knappen klickas. Lägg till implementeringen i HangupButton_Click för att avsluta ett anrop och stoppa förhandsgranskningen och videoströmmarna.

        private async void HangupButton_Click(object sender, RoutedEventArgs e)
        {
            var call = this.callAgent?.Calls?.FirstOrDefault();
            if (call != null)
            {
                await call.HangUpAsync(new HangUpOptions() { ForEveryone = false });
            }
        }

Växla ljudavstängning/ljudavstängning

Stäng av det utgående ljudet när Mute knappen klickas. Lägg till implementeringen i MuteLocal_Click för att stänga av anropet.

        private async void MuteLocal_Click(object sender, RoutedEventArgs e)
        {
            var muteCheckbox = sender as CheckBox;

            if (muteCheckbox != null)
            {
                var call = this.callAgent?.Calls?.FirstOrDefault();

                if (call != null)
                {
                    if ((bool)muteCheckbox.IsChecked)
                    {
                        await call.MuteOutgoingAudioAsync();
                    }
                    else
                    {
                        await call.UnmuteOutgoingAudioAsync();
                    }
                }

                // Update the UI to reflect the state
            }
        }

Acceptera ett inkommande samtal

IncomingCallReceived händelsemottagaren har konfigurerats i SDK bootstrap-hjälpen InitCallAgentAndDeviceManagerAsync.

    this.callAgent.IncomingCallReceived += OnIncomingCallAsync;

Programmet har möjlighet att konfigurera hur det inkommande samtalet ska godkännas, till exempel video- och ljudströmstyper.

        private async void OnIncomingCallAsync(object sender, IncomingCallReceivedEventArgs args)
        {
            var incomingCall = args.IncomingCall;

            var acceptCallOptions = new AcceptCallOptions() { };

            call = await incomingCall.AcceptAsync(acceptCallOptions);
            call.StateChanged += OnStateChangedAsync;
        }

Övervaka och svara på anropstillståndsändringshändelse

StateChanged händelsen på CommunicationCall objektet utlöses när en pågående anropstransaktioner från ett tillstånd till ett annat. Programmet erbjuds möjligheter att återspegla tillståndsändringarna i användargränssnittet eller infoga affärslogik.

        private async void OnStateChangedAsync(object sender, PropertyChangedEventArgs args)
        {
            var call = sender as CommunicationCall;

            if (call != null)
            {
                var state = call.State;

                // Update the UI

                switch (state)
                {
                    case CallState.Connected:
                        {
                            await call.StartAudioAsync(micStream);

                            break;
                        }
                    case CallState.Disconnected:
                        {
                            call.StateChanged -= OnStateChangedAsync;

                            call.Dispose();

                            break;
                        }
                    default: break;
                }
            }
        }

Få samtalsknappen att fungera

När inte Callee ID är null eller tomt kan du starta ett anrop.

Anropstillståndet måste ändras med hjälp av åtgärden OnStateChangedAsync .


    private async void CallButton_Click(object sender, RoutedEventArgs e)
    {
        var callString = CalleeTextBox.Text.Trim();

        if (!string.IsNullOrEmpty(callString))
        {
            call = await StartCallAsync(callString);

            call.StateChanged += OnStateChangedAsync;
        }
    
        
    }

Kör koden

Du kan skapa och köra koden i Visual Studio. För lösningsplattformar har vi stöd ARM64för , x64och x86.

Manuella steg för att konfigurera anropet:

  1. Starta appen med Visual Studio.
  2. Ange objekt-ID för automatisk dirigering (med prefix) och välj knappen "Starta anrop". Programmet startar det utgående anropet till den automatiska dirigering med angivet objekt-ID.
  3. Samtalet är anslutet till den automatiska dirigering.
  4. Communication Services-användaren dirigeras via automatisk dirigering baserat på dess konfiguration.

Rensa resurser

Om du vill rensa och ta bort en Communication Services-prenumeration kan du ta bort resursen eller resursgruppen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort. Läs mer om att rensa resurser.

Nästa steg

Mer information finns i följande artiklar: