Call Recording API Quickstart

Important

Functionality described in this document is currently in public preview. This preview version is provided without a service-level agreement, and it's not recommended for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.

This quickstart gets you started recording voice and video calls. This quickstart assumes you've already used the Calling client SDK to build the end-user calling experience. Using the Calling Server APIs and SDKs you can enable and manage recordings.

Note

Unmixed audio-only is still in a Private Preview and NOT enabled for Teams Interop meetings.

Sample Code

Find the finalized code for this quickstart on GitHub.

Prerequisites

Object model

The following classes handle some of the major features of the recording Server apps of C#.

Name Description
CallingServerClient This class is needed for the recording functionality. You create an instance of CallingServerClient using Azure Communication Services resource connection string and use it to start/stop and pause/resume a call recording.

Getting serverCallId as a requirement for call recording server APIs from JavaScript application

Note

This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this API please use 'beta' release of Azure Communication Services Calling Web SDK. A client sample with recording flows is available at GitHub.

Call recording is an extended feature of the core Call API. You first need to import calling Features from the Calling SDK:

import { Features} from "@azure/communication-calling";

Then you can get the recording feature API object from the call instance:

const callTransferApi = call.feature(Features.Recording);

Subscribe to recording changes:

const isRecordingActiveChangedHandler = () => {
  console.log(callRecordingApi.isRecordingActive);
};

callRecordingApi.on('isRecordingActiveChanged', isRecordingActiveChangedHandler);

Get server call ID which can be used to start/stop/pause/resume recording sessions:

Once the call is connected use the getServerCallId method to get the server call ID.

callAgent.on('callsUpdated', (e: { added: Call[]; removed: Call[] }): void => {
    e.added.forEach((addedCall) => {
        addedCall.on('stateChanged', (): void => {
            if (addedCall.state === 'Connected') {
                addedCall.info.getServerCallId().then(result => {
                    dispatch(setServerCallId(result));
                }).catch(err => {
                    console.log(err);
                });
            }
        });
    });
});

Create a calling server client

To create a calling server client, you'll use your Azure Communication Services connection string and pass it to calling server client object.

CallingServerClient callingServerClient = new CallingServerClient("<Resource_Connection_String>");

Start recording session using 'StartRecordingAsync' server API

Use the server call ID received during initiation of a call.

var startRecordingResponse = await callingServerClient.InitializeServerCall("<servercallid>").StartRecordingAsync("<callbackuri>").ConfigureAwait(false);

The StartRecordingAsync API response contains the recording ID of the recording session.

Specify a user on a channel 0 for unmixed audio-only

var channelAffinity = new []
{
    new ChannelAffinity
    {
        Channel = 0,
        Participant = user,
    },
};

var startRecordingResponse = await callingServerClient.InitializeServerCall("<servercallid>").StartRecordingAsync("<callbackuri>","<RecordingContent>","<RecordingChannel>","<RecordingFormat>", channelAffinity).ConfigureAwait(false);

Start recording session with options using 'StartRecordingAsync' server API

Use the server call ID received during initiation of a call.

  • RecordingContent is used to pass the recording content type. Ex: audio/audiovideo.
  • RecordingChannel is used to pass the recording channel type. Ex: mixed/unmixed.
  • RecordingFormat is used to pass the format of the recording. Ex: mp4/mp3/wav.
var startRecordingResponse = await callingServerClient.InitializeServerCall("<servercallid>").StartRecordingAsync("<callbackuri>","<RecordingContent>","<RecordingChannel>","<RecordingFormat>").ConfigureAwait(false);

The StartRecordingAsync API response contains the recording ID of the recording session.

Specify a user on a channel 0 for unmixed audio-only

var channelAffinity = new []
{
    new ChannelAffinity
    {
        Channel = 0,
        Participant = user,
    },
};

var startRecordingResponse = await callingServerClient.InitializeServerCall("<servercallid>").StartRecordingAsync("<callbackuri>", RecordingContent.Audio, RecordingChannel.Unmixed, RecordingFormat.Wav, channelAffinity).ConfigureAwait(false);

Stop recording session using 'StopRecordingAsync' server API

Use the recording ID received in response of StartRecordingAsync.

 var stopRecording = await callingServerClient.InitializeServerCall("<servercallid>").StopRecordingAsync("<recordingid>").ConfigureAwait(false);

Pause recording session using 'PauseRecordingAsync' server API

Use the recording ID received in response of StartRecordingAsync.

var pauseRecording = await callingServerClient.InitializeServerCall("<servercallid>").PauseRecordingAsync("<recordingid>");

Resume recording session using 'ResumeRecordingAsync' server API

Use the recording ID received in response of StartRecordingAsync.

var resumeRecording = await callingServerClient.InitializeServerCall("<servercallid>").ResumeRecordingAsync("<recordingid>");

Download recording File using 'DownloadStreamingAsync' server API

