0

现在我试图通过插入以下示例中的代码来转移呼叫。你能复习一下吗?这是 Tom Morgan 的一个示例(https://github.com/tomorgan/TeamsIVRBotSample)。在 Bot.cs -> Method CallsOnIncoming (ICallCollection sender, CollectionEventArgs args) 类中,我将代码用于传输调用,但在调试代码时什么也不做。

这是原始 Bot.cs 文件的代码:

namespace ThoughtStuff.TeamsSamples.IVRBotSample
{
    using Microsoft.ApplicationInsights;
    using Microsoft.Extensions.Logging;
    using Microsoft.Graph;
    using Microsoft.Graph.Calls;
    using Microsoft.Graph.Core;
    using Microsoft.Graph.Core.Telemetry;
    using Microsoft.Graph.StatefulClient;
    using Sample.Common.Authentication;
    using Sample.Common.Meetings;
    using Sample.Common.OnlineMeetings;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using ThoughtStuff.TeamsSamples.Data;



    /// <summary>
    /// The core bot logic.
    /// </summary>
    public class Bot
    {

        private readonly IGraphLogger graphLogger;

        private ConcurrentDictionary<string, CallHandler> callHandlers = new ConcurrentDictionary<string, CallHandler>();

        private LinkedList<string> callbackLogs = new LinkedList<string>();

        private AuthenticationProvider authProvider;
        private TelemetryClient telemetry = new TelemetryClient();

        public Uri baseURL { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Bot"/> class.
        /// </summary>
        /// <param name="options">The bot options</param>
        /// <param name="loggerFactory">The logger factory</param>
        public Bot(BotOptions options, IGraphLogger graphLogger)
        {
            var instanceNotificationUri = CallAffinityMiddleware.GetWebInstanceCallbackUri(new Uri(options.BotBaseUrl, HttpRouteConstants.OnIncomingRequestRoute));

            this.graphLogger = graphLogger;
            this.baseURL = options.BotBaseUrl;

            var authProvider = new AuthenticationProvider(
                options.AppId,
                options.AppSecret,
                this.graphLogger);

            var builder = new StatefulClientBuilder("TeamsIVRBotSample", options.AppId, this.graphLogger);
            builder.SetAuthenticationProvider(authProvider);
            builder.SetNotificationUrl(instanceNotificationUri);
            builder.SetServiceBaseUrl(options.PlaceCallEndpointUrl);

            this.Client = builder.Build();


            this.Client.Calls().OnIncoming += this.CallsOnIncoming;
            this.Client.Calls().OnUpdated += this.CallsOnUpdated;

        }


        /// <summary>
        /// Gets the client.
        /// </summary>
        /// <value>
        /// The client.
        /// </value>
        public IStatefulClient Client { get; }



        /// <summary>
        /// add callback log for diagnostics
        /// </summary>
        /// <param name="message">the message</param>
        public void AddCallbackLog(string message)
        {
            this.callbackLogs.AddFirst(message);
        }


        /// <summary>
        /// Incoming call handler
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="CollectionEventArgs{ICall}"/> instance containing the event data.</param>
        private void CallsOnIncoming(ICallCollection sender, CollectionEventArgs<ICall> args)
        {
            Task answerTask;

            var call = args.AddedResources.First();

            var callee = call.Resource.Targets.First();
            var callType = callee?.Identity?.GetApplicationInstance() == null ? CallType.BotIncoming : CallType.BotEndpointIncoming;

            var callHandler = new IncomingCallHandler(this, call);
            this.callHandlers[call.Resource.Id] = callHandler;
            var mediaConfig = new List<MediaInfo>();

            answerTask = call.AnswerAsync(mediaConfig, new[] { Modality.Audio });

            Task.Run(async () =>
            {
                try
                {
                    await answerTask.ConfigureAwait(false);
                    this.graphLogger.Info("Started answering incoming call");
                }
                catch (Exception ex)
                {
                    this.graphLogger.Error(ex, $"Exception happened when answering the call.");
                }
            });
        }

        /// <summary>
        /// Updated call handler.
        /// </summary>
        /// <param name="sender">The <see cref="ICallCollection"/> sender.</param>
        /// <param name="args">The <see cref="CollectionEventArgs{ICall}"/> instance containing the event data.</param>
        private void CallsOnUpdated(ICallCollection sender, CollectionEventArgs<ICall> args)
        {
            foreach (var call in args.RemovedResources)
            {
                if (this.callHandlers.TryRemove(call.Id, out CallHandler handler))
                {
                    handler.Dispose();
                }
            }
        }



    }
}

这是我修改的用于转移呼叫的代码:

namespace ThoughtStuff.TeamsSamples.IVRBotSample
{
    using Microsoft.ApplicationInsights;
    using Microsoft.Extensions.Logging;
    using Microsoft.Graph;
    using Microsoft.Graph.Calls;
    using Microsoft.Graph.Core;
    using Microsoft.Graph.Core.Telemetry;
    using Microsoft.Graph.StatefulClient;
    using Sample.Common.Authentication;
    using Sample.Common.Meetings;
    using Sample.Common.OnlineMeetings;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using ThoughtStuff.TeamsSamples.Data;



    /// <summary>
    /// The core bot logic.
    /// </summary>
    public class Bot
    {

        private readonly IGraphLogger graphLogger;

        private ConcurrentDictionary<string, CallHandler> callHandlers = new ConcurrentDictionary<string, CallHandler>();

        private LinkedList<string> callbackLogs = new LinkedList<string>();

        private AuthenticationProvider authProvider;
        private TelemetryClient telemetry = new TelemetryClient();

        public Uri baseURL { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Bot"/> class.
        /// </summary>
        /// <param name="options">The bot options</param>
        /// <param name="loggerFactory">The logger factory</param>
        public Bot(BotOptions options, IGraphLogger graphLogger)
        {
            var instanceNotificationUri = CallAffinityMiddleware.GetWebInstanceCallbackUri(new Uri(options.BotBaseUrl, HttpRouteConstants.OnIncomingRequestRoute));

            this.graphLogger = graphLogger;
            this.baseURL = options.BotBaseUrl;

            var authProvider = new AuthenticationProvider(
                options.AppId,
                options.AppSecret,
                this.graphLogger);

            var builder = new StatefulClientBuilder("TeamsIVRBotSample", options.AppId, this.graphLogger);
            builder.SetAuthenticationProvider(authProvider);
            builder.SetNotificationUrl(instanceNotificationUri);
            builder.SetServiceBaseUrl(options.PlaceCallEndpointUrl);

            this.Client = builder.Build();


            this.Client.Calls().OnIncoming += this.CallsOnIncoming;
            this.Client.Calls().OnUpdated += this.CallsOnUpdated;

        }


        /// <summary>
        /// Gets the client.
        /// </summary>
        /// <value>
        /// The client.
        /// </value>
        public IStatefulClient Client { get; }



        /// <summary>
        /// add callback log for diagnostics
        /// </summary>
        /// <param name="message">the message</param>
        public void AddCallbackLog(string message)
        {
            this.callbackLogs.AddFirst(message);
        }



        /// <summary>
        /// Incoming call handler
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="CollectionEventArgs{ICall}"/> instance containing the event data.</param>
        private void CallsOnIncoming(ICallCollection sender, CollectionEventArgs<ICall> args)
        {



            Task answerTask;
            Task transferTask;

            var call = args.AddedResources.First();

            //****************************************************
            Dictionary<string, object> _additionalData = new Dictionary<string, object>();
            _additionalData.Add("tenantId", "72f988bf-86f1-41af-91ab-2d7cd011db47");

            var target = new InvitationParticipantInfo
            {
                LanguageId = "en-US", Region = "westus", EndpointType = EndpointType.Default, 
                Identity = new IdentitySet
                {
                    User = new Identity
                    {
                        AdditionalData = _additionalData,
                        //Id = "2137934521"
                        Id = "77b1cacb-c38b-4b57-a4a5-f5919360bc24",
                        //Id = "3df8c3ce-96c5-41fb-ac3c-79ca38bdf02e"


                    }
                }
            };

            //ICall oritinalCall = this.Client.Calls()[call.Id];

            //Task.Run(async () =>
            //{

            //    await oritinalCall.TransferAsync(target).ConfigureAwait(false);
            //});
            //*****************************************************

            var callee = call.Resource.Targets.First();
            var callType = callee?.Identity?.GetApplicationInstance() == null ? CallType.BotIncoming : CallType.BotEndpointIncoming;

            var callHandler = new IncomingCallHandler(this, call);
            this.callHandlers[call.Resource.Id] = callHandler;
            var mediaConfig = new List<MediaInfo>();


            answerTask = call.AnswerAsync(mediaConfig, new[] { Modality.Audio });
            transferTask = call.TransferAsync(target);
            Task.Run(async () =>
            {
                try
                {
                    //await answerTask.ConfigureAwait(false);
                    await transferTask.ConfigureAwait(false);
                    this.graphLogger.Info("Started answering incoming call");
                }
                catch (Exception ex)
                {
                    this.graphLogger.Error(ex, $"Exception happened when answering the call.");
                }
            });
        }



        /// <summary>
        /// Updated call handler.
        /// </summary>
        /// <param name="sender">The <see cref="ICallCollection"/> sender.</param>
        /// <param name="args">The <see cref="CollectionEventArgs{ICall}"/> instance containing the event data.</param>
        private void CallsOnUpdated(ICallCollection sender, CollectionEventArgs<ICall> args)
        {
            foreach (var call in args.RemovedResources)
            {
                if (this.callHandlers.TryRemove(call.Id, out CallHandler handler))
                {
                    handler.Dispose();
                }
            }
        }



    }
}
4

1 回答 1

0

我的猜测是,在呼叫进入“已建立”状态之前,您将无法转接呼叫。

您可以在通话后使用OnUpdated事件查看状态更改。

一旦呼叫达到该状态,您应该能够使用现有代码很好地转移呼叫。

有关相关示例,请查看机器人示例 IncidentBot,它有一个来电处理程序,一旦应答就会播放一条消息。查看IncomingCallHandler类及其用法。

于 2019-11-10T22:12:20.553 回答