Conduct audio calls with Skype in the v3 C# SDK

APPLIES TO: SDK v3

Note

As of October 31, 2019 the Skype channel no longer accepts new Bot publishing requests. This means that you can continue to develop bots using the Skype channel, but your bot will be limited to 100 users. You will not be able to publish your bot to a larger audience. Current Skype bots will continue to run uninterrupted. Read more about why some features are not available in Skype anymore.

If you are building a bot for Skype, your bot can communicate with users via audio call. Audio calls are useful when the user does not want to or cannot provide input by typing, tapping, or clicking.

A bot may support other user controls such as rich cards or text in addition to audio calls, or communicate through audio calls only.

The architecture for a bot that supports audio calls is very similar to that of a typical bot. The following code samples show how to enable support for audio calls via Skype with the Bot Framework SDK for .NET.

Enable support for audio calls

To enable a bot to support audio calls, define the CallingController.

[BotAuthentication]
[RoutePrefix("api/calling")]
public class CallingController : ApiController
{
    public CallingController() : base()
    {
        CallingConversation.RegisterCallingBot(callingBotService => new IVRBot(callingBotService));
    }

    [Route("callback")]
    public async Task<HttpResponseMessage> ProcessCallingEventAsync()
    {
        return await CallingConversation.SendAsync(this.Request, CallRequestType.CallingEvent);
    }

    [Route("call")]
    public async Task<HttpResponseMessage> ProcessIncomingCallAsync()
    {
        return await CallingConversation.SendAsync(this.Request, CallRequestType.IncomingCall);
    }
}

Note

In addition to the CallingController, which supports audio calls, a bot may also contain a MessagesController to support messages. Providing both options allows users to interact with the bot in the way that they prefer.

Answer the call

The ProcessIncomingCallAsync task will execute whenever a user initiates a call to this bot from Skype. The constructor registers the IVRBot class, which has a predefined handler for the incomingCallEvent.

The first action within the workflow should determine if the bot answers or rejects the incoming call. This workflow instructs the bot to answer the incoming call and then play a welcome message.

private Task OnIncomingCallReceived(IncomingCallEvent incomingCallEvent)
{
    this.callStateMap[incomingCallEvent.IncomingCall.Id] = new CallState(incomingCallEvent.IncomingCall.Participants);

    incomingCallEvent.ResultingWorkflow.Actions = new List<ActionBase>
    {
        new Answer { OperationId = Guid.NewGuid().ToString() },
        GetPromptForText(WelcomeMessage)
    };

    return Task.FromResult(true);
}

After the bot answers

If the bot answers the call, subsequent actions specified within the workflow will instruct the Skype Bot Platform for Calling to play prompt, record audio, recognize speech, or collect digits from a dial pad. The final action of the workflow might be to end the call.

This code sample defines a handler that will set up a menu after the welcome message completes.

private Task OnPlayPromptCompleted(PlayPromptOutcomeEvent playPromptOutcomeEvent)
{
    var callState = this.callStateMap[playPromptOutcomeEvent.ConversationResult.Id];
    SetupInitialMenu(playPromptOutcomeEvent.ResultingWorkflow);
    return Task.FromResult(true);
}

The CreateIvrOptions method defines that menu that will be presented to the user.

private static Recognize CreateIvrOptions(string textToBeRead, int numberOfOptions, bool includeBack)
{
    if (numberOfOptions > 9)
    {
        throw new Exception("too many options specified");
    }

    var choices = new List<RecognitionOption>();

    for (int i = 1; i <= numberOfOptions; i++)
    {
        choices.Add(new RecognitionOption { Name = Convert.ToString(i), DtmfVariation = (char)('0' + i) });
    }

    if (includeBack)
    {
        choices.Add(new RecognitionOption { Name = "#", DtmfVariation = '#' });
    }

    var recognize = new Recognize
    {
        OperationId = Guid.NewGuid().ToString(),
        PlayPrompt = GetPromptForText(textToBeRead),
        BargeInAllowed = true,
        Choices = choices
    };

    return recognize;
}

The RecognitionOption class defines both the spoken answer as well as the corresponding Dual-Tone Multi-Frequency (DTMF) variation. DTMF enables the user to answer by typing the corresponding digits on the keypad instead of speaking.

The OnRecognizeCompleted method processes the user's selection, and the input parameter recognizeOutcomeEvent contains the value of the user's selection.

private Task OnRecognizeCompleted(RecognizeOutcomeEvent recognizeOutcomeEvent)
{
    var callState = this.callStateMap[recognizeOutcomeEvent.ConversationResult.Id];
    ProcessMainMenuSelection(recognizeOutcomeEvent, callState);
    return Task.FromResult(true);
}

Support natural language

The bot can also be designed to support natural language responses. The Bing Speech API enables the bot to recognize words in the user's spoken reply.

private async Task OnRecordCompleted(RecordOutcomeEvent recordOutcomeEvent)
{
    recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
    {
        GetPromptForText(EndingMessage),
        new Hangup { OperationId = Guid.NewGuid().ToString() }
    };

    // Convert the audio to text
    if (recordOutcomeEvent.RecordOutcome.Outcome == Outcome.Success)
    {
        var record = await recordOutcomeEvent.RecordedContent;
        string text = await this.GetTextFromAudioAsync(record);

        var callState = this.callStateMap[recordOutcomeEvent.ConversationResult.Id];

        await this.SendSTTResultToUser("We detected the following audio: " + text, callState.Participants);
    }

    recordOutcomeEvent.ResultingWorkflow.Links = null;
    this.callStateMap.Remove(recordOutcomeEvent.ConversationResult.Id);
}

Sample code

For a complete sample that shows how to support audio calls with Skype using the Bot Framework SDK for .NET, see the Skype Calling Bot sample in GitHub.

Additional resources