Use an Azure Event Grid web hook or other triggered action should be used to notify your services when the recorded media is ready for download.

Below is an example of the event schema.

{
    "id": string, // Unique guid for event
    "topic": string, // Azure Communication Services resource id
    "subject": string, // /recording/call/{call-id}
    "data": {
        "recordingStorageInfo": {
            "recordingChunks": [
                {
                    "documentId": string, // Document id for retrieving from AMS storage
                    "contentLocation": string, //Azure Communication Services URL where the content is located
                    "metadataLocation": string, // Azure Communication Services URL where the metadata for this chunk is located
                    "index": int, // Index providing ordering for this chunk in the entire recording
                    "endReason": string, // Reason for chunk ending: "SessionEnded", "ChunkMaximumSizeExceeded”, etc.
                }
            ]
        },
        "recordingStartTime": string, // ISO 8601 date time for the start of the recording
        "recordingDurationMs": int, // Duration of recording in milliseconds
        "sessionEndReason": string // Reason for call ending: "CallEnded", "InitiatorLeft”, etc.
    },
    "eventType": string, // "Microsoft.Communication.RecordingFileStatusUpdated"
    "dataVersion": string, // "1.0"
    "metadataVersion": string, // "1"
    "eventTime": string // ISO 8601 date time for when the event was created
}

Use DownloadStreamingAsync API for downloading the recorded media.

var recordingDownloadUri = new Uri(downloadLocation);
var response = callingServerClient.DownloadStreamingAsync(recordingDownloadUri);

The downloadLocation for the recording can be fetched from the contentLocation attribute of the recordingChunk. DownloadStreamingAsync method returns response of type Response<Stream>, which contains the downloaded content.

Sample Code

Find the finalized code for this quickstart on GitHub.

Prerequisites

Object model

The following classes handle some of the major features of the recording Server apps of Java.

Name Description
CallingServerClientBuilder This class is used to create instance of CallingServerClient.
CallingServerClient This class is needed for the calling functionality. You obtain an instance via CallingServerClientBuilder and use it to start/hangup a call, play/cancel audio and add/remove participants

Getting serverCallId as a requirement for call recording server APIs from JavaScript application

Note

This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this API please use 'beta' release of Azure Communication Services Calling Web SDK. A client sample with recording flows is available at GitHub.

Call recording is an extended feature of the core Call API. You first need to import calling Features from the Calling SDK:

import { Features} from "@azure/communication-calling";

Then you can get the recording feature API object from the call instance:

const callTransferApi = call.feature(Features.Recording);

Subscribe to recording changes:

const recordingStateChanged = () => {
    let recordings = callRecordingApi.recordings;

    let state = SDK.RecordingState.None;
    if (recordings.length > 0) {
        state = recordings.some(r => r.state == SDK.RecordingState.Started)
            ? SDK.RecordingState.Started
            : SDK.RecordingState.Paused;
    }
    
	console.log(`RecordingState: ${state}`);
}

const recordingsChangedHandler = (args: { added: SDK.RecordingInfo[], removed: SDK.RecordingInfo[]}) => {
    args.added?.forEach(a => {
        a.on('recordingStateChanged', recordingStateChanged);
    });

    args.removed?.forEach(r => {
        r.off('recordingStateChanged', recordingStateChanged);
    });

    recordingStateChanged();
};

callRecordingApi.on('recordingsUpdated', recordingsChangedHandler);

Get server call ID which can be used to start/stop/pause/resume recording sessions:

Once the call is connected use the getServerCallId method to get the server call ID.

callAgent.on('callsUpdated', (e: { added: Call[]; removed: Call[] }): void => {
    e.added.forEach((addedCall) => {
        addedCall.on('stateChanged', (): void => {
            if (addedCall.state === 'Connected') {
                addedCall.info.getServerCallId().then(result => {
                    dispatch(setServerCallId(result));
                }).catch(err => {
                    console.log(err);
                });
            }
        });
    });
});

Create a calling server client

To create a calling server client, you'll use your Communication Services connection string and pass it to calling server client object.

NettyAsyncHttpClientBuilder httpClientBuilder = new NettyAsyncHttpClientBuilder();
CallingServerClientBuilder builder = new CallingServerClientBuilder().httpClient(httpClientBuilder.build())
 .connectionString(connectionString);
 callingServerClient = builder.buildClient();

Start recording session using 'startRecordingWithResponse' server API

Use the server call ID received during initiation of the call.

URI recordingStateCallbackUri = new URI("<CallbackUri>");

Response<StartCallRecordingResult> response = this.callingServerClient.initializeServerCall("<serverCallId>")
.startRecordingWithResponse(String.valueOf(recordingStateCallbackUri), null, null);

The startRecordingWithResponse API response contains the recording ID of the recording session.

Start recording session with StartRecordingOptions using 'startRecordingWithResponse' server API

Use the server call ID received during initiation of the call.

  • RecordingContent is used to pass the recording content type. Ex: AUDIO/AUDIO_VIDEO.
  • RecordingChannel is used to pass the recording channel type. Ex: MIXED/UNMIXED.
  • RecordingFormat is used to pass the format of the recording. Ex: MP4/MP3/WAV.
URI recordingStateCallbackUri = new URI("<CallbackUri>");
StartRecordingOptions recordingOptions = new StartRecordingOptions();
recordingOptions.setRecordingContent(RecordingContent.AUDIO_VIDEO);
recordingOptions.setRecordingChannel(RecordingChannel.MIXED);
recordingOptions.setRecordingFormat(RecordingFormat.MP4);
Response<StartCallRecordingResult> response = this.callingServerClient.initializeServerCall("<serverCallId>")
.startRecordingWithResponse(String.valueOf(recordingStateCallbackUri), recordingOptions, null);

Specify a user on a channel 0 for unmixed audio-only

URI recordingStateCallbackUri = new URI("<CallbackUri>");
StartRecordingOptions recordingOptions = new StartRecordingOptions();
recordingOptions.setRecordingContent(RecordingContent.AUDIO);
recordingOptions.setRecordingChannel(RecordingChannel.UNMIXED);
recordingOptions.setRecordingFormat(RecordingFormat.WAV);
recordingOptions.setChannelAffinity({ new ChannelAffinity(0, user) });
Response<StartCallRecordingResult> response = this.callingServerClient.initializeServerCall("<serverCallId>")
.startRecordingWithResponse(String.valueOf(recordingStateCallbackUri), recordingOptions, null);

The StartRecordingAsync API response contains the recording ID of the recording session.

Stop recording session using 'stopRecordingWithResponse' server API

Use the recording ID received in response of startRecordingWithResponse.

Response<Void> response = this.callingServerClient.initializeServerCall(serverCallId)
.stopRecordingWithResponse(recordingId, null);

Pause recording session using 'pauseRecordingWithResponse' server API

Use the recording ID received in response of startRecordingWithResponse.

Response<Void> response = this.callingServerClient.initializeServerCall(serverCallId)
.pauseRecordingWithResponse(recordingId, null);

Resume recording session using 'resumeRecordingWithResponse' server API

Use the recording ID received in response of startRecordingWithResponse.

Response<Void> response = this.callingServerClient.initializeServerCall(serverCallId)
.resumeRecordingWithResponse(serverCallId, null);

Download recording File using 'downloadToWithResponse' server API

Use an Azure Event Grid web hook or other triggered action should be used to notify your services when the recorded media is ready for download.

Below is an example of the event schema.

{
    "id": string, // Unique guid for event
    "topic": string, // Azure Communication Services resource id
    "subject": string, // /recording/call/{call-id}
    "data": {
        "recordingStorageInfo": {
            "recordingChunks": [
                {
                    "documentId": string, // Document id for retrieving from AMS storage
                    "contentLocation": string, //Azure Communication Services URL where the content is located
                    "metadataLocation": string, // Azure Communication Services URL where the metadata for this chunk is located
                    "index": int, // Index providing ordering for this chunk in the entire recording
                    "endReason": string, // Reason for chunk ending: "SessionEnded", "ChunkMaximumSizeExceeded”, etc.
                }
            ]
        },
        "recordingStartTime": string, // ISO 8601 date time for the start of the recording
        "recordingDurationMs": int, // Duration of recording in milliseconds
        "sessionEndReason": string // Reason for call ending: "CallEnded", "InitiatorLeft”, etc.
    },
    "eventType": string, // "Microsoft.Communication.RecordingFileStatusUpdated"
    "dataVersion": string, // "1.0"
    "metadataVersion": string, // "1"
    "eventTime": string // ISO 8601 date time for when the event was created
}

Use downloadToWithResponse method of CallingServerClient class for downloading the recorded media. Following are the supported parameters for downloadToWithResponse method:

  • contentLocation: Azure Communication Services URL where the content is located.
  • destinationPath : File location.
  • parallelDownloadOptionss: An optional ParallelDownloadOptions object to modify how the - parallel download will work.
  • overwrite: True to overwrite the file if it exists.
  • context: A Context representing the request context.
Boolean overwrite = true;
ParallelDownloadOptions parallelDownloadOptions = null;
Context context = null;

String filePath = String.format(".\\%s.%s", documentId, fileType);
Path destinationPath = Paths.get(filePath);

Response<Void> downloadResponse = callingServerClient.downloadToWithResponse(contentLocation, destinationPath, parallelDownloadOptions, overwrite, context);

The content location and document IDs for the recording files can be fetched from the contentLocation and documentId fields respectively, for each recordingChunk.

Clean up resources

If you want to clean up and remove a Communication Services subscription, you can delete the resource or resource group. Deleting the resource group also deletes any other resources associated with it. Learn more about cleaning up resources.

Next steps

For more information, see the following articles: