Develop (#31)
* Removing MeetingScreenShots bot and updating ReadMe.md to reflect that conferencing scenarios are not supported. * Updating message
This commit is contained in:
Родитель
04223a0c7b
Коммит
053b73eebb
|
@ -6,6 +6,8 @@ This is an advanced capability which allows the bot to send and receive voice an
|
|||
|
||||
The Real-Time Media Platform for Bots works with the Skype Calling Cloud to take care of call setup and media session establishment, enabling the bot to engage in a voice and (optionally) video conversation with a Skype caller. The platform provides a simple "socket"-like API for the bot to send and receive media, and handles the real-time encoding and decoding of media, using codecs such as SILK for audio and H.264 for video.
|
||||
|
||||
**Currently Real-Time Media Platform supports P2P bots only. Conferencing scenarios are not supported.**
|
||||
|
||||
## Developer resources
|
||||
|
||||
### SDKs
|
||||
|
@ -25,3 +27,6 @@ To develop a real-time media bot, you must install these NuGet packages within y
|
|||
## Contributing
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
Release notes
|
||||
- Due to privacy concerns with bots, conferencing scenarios are currently not supported. Hence we have removed the MeetingScreenShots sample. We are working on enabling this feature again.
|
|
@ -1,263 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using CorrelationId = FrontEnd.Logging.CorrelationId;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrontEnd.CallLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// This class handles media related logic for a call.
|
||||
/// </summary>
|
||||
internal class MediaSession : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Msi when there is no dominant speaker
|
||||
/// </summary>
|
||||
public const uint DominantSpeaker_None = DominantSpeakerChangedEventArgs.None;
|
||||
|
||||
/// <summary>
|
||||
/// Unique correlationID of this particular call.
|
||||
/// </summary>
|
||||
private readonly string _correlationId;
|
||||
|
||||
/// <summary>
|
||||
/// The audio socket created for this particular call.
|
||||
/// </summary>
|
||||
private readonly AudioSocket _audioSocket;
|
||||
|
||||
/// <summary>
|
||||
/// The video based screen sharing socket created for this particular call.
|
||||
/// </summary>
|
||||
private readonly VideoSocket _videoSocket;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the call has been disposed
|
||||
/// </summary>
|
||||
private int _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// The time stamp when video image was updated last
|
||||
/// </summary>
|
||||
private DateTime _lastVideoCapturedTimeUtc = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// The time between each video frame capturing
|
||||
/// </summary>
|
||||
private TimeSpan VideoCaptureFrequency = TimeSpan.FromMilliseconds(1000);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// The current Video image
|
||||
/// </summary>
|
||||
public Bitmap CurrentVideoImage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Id of this call.
|
||||
/// </summary>
|
||||
public string Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The opaque media configuration object sent back to the Skype platform when answering a call.
|
||||
/// </summary>
|
||||
public JObject MediaConfiguration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of IRealTimeMediaCall that handles incoming and outgoing requests
|
||||
/// </summary>
|
||||
public readonly RealTimeMediaCall RealTimeMediaCall;
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Create a new instance of the MediaSession.
|
||||
/// </summary>
|
||||
public MediaSession(string id, string correlationId, RealTimeMediaCall call)
|
||||
{
|
||||
_correlationId = correlationId;
|
||||
this.Id = id;
|
||||
RealTimeMediaCall = call;
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: Call created");
|
||||
|
||||
try
|
||||
{
|
||||
_audioSocket = new AudioSocket(new AudioSocketSettings
|
||||
{
|
||||
StreamDirections = StreamDirection.Recvonly,
|
||||
SupportedAudioFormat = AudioFormat.Pcm16K, // audio format is currently fixed at PCM 16 KHz.
|
||||
CallId = correlationId
|
||||
});
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]:Created AudioSocket");
|
||||
|
||||
// video socket
|
||||
_videoSocket = new VideoSocket(new VideoSocketSettings
|
||||
{
|
||||
StreamDirections = StreamDirection.Recvonly,
|
||||
ReceiveColorFormat = VideoColorFormat.NV12,
|
||||
CallId = correlationId
|
||||
});
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: Created VideoSocket");
|
||||
|
||||
//audio socket events
|
||||
_audioSocket.DominantSpeakerChanged += OnDominantSpeakerChanged;
|
||||
|
||||
//Video socket events
|
||||
_videoSocket.VideoMediaReceived += OnVideoMediaReceived;
|
||||
|
||||
MediaConfiguration = MediaPlatform.CreateMediaConfiguration(_audioSocket, _videoSocket);
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: MediaConfiguration={MediaConfiguration.ToString(Formatting.Indented)}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Error in MediaSession creation" + ex.ToString());
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from all audio/video send/receive-related events, cancels tasks and disposes sockets
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 0)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: Disposing Call");
|
||||
|
||||
if (_audioSocket != null)
|
||||
{
|
||||
_audioSocket.DominantSpeakerChanged -= OnDominantSpeakerChanged;
|
||||
_audioSocket.Dispose();
|
||||
}
|
||||
|
||||
if (_videoSocket != null)
|
||||
{
|
||||
_videoSocket.VideoMediaReceived -= OnVideoMediaReceived;
|
||||
_videoSocket.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: Ignoring exception in dispose {ex}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Audio
|
||||
/// <summary>
|
||||
/// Listen for dominant speaker changes in the conference
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnDominantSpeakerChanged(object sender, DominantSpeakerChangedEventArgs e)
|
||||
{
|
||||
CorrelationId.SetCurrentId(_correlationId);
|
||||
Log.Info(
|
||||
new CallerInfo(),
|
||||
LogContext.Media,
|
||||
$"[{this.Id}:OnDominantSpeakerChanged(DominantSpeaker={e.CurrentDominantSpeaker})]"
|
||||
);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await RealTimeMediaCall.Subscribe(e.CurrentDominantSpeaker, true).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"[{this.Id}]: Ignoring exception in subscribe {ex}");
|
||||
}
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Video
|
||||
private void OnVideoMediaReceived(object sender, VideoMediaReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
CorrelationId.SetCurrentId(_correlationId);
|
||||
|
||||
if (DateTime.Now > this._lastVideoCapturedTimeUtc + this.VideoCaptureFrequency)
|
||||
{
|
||||
// Update the last capture timestamp
|
||||
this._lastVideoCapturedTimeUtc = DateTime.Now;
|
||||
|
||||
Log.Info(
|
||||
new CallerInfo(),
|
||||
LogContext.Media,
|
||||
"[{0}]: Capturing image: [VideoMediaReceivedEventArgs(Data=<{1}>, Length={2}, Timestamp={3}, Width={4}, Height={5}, ColorFormat={6}, FrameRate={7})]",
|
||||
this.Id,
|
||||
e.Buffer.Data.ToString(),
|
||||
e.Buffer.Length,
|
||||
e.Buffer.Timestamp,
|
||||
e.Buffer.VideoFormat.Width,
|
||||
e.Buffer.VideoFormat.Height,
|
||||
e.Buffer.VideoFormat.VideoColorFormat,
|
||||
e.Buffer.VideoFormat.FrameRate);
|
||||
|
||||
// Make a copy of the media buffer
|
||||
Stopwatch watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
byte[] buffer = new byte[e.Buffer.Length];
|
||||
Marshal.Copy(e.Buffer.Data, buffer, 0, (int)e.Buffer.Length);
|
||||
|
||||
VideoMediaBuffer videoRenderMediaBuffer = e.Buffer as VideoMediaBuffer;
|
||||
|
||||
IntPtr ptrToBuffer = Marshal.AllocHGlobal(buffer.Length);
|
||||
Marshal.Copy(buffer, 0, ptrToBuffer, buffer.Length);
|
||||
|
||||
watch.Stop();
|
||||
Log.Info(new CallerInfo(), LogContext.Media, $"{this.Id} Took {watch.ElapsedMilliseconds} ms to copy buffer");
|
||||
|
||||
// Transform to bitmap object
|
||||
Bitmap bmpObject = MediaUtils.TransformNV12ToBmpFaster(buffer, e.Buffer.VideoFormat.Width, e.Buffer.VideoFormat.Height);
|
||||
|
||||
bool sendChatMessage = (CurrentVideoImage == null);
|
||||
Log.Info(new CallerInfo(), LogContext.Media, $"{this.Id} send chat message {sendChatMessage}");
|
||||
|
||||
// 3. Update the bitmap cache
|
||||
CurrentVideoImage = bmpObject;
|
||||
|
||||
if (sendChatMessage)
|
||||
{
|
||||
Task.Run(async () => {
|
||||
try
|
||||
{
|
||||
await RealTimeMediaCall.SendMessageForCall(RealTimeMediaCall);
|
||||
}catch(Exception ex)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Exception in SendingChatMessage {ex}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.Media, $"{this.Id} Exception in VideoMediaReceived {ex.ToString()}");
|
||||
}
|
||||
|
||||
e.Buffer.Dispose();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using FrontEnd.Logging;
|
||||
|
||||
namespace FrontEnd
|
||||
{
|
||||
/// <summary>
|
||||
/// Media related utility class
|
||||
/// </summary>
|
||||
public class MediaUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Transform NV12 to bmp image so we can view how is it looks like. Note it's not NV12 to RBG conversion.
|
||||
/// </summary>
|
||||
/// <param name="data">NV12 sample data</param>
|
||||
/// <param name="width">Image width</param>
|
||||
/// <param name="height">Image height</param>
|
||||
public static Bitmap TransformNV12ToBmpFaster(byte[] data, int width = 1280, int height = 720)
|
||||
{
|
||||
int stride = (int)(4 * (((width * (Image.GetPixelFormatSize(PixelFormat.Format32bppRgb) / 8)) + 3) / 4));
|
||||
|
||||
Stopwatch watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
Bitmap bmp = new Bitmap((int)width, (int)height, PixelFormat.Format32bppRgb);
|
||||
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* ptr = (byte*)bmpData.Scan0;
|
||||
int uvStart = (int)width * (int)height;
|
||||
for (int y = 0; y < (int)height; y++)
|
||||
{
|
||||
int currentLine = y * bmpData.Stride;
|
||||
for (int x = 0; x < (int)width; x++)
|
||||
{
|
||||
int vIndex = uvStart + (y >> 1) * (int)width + ((x >> 1) << 1);
|
||||
byte grayscale = data[x + (y * width)];
|
||||
byte blue = (byte)(data[vIndex] + grayscale - 127);
|
||||
byte red = (byte)(data[vIndex + 1] + grayscale - 127);
|
||||
byte green = (byte)(1.704 * grayscale - 0.510 * red - 0.194 * blue);
|
||||
|
||||
ptr[(x * 4) + y * stride] = blue;
|
||||
ptr[(x * 4) + y * stride + 1] = green;
|
||||
ptr[(x * 4) + y * stride + 2] = red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmp.UnlockBits(bmpData);
|
||||
|
||||
watch.Stop();
|
||||
Log.Info(new CallerInfo(), LogContext.Media, "Took {0} ms to lock and unlock", watch.ElapsedMilliseconds);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,370 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Bot.Builder.Calling.ObjectModel.Contracts;
|
||||
using Microsoft.Bot.Builder.Calling.ObjectModel.Misc;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling.Events;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling.ObjectModel.Contracts;
|
||||
using Microsoft.Bot.Connector;
|
||||
using FrontEnd.Http;
|
||||
|
||||
namespace FrontEnd.CallLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// This class does all the signaling needed to handle a call.
|
||||
/// </summary>
|
||||
internal class RealTimeMediaCall : IRealTimeMediaCall
|
||||
{
|
||||
/// <summary>
|
||||
/// Container for the current active calls.
|
||||
/// </summary>
|
||||
private static ConcurrentDictionary<string, RealTimeMediaCall> ActiveMediaCalls;
|
||||
|
||||
/// <summary>
|
||||
/// The MediaStreamId of the participant to which the video channel is currently subscribed to
|
||||
/// </summary>
|
||||
private RosterParticipant _subscribedToParticipant;
|
||||
|
||||
/// <summary>
|
||||
/// Roster to get the video msi of the dominant speaker
|
||||
/// </summary>
|
||||
private IEnumerable<RosterParticipant> _participants;
|
||||
|
||||
/// <summary>
|
||||
/// MediaSession that handles media related details
|
||||
/// </summary>
|
||||
public MediaSession MediaSession { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// ThreadId corresponding to this call to tie with chat messages for this conversation
|
||||
/// </summary>
|
||||
public string ThreadId;
|
||||
|
||||
/// <summary>
|
||||
/// Service that helps parse incoming requests and provide corresponding events
|
||||
/// </summary>
|
||||
public IRealTimeMediaCallService CallService { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id generated locally that is unique to each RealTimeMediaCall
|
||||
/// </summary>
|
||||
public readonly string CallId;
|
||||
|
||||
/// <summary>
|
||||
/// CorrelationId that needs to be set in the media platform for correlating logs across services
|
||||
/// </summary>
|
||||
public readonly string CorrelationId;
|
||||
|
||||
static RealTimeMediaCall()
|
||||
{
|
||||
ActiveMediaCalls = new ConcurrentDictionary<string, RealTimeMediaCall>();
|
||||
}
|
||||
|
||||
public RealTimeMediaCall(IRealTimeMediaCallService callService)
|
||||
{
|
||||
if (callService == null)
|
||||
throw new ArgumentNullException(nameof(callService));
|
||||
|
||||
CallService = callService;
|
||||
CorrelationId = callService.CorrelationId;
|
||||
CallId = CorrelationId + ":" + Guid.NewGuid().ToString();
|
||||
|
||||
//Register for the events
|
||||
CallService.OnIncomingCallReceived += OnIncomingCallReceived;
|
||||
CallService.OnAnswerAppHostedMediaCompleted += OnAnswerAppHostedMediaCompleted;
|
||||
CallService.OnCallStateChangeNotification += OnCallStateChangeNotification;
|
||||
CallService.OnRosterUpdateNotification += OnRosterUpdateNotification;
|
||||
CallService.OnCallCleanup += OnCallCleanup;
|
||||
}
|
||||
|
||||
private Task OnIncomingCallReceived(RealTimeMediaIncomingCallEvent incomingCallEvent)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] OnIncomingCallReceived");
|
||||
|
||||
//handles the media for this call like creating sockets, registering for events on the socket and sending/receiving media
|
||||
MediaSession = new MediaSession(CallId, CorrelationId, this);
|
||||
incomingCallEvent.RealTimeMediaWorkflow.Actions = new ActionBase[]
|
||||
{
|
||||
new AnswerAppHostedMedia
|
||||
{
|
||||
MediaConfiguration = MediaSession.MediaConfiguration,
|
||||
OperationId = Guid.NewGuid().ToString()
|
||||
}
|
||||
};
|
||||
|
||||
//subscribe for roster changes and call state changes
|
||||
incomingCallEvent.RealTimeMediaWorkflow.NotificationSubscriptions = new NotificationType[] { NotificationType.RosterUpdate, NotificationType.CallStateChange};
|
||||
ThreadId = incomingCallEvent.IncomingCall.ThreadId;
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Answering the call");
|
||||
|
||||
ActiveMediaCalls.AddOrUpdate(CallId, this, (callId, oldcall) => this);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task OnAnswerAppHostedMediaCompleted(AnswerAppHostedMediaOutcomeEvent answerAppHostedMediaOutcomeEvent)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] OnAnswerAppHostedMediaCompleted");
|
||||
AnswerAppHostedMediaOutcome answerAppHostedMediaOutcome = answerAppHostedMediaOutcomeEvent.AnswerAppHostedMediaOutcome;
|
||||
if (answerAppHostedMediaOutcome.Outcome == Outcome.Failure)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] AnswerAppHostedMedia failed with reason: {answerAppHostedMediaOutcome.FailureReason}");
|
||||
//cleanup internal resources
|
||||
MediaSession.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
answerAppHostedMediaOutcomeEvent.RealTimeMediaWorkflow.NotificationSubscriptions = new NotificationType[] { NotificationType.CallStateChange, NotificationType.RosterUpdate };
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] threw {ex.ToString()}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnRosterUpdateNotification(RosterUpdateNotification rosterUpdateNotification)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] OnRosterUpdateNotification");
|
||||
_participants = rosterUpdateNotification.Participants;
|
||||
|
||||
uint prevSubscribedMsi = (_subscribedToParticipant == null) ? MediaSession.DominantSpeaker_None
|
||||
: Convert.ToUInt32(_subscribedToParticipant.MediaStreamId);
|
||||
await Subscribe(prevSubscribedMsi, false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This gets called when the user hangs up the call to the bot
|
||||
/// </summary>
|
||||
/// <param name="callStateChangeNotification"></param>
|
||||
/// <returns></returns>
|
||||
private Task OnCallStateChangeNotification(CallStateChangeNotification callStateChangeNotification)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Received CallStateChangeNotification with AudioVideoCallStateType={callStateChangeNotification.CurrentState.ToString()}");
|
||||
|
||||
if (callStateChangeNotification.CurrentState == CallState.Terminated)
|
||||
{
|
||||
//cleanup the media session that disposes sockets, etc
|
||||
MediaSession.Dispose();
|
||||
RealTimeMediaCall temp;
|
||||
ActiveMediaCalls.TryRemove(CallId, out temp);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the IRealTimeMediaCallService detects an error and cleans up the call locally
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Task OnCallCleanup()
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Received OnCallCleanup");
|
||||
if (MediaSession != null)
|
||||
{
|
||||
MediaSession.Dispose();
|
||||
}
|
||||
|
||||
RealTimeMediaCall temp;
|
||||
ActiveMediaCalls.TryRemove(CallId, out temp);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe to the video stream of a participant. This function is called when dominant speaker notification is received and when roster changes
|
||||
/// When invoked on dominant speaker change, look if the participant is sharing their video. If yes then subscribe else choose the first participant in the list sharing their video
|
||||
/// When invoked on roster change, verify if the previously subscribed-to participant is still in the roster and sending video
|
||||
/// </summary>
|
||||
/// <param name="msi">Msi of dominant speaker or previously subscribed to msi depending on where it is invoked</param>
|
||||
/// <param name="msiOfDominantSpeaker">Gives more detail on the above msi.. Whether it is of dominant speaker or previously subscribed to video msi</param>
|
||||
/// <returns></returns>
|
||||
internal async Task Subscribe(uint msi, bool msiOfDominantSpeaker)
|
||||
{
|
||||
try
|
||||
{
|
||||
RosterParticipant participant;
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Received subscribe request for Msi {msi} msiOfDominantSpeaker {msiOfDominantSpeaker}");
|
||||
if(msiOfDominantSpeaker)
|
||||
{
|
||||
participant = GetParticipantWithDominantSpeakerMsi(msi);
|
||||
}
|
||||
else
|
||||
{
|
||||
participant = GetParticipantForRosterChange(msi);
|
||||
}
|
||||
|
||||
if (participant == null)
|
||||
{
|
||||
_subscribedToParticipant = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//if we have already subscribed earlier, skip the subscription
|
||||
if (_subscribedToParticipant != null && _subscribedToParticipant.MediaStreamId == participant.MediaStreamId)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Already subscribed to {participant.Identity}. So skipping subscription");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Subscribing to {participant.Identity} with msi {participant.MediaStreamId}");
|
||||
|
||||
//Get subscription details
|
||||
var videoSubscription = new VideoSubscription
|
||||
{
|
||||
ParticipantIdentity = participant.Identity,
|
||||
OperationId = Guid.NewGuid().ToString(),
|
||||
SocketId = 0, //index of the VideoSocket in MediaConfiguration which receives the incoming video stream
|
||||
VideoModality = ModalityType.Video,
|
||||
VideoResolution = ResolutionFormat.Hd1080p
|
||||
};
|
||||
|
||||
await CallService.Subscribe(videoSubscription).ConfigureAwait(false);
|
||||
_subscribedToParticipant = participant;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Subscribe threw exception {ex.ToString()}");
|
||||
_subscribedToParticipant = null;
|
||||
}
|
||||
}
|
||||
|
||||
private RosterParticipant GetParticipantWithDominantSpeakerMsi(uint dominantSpeakerMsi)
|
||||
{
|
||||
RosterParticipant firstParticipant = null;
|
||||
if (_participants == null)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Did not receive rosterupdate notification yet");
|
||||
return null;
|
||||
}
|
||||
|
||||
string dominantSpeakerIdentity = string.Empty;
|
||||
foreach (RosterParticipant participant in _participants)
|
||||
{
|
||||
if (participant.MediaStreamId == dominantSpeakerMsi.ToString())
|
||||
{
|
||||
//identify
|
||||
if (participant.MediaType == ModalityType.Audio)
|
||||
{
|
||||
dominantSpeakerIdentity = participant.Identity;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (participant.MediaType != ModalityType.Video
|
||||
|| !(participant.MediaStreamDirection == "sendonly" || participant.MediaStreamDirection == "sendrecv")
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//cache the first participant.. just incase dominant speaker is not sending video
|
||||
if (firstParticipant == null)
|
||||
{
|
||||
firstParticipant = participant;
|
||||
if (dominantSpeakerMsi == MediaSession.DominantSpeaker_None)
|
||||
{
|
||||
return firstParticipant;
|
||||
}
|
||||
}
|
||||
|
||||
//The dominant speaker is sending video..
|
||||
if (participant.Identity == dominantSpeakerIdentity)
|
||||
{
|
||||
return participant;
|
||||
}
|
||||
}
|
||||
|
||||
//If dominant speaker is not sending video or if dominant speaker has exited the conference, choose the first participant sending video
|
||||
return firstParticipant;
|
||||
}
|
||||
|
||||
private RosterParticipant GetParticipantForRosterChange(uint msi)
|
||||
{
|
||||
RosterParticipant firstParticipant = null;
|
||||
if (_participants == null)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"[{CallId}] Did not receive rosterupdate notification yet");
|
||||
return null;
|
||||
}
|
||||
|
||||
string dominantSpeakerIdentity = string.Empty;
|
||||
foreach (RosterParticipant participant in _participants)
|
||||
{
|
||||
if (participant.MediaStreamId == msi.ToString())
|
||||
{
|
||||
if (participant.MediaType == ModalityType.Video && (participant.MediaStreamDirection == "sendonly" || participant.MediaStreamDirection == "sendrecv"))
|
||||
{
|
||||
return participant;
|
||||
}
|
||||
}
|
||||
|
||||
if (participant.MediaType != ModalityType.Video
|
||||
|| !(participant.MediaStreamDirection == "sendonly" || participant.MediaStreamDirection == "sendrecv")
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (firstParticipant == null)
|
||||
{
|
||||
firstParticipant = participant;
|
||||
}
|
||||
}
|
||||
|
||||
//No dominant speaker or dominant speaker is not sending video or if old dominant speaker has exited the conference, choose a new oe
|
||||
return firstParticipant;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug: Get a list of the active mediasessions
|
||||
/// </summary>
|
||||
/// <returns>List of current call identifiers.</returns>
|
||||
public static IList<string> GetActiveRealTimeMediaCalls()
|
||||
{
|
||||
return ActiveMediaCalls.Values.Select(x => x.CallId).ToList();
|
||||
}
|
||||
|
||||
internal static RealTimeMediaCall GetCallForCallId(string callId)
|
||||
{
|
||||
return ActiveMediaCalls.Values.FirstOrDefault(x => (x.CallId == callId));
|
||||
}
|
||||
|
||||
internal static async Task SendUrlForConversationId(string threadId)
|
||||
{
|
||||
RealTimeMediaCall mediaCall = ActiveMediaCalls.Values.FirstOrDefault(x => (x.ThreadId == threadId));
|
||||
if (mediaCall == null)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"No active mediacall for {threadId}");
|
||||
return;
|
||||
}
|
||||
await SendMessageForCall(mediaCall);
|
||||
}
|
||||
|
||||
internal static async Task SendMessageForCall(RealTimeMediaCall mediaCall)
|
||||
{
|
||||
string url = $"{Service.Instance.Configuration.AzureInstanceBaseUrl}/{HttpRouteConstants.CallSignalingRoutePrefix}/{HttpRouteConstants.Image}";
|
||||
url = url.Replace("{callid}", mediaCall.CallId);
|
||||
try
|
||||
{
|
||||
await MessageSender.SendMessage(mediaCall.ThreadId, url);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, $"[{mediaCall.CallId}] Exception in sending chat {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System.Drawing;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using FrontEnd.Http;
|
||||
using FrontEnd.Logging;
|
||||
|
||||
namespace FrontEnd.CallLogic
|
||||
{
|
||||
public static class VideoImageViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the image for a particular call
|
||||
/// </summary>
|
||||
/// <param name="conversationResult"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponseMessage GetVideoImageResponse(string callId)
|
||||
{
|
||||
RealTimeMediaCall mediaCall = RealTimeMediaCall.GetCallForCallId(callId);
|
||||
if (mediaCall == null)
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
MediaSession mediaSession = mediaCall.MediaSession;
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"[{callId}] Received request to retrieve image for call");
|
||||
Bitmap bitmap = mediaSession.CurrentVideoImage;
|
||||
if (bitmap == null)
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
|
||||
response.Content = new PushStreamContent((targetStream, httpContext, transportContext) =>
|
||||
{
|
||||
using (targetStream)
|
||||
{
|
||||
bitmap.Save(targetStream, System.Drawing.Imaging.ImageFormat.Jpeg);
|
||||
}
|
||||
}, new MediaTypeHeaderValue("image/jpeg"));
|
||||
|
||||
response.Headers.Add("Cache-Control", "private,must-revalidate,post-check=1,pre-check=2,no-cache");
|
||||
|
||||
string url = $"{Service.Instance.Configuration.AzureInstanceBaseUrl}/{HttpRouteConstants.CallSignalingRoutePrefix}/{HttpRouteConstants.Image}";
|
||||
url = url.Replace("{callid}", callId);
|
||||
response.Headers.Add("Refresh", $"3; url={url}");
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,349 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props" Condition="Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>FrontEnd</RootNamespace>
|
||||
<AssemblyName>FrontEnd</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=3.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.Attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.Attributes.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.IO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.IO.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.JSON, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Runtime.CSharp.4.2.1\lib\net45\Bond.JSON.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Chronic, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3bd1f1ef638b0d3c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Builder.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.Autofac, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Builder.Autofac.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.Calling, Version=3.0.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.Calling.3.0.4\lib\net46\Microsoft.Bot.Builder.Calling.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.RealTimeMediaCalling, Version=1.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.RealTimeMediaCalling.1.0.4-alpha\lib\net46\Microsoft.Bot.Builder.RealTimeMediaCalling.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Connector, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Connector.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Protocol.Extensions, Version=1.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.4.403061554\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Hosting, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.OAuth, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.OpenIdConnect, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.OpenIdConnect.3.0.1\lib\net45\Microsoft.Owin.Security.OpenIdConnect.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Rest.ClientRuntime.2.3.2\lib\net45\Microsoft.Rest.ClientRuntime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Skype.Bots.Media, Version=1.5.0.1177, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=AMD64">
|
||||
<HintPath>..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\lib\Microsoft.Skype.Bots.Media.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<SpecificVersion>True</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.Threading, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.VisualStudio.Threading.14.1.131\lib\net45\Microsoft.VisualStudio.Threading.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.Validation, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IdentityModel" />
|
||||
<Reference Include="System.IdentityModel.Tokens.Jwt, Version=4.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IdentityModel.Tokens.Jwt.4.0.4.403061554\lib\net45\System.IdentityModel.Tokens.Jwt.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Threading.Tasks.Dataflow, Version=4.5.25.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Dataflow.4.5.25\lib\dotnet\System.Threading.Tasks.Dataflow.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.Owin, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CallLogic\RealTimeMediaCall.cs" />
|
||||
<Compile Include="CallLogic\MediaSession.cs" />
|
||||
<Compile Include="CallLogic\MediaUtils.cs" />
|
||||
<Compile Include="CallLogic\VideoImageViewer.cs" />
|
||||
<Compile Include="Http\CallEndpointStartup.cs" />
|
||||
<Compile Include="Http\RealTimeMediaCallingBotServiceSettings.cs" />
|
||||
<Compile Include="Http\CallController.cs" />
|
||||
<Compile Include="Http\ExceptionLogger.cs" />
|
||||
<Compile Include="Http\HttpRouteConstants.cs" />
|
||||
<Compile Include="Http\LoggingMessageHandler.cs" />
|
||||
<Compile Include="Http\MessagesController.cs" />
|
||||
<Compile Include="Http\MessageSender.cs" />
|
||||
<Compile Include="IConfiguration.cs" />
|
||||
<Compile Include="Logging\CallerInfo.cs" />
|
||||
<Compile Include="Logging\CorrelationId.cs" />
|
||||
<Compile Include="Logging\Log.cs" />
|
||||
<Compile Include="MediaLogic\AudioSendBuffer.cs" />
|
||||
<Compile Include="MediaLogic\VideoSendBuffer.cs" />
|
||||
<Compile Include="Service.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\InstallMPServiceImpCounters.ps1">
|
||||
<Link>skype_media_lib\InstallMPServiceImpCounters.ps1</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.ini">
|
||||
<Link>skype_media_lib\MediaPerf.ini</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPlatformStartupScript.bat">
|
||||
<Link>skype_media_lib\MediaPlatformStartupScript.bat</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default.tmx">
|
||||
<Link>skype_media_lib\TraceFormat\default.tmx</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default_media.tmx">
|
||||
<Link>skype_media_lib\TraceFormat\default_media.tmx</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\EtlReader.dll">
|
||||
<Link>skype_media_lib\EtlReader.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.dll">
|
||||
<Link>skype_media_lib\MediaPerf.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.h">
|
||||
<Link>skype_media_lib\MediaPerf.h</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Applications.Telemetry.dll">
|
||||
<Link>skype_media_lib\Microsoft.Applications.Telemetry.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Applications.Telemetry.Server.dll">
|
||||
<Link>skype_media_lib\Microsoft.Applications.Telemetry.Server.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Bond.dll">
|
||||
<Link>skype_media_lib\Microsoft.Bond.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Bond.Interfaces.dll">
|
||||
<Link>skype_media_lib\Microsoft.Bond.Interfaces.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.ClsContracts.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.ClsContracts.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.ClsLite.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.ClsLite.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.Internal.Media.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.Internal.Media.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.Internal.Media.MediaApi.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.Internal.Media.MediaApi.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Skype.ECS.Client.dll">
|
||||
<Link>skype_media_lib\Microsoft.Skype.ECS.Client.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPAzAppHost.dll">
|
||||
<Link>skype_media_lib\MPAzAppHost.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPServiceHostLib.dll">
|
||||
<Link>skype_media_lib\MPServiceHostLib.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPServiceImp.dll">
|
||||
<Link>skype_media_lib\MPServiceImp.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\rtmcodecs.dll">
|
||||
<Link>skype_media_lib\rtmcodecs.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\RtmMvrCs.dll">
|
||||
<Link>skype_media_lib\RtmMvrCs.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\rtmpal.dll">
|
||||
<Link>skype_media_lib\rtmpal.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Skype.ECS.Criteria.dll">
|
||||
<Link>skype_media_lib\Skype.ECS.Criteria.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Skype.ECS.Utilities.dll">
|
||||
<Link>skype_media_lib\Skype.ECS.Utilities.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\SkypeRT.dll">
|
||||
<Link>skype_media_lib\SkypeRT.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default.xml">
|
||||
<Link>skype_media_lib\TraceFormat\default.xml</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets" Condition="Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets" Condition="Exists('..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,121 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using FrontEnd.CallLogic;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling;
|
||||
using Microsoft.Bot.Connector;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// CallContoller is the enty point for handling incoming call signaling HTTP requests from Skype platform.
|
||||
/// </summary>
|
||||
[RoutePrefix(HttpRouteConstants.CallSignalingRoutePrefix)]
|
||||
public class CallController : ApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiate a CallController with a specific ICallProcessor (e.g. for testing).
|
||||
/// </summary>
|
||||
/// <param name="callProcessor"></param>
|
||||
static CallController()
|
||||
{
|
||||
RealTimeMediaCalling.RegisterRealTimeMediaCallingBot(c => { return new RealTimeMediaCall(c); },
|
||||
new RealTimeMediaCallingBotServiceSettings()
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle an incoming call.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route(HttpRouteConstants.OnIncomingCallRoute)]
|
||||
[BotAuthentication]
|
||||
public async Task<HttpResponseMessage> OnIncomingCallAsync()
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Received HTTP {Request.Method}, {Request.RequestUri}");
|
||||
|
||||
var response = await RealTimeMediaCalling.SendAsync(Request, RealTimeMediaCallRequestType.IncomingCall).ConfigureAwait(false);
|
||||
|
||||
// Enforce the connection close to ensure that requests are evenly load balanced so
|
||||
// calls do no stick to one instance of the worker role.
|
||||
response.Headers.ConnectionClose = true;
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a callback for an existing call.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route(HttpRouteConstants.OnCallbackRoute)]
|
||||
[BotAuthentication]
|
||||
public async Task<HttpResponseMessage> OnCallbackAsync()
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Received HTTP {Request.Method}, {Request.RequestUri}");
|
||||
|
||||
//let the RealTimeMediaCalling SDK know of the incoming callback. The SDK deserializes the callback, validates it and calls the appropriate
|
||||
//events on the IRealTimeMediaCall for this request
|
||||
var response = await RealTimeMediaCalling.SendAsync(Request, RealTimeMediaCallRequestType.CallingEvent).ConfigureAwait(false);
|
||||
|
||||
// Enforce the connection close to ensure that requests are evenly load balanced so
|
||||
// calls do no stick to one instance of the worker role.
|
||||
response.Headers.ConnectionClose = true;
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a notification for an existing call.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route(HttpRouteConstants.OnNotificationRoute)]
|
||||
[BotAuthentication]
|
||||
public async Task<HttpResponseMessage> OnNotificationAsync()
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Notification Received HTTP {Request.Method} on {Request.RequestUri}");
|
||||
|
||||
//let the RealTimeMediaCalling SDK know of the incoming notification. The SDK deserializes the callback, validates it and calls the appropriate
|
||||
//events on the IRealTimeMediaCall for this request
|
||||
var response = await RealTimeMediaCalling.SendAsync(Request, RealTimeMediaCallRequestType.NotificationEvent).ConfigureAwait(false);
|
||||
|
||||
// Enforce the connection close to ensure that requests are evenly load balanced so
|
||||
// calls do no stick to one instance of the worker role.
|
||||
response.Headers.ConnectionClose = true;
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the image of screen sharing.
|
||||
/// </summary>
|
||||
/// <param name="callid">Id of the call to retrieve image</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route(HttpRouteConstants.Image)]
|
||||
public HttpResponseMessage OnGetImage(string callid)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Retrieving image for call id {callid}");
|
||||
|
||||
try
|
||||
{
|
||||
return VideoImageViewer.GetVideoImageResponse(callid);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warning(new CallerInfo(), LogContext.FrontEnd, $"[OnGetImage] Exception {e.ToString()}");
|
||||
var response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
|
||||
response.Content = new StringContent(e.ToString());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.ExceptionHandling;
|
||||
using FrontEnd.Logging;
|
||||
using Owin;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling.ObjectModel.Misc;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize the httpConfiguration for OWIN
|
||||
/// </summary>
|
||||
public class CallEndpointStartup
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration settings like Auth, Routes for OWIN
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
HttpConfiguration httpConfig = new HttpConfiguration();
|
||||
httpConfig.MapHttpAttributeRoutes();
|
||||
httpConfig.MessageHandlers.Add(new LoggingMessageHandler(isIncomingMessageHandler: true, logContext: LogContext.FrontEnd));
|
||||
|
||||
httpConfig.Services.Add(typeof(IExceptionLogger), new ExceptionLogger());
|
||||
httpConfig.Formatters.JsonFormatter.SerializerSettings = RealTimeMediaSerializer.GetSerializerSettings();
|
||||
httpConfig.EnsureInitialized();
|
||||
|
||||
app.UseWebApi(httpConfig);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http.ExceptionHandling;
|
||||
using FrontEnd.Logging;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
internal class ExceptionLogger : IExceptionLogger
|
||||
{
|
||||
public ExceptionLogger()
|
||||
{
|
||||
}
|
||||
|
||||
public Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Exception processing HTTP request. {0}", context.Exception.ToString());
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP route constants for routing requests to CallController methods.
|
||||
/// </summary>
|
||||
public static class HttpRouteConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Route prefix for all incoming requests.
|
||||
/// </summary>
|
||||
public const string CallSignalingRoutePrefix = "api/calling";
|
||||
|
||||
/// <summary>
|
||||
/// Route for incoming calls.
|
||||
/// </summary>
|
||||
public const string OnIncomingCallRoute = "call";
|
||||
|
||||
/// <summary>
|
||||
/// Route for incoming calls.
|
||||
/// </summary>
|
||||
public const string OnIncomingMessageRoute = "";
|
||||
|
||||
/// <summary>
|
||||
/// Route for existing call callbacks.
|
||||
/// </summary>
|
||||
public const string OnCallbackRoute = "callback";
|
||||
|
||||
/// <summary>
|
||||
/// Route for existing call notifications.
|
||||
/// </summary>
|
||||
public const string OnNotificationRoute = "notification";
|
||||
|
||||
/// <summary>
|
||||
/// Route for getting all calls
|
||||
/// </summary>
|
||||
public const string Calls = "calls";
|
||||
|
||||
/// <summary>
|
||||
/// Route for getting Image for a call
|
||||
/// </summary>
|
||||
public const string Image = "image/{callid}";
|
||||
}
|
||||
}
|
|
@ -1,339 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FrontEnd.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to log HTTP requests and responses and to set the CorrelationID based on the X-Microsoft-Skype-Chain-ID header
|
||||
/// value of incoming HTTP requests from Skype platform.
|
||||
/// </summary>
|
||||
internal class LoggingMessageHandler : DelegatingHandler
|
||||
{
|
||||
public const string CidHeaderName = "X-Microsoft-Skype-Chain-ID";
|
||||
|
||||
private readonly bool isIncomingMessageHandler;
|
||||
private readonly LogContext logContext;
|
||||
private string[] urlIgnorers;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new LoggingMessageHandler.
|
||||
/// </summary>
|
||||
public LoggingMessageHandler(bool isIncomingMessageHandler, LogContext logContext, string[] urlIgnorers = null)
|
||||
{
|
||||
this.isIncomingMessageHandler = isIncomingMessageHandler;
|
||||
this.logContext = logContext;
|
||||
this.urlIgnorers = urlIgnorers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the request and response.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
string requestCid;
|
||||
string responseCid;
|
||||
|
||||
if (this.isIncomingMessageHandler)
|
||||
{
|
||||
requestCid = AdoptCorrelationId(request.Headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestCid = SetCorrelationId(request.Headers);
|
||||
}
|
||||
|
||||
bool ignore =
|
||||
this.urlIgnorers != null &&
|
||||
this.urlIgnorers.Any(ignorer => request.RequestUri.ToString().IndexOf(ignorer, StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
|
||||
if (ignore)
|
||||
{
|
||||
return await SendAndLogAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string localMessageId = Guid.NewGuid().ToString();
|
||||
string requestUriText = request.RequestUri.ToString();
|
||||
string requestHeadersText = GetHeadersText(request.Headers);
|
||||
|
||||
if (request.Content != null)
|
||||
{
|
||||
requestHeadersText =
|
||||
String.Join(
|
||||
Environment.NewLine,
|
||||
requestHeadersText,
|
||||
GetHeadersText(request.Content.Headers));
|
||||
}
|
||||
|
||||
string requestBodyText = await GetBodyText(request.Content).ConfigureAwait(false);
|
||||
|
||||
Log.Info(new CallerInfo(), logContext, "|| correlationId={0} || local.msgid={1} ||{2}{3}:: {4} {5}{6}{7}{8}{9}{10}$$END$$",
|
||||
requestCid, localMessageId,
|
||||
Environment.NewLine,
|
||||
this.isIncomingMessageHandler ? "Incoming" : "Outgoing",
|
||||
request.Method.ToString(),
|
||||
requestUriText,
|
||||
Environment.NewLine,
|
||||
requestHeadersText,
|
||||
Environment.NewLine,
|
||||
requestBodyText,
|
||||
Environment.NewLine);
|
||||
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
HttpResponseMessage response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
Log.Info(
|
||||
new CallerInfo(),
|
||||
logContext,
|
||||
"{0} HTTP request with Local id={1} took {2}ms.",
|
||||
this.isIncomingMessageHandler ? "Incoming" : "Outgoing",
|
||||
localMessageId,
|
||||
stopwatch.ElapsedMilliseconds);
|
||||
|
||||
if (this.isIncomingMessageHandler)
|
||||
{
|
||||
responseCid = SetCorrelationId(response.Headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
responseCid = AdoptCorrelationId(response.Headers);
|
||||
}
|
||||
|
||||
this.WarnIfDifferent(requestCid, responseCid);
|
||||
|
||||
HttpStatusCode statusCode = response.StatusCode;
|
||||
|
||||
string responseUriText = request.RequestUri.ToString();
|
||||
string responseHeadersText = GetHeadersText(response.Headers);
|
||||
|
||||
if (response.Content != null)
|
||||
{
|
||||
responseHeadersText =
|
||||
String.Join(
|
||||
Environment.NewLine,
|
||||
responseHeadersText,
|
||||
GetHeadersText(response.Content.Headers));
|
||||
}
|
||||
|
||||
string responseBodyText = await GetBodyText(response.Content).ConfigureAwait(false);
|
||||
|
||||
Log.Info(new CallerInfo(), logContext, "|| correlationId={0} || statuscode={1} || local.msgid={2} ||{3}Response to {4}:: {5} {6}{7}{8} {9}{10}{11}{12}{13}{14}$$END$$",
|
||||
CorrelationId.GetCurrentId(), statusCode, localMessageId,
|
||||
Environment.NewLine,
|
||||
this.isIncomingMessageHandler ? "incoming" : "outgoing",
|
||||
request.Method.ToString(),
|
||||
responseUriText,
|
||||
Environment.NewLine,
|
||||
((int)response.StatusCode).ToString(),
|
||||
response.StatusCode.ToString(),
|
||||
Environment.NewLine,
|
||||
responseHeadersText,
|
||||
Environment.NewLine,
|
||||
responseBodyText,
|
||||
Environment.NewLine);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendAndLogAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Exception occurred when calling SendAsync: {0}", e.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void WarnIfDifferent(string requestCid, string responseCid)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(requestCid) || string.IsNullOrWhiteSpace(responseCid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.Equals(requestCid, responseCid))
|
||||
{
|
||||
Log.Warning(
|
||||
new CallerInfo(), LogContext.FrontEnd,
|
||||
"The correlationId of the {0} request, {1}, is different from the {2} response, {3}.",
|
||||
this.isIncomingMessageHandler ? "incoming" : "outgoing",
|
||||
requestCid,
|
||||
this.isIncomingMessageHandler ? "outgoing" : "outgoing",
|
||||
responseCid);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetHeadersText(HttpHeaders headers)
|
||||
{
|
||||
if (headers == null || !headers.Any())
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
List<string> headerTexts = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, IEnumerable<string>> h in headers)
|
||||
{
|
||||
headerTexts.Add(GetHeaderText(h));
|
||||
}
|
||||
|
||||
return String.Join(Environment.NewLine, headerTexts);
|
||||
}
|
||||
|
||||
private static string GetHeaderText(KeyValuePair<string, IEnumerable<string>> header)
|
||||
{
|
||||
return String.Format("{0}: {1}", header.Key, String.Join(",", header.Value));
|
||||
}
|
||||
|
||||
private static string AdoptCorrelationId(HttpHeaders headers)
|
||||
{
|
||||
string correlationId = null;
|
||||
IEnumerable<string> correlationIdHeaderValues;
|
||||
if (headers.TryGetValues(CidHeaderName, out correlationIdHeaderValues))
|
||||
{
|
||||
correlationId = correlationIdHeaderValues.FirstOrDefault();
|
||||
CorrelationId.SetCurrentId(correlationId);
|
||||
}
|
||||
|
||||
return correlationId;
|
||||
}
|
||||
|
||||
private static string SetCorrelationId(HttpHeaders headers)
|
||||
{
|
||||
string correlationId = CorrelationId.GetCurrentId();
|
||||
if (!string.IsNullOrWhiteSpace(correlationId))
|
||||
{
|
||||
headers.Add(CidHeaderName, correlationId);
|
||||
}
|
||||
|
||||
return correlationId;
|
||||
}
|
||||
|
||||
public static async Task<string> GetBodyText(HttpContent content)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
return "(empty body)";
|
||||
}
|
||||
|
||||
if (content.IsMimeMultipartContent())
|
||||
{
|
||||
Stream stream = await content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
return "(cannot log body because HTTP stream cannot seek)";
|
||||
}
|
||||
|
||||
StringBuilder multipartBodyBuilder = new StringBuilder();
|
||||
MultipartMemoryStreamProvider streamProvider = new MultipartMemoryStreamProvider();
|
||||
await content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(streamProvider, (int)stream.Length).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var multipartContent in streamProvider.Contents)
|
||||
{
|
||||
multipartBodyBuilder.AppendLine("-- beginning of multipart content --");
|
||||
|
||||
// Headers
|
||||
string headerText = GetHeadersText(multipartContent.Headers);
|
||||
multipartBodyBuilder.AppendLine(headerText);
|
||||
|
||||
// Body of message
|
||||
string multipartBody = await multipartContent.ReadAsStringAsync().ConfigureAwait(false);
|
||||
string formattedJsonBody;
|
||||
|
||||
if (TryFormatJsonBody(multipartBody, out formattedJsonBody))
|
||||
{
|
||||
multipartBody = formattedJsonBody;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(multipartBody))
|
||||
{
|
||||
multipartBodyBuilder.AppendLine("(empty body)");
|
||||
}
|
||||
else
|
||||
{
|
||||
multipartBodyBuilder.AppendLine(multipartBody);
|
||||
}
|
||||
|
||||
multipartBodyBuilder.AppendLine("-- end of multipart content --");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Reset the stream position so consumers of this class can re-read the multipart content.
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
return multipartBodyBuilder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
string body = await content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
string formattedJsonBody;
|
||||
if (TryFormatJsonBody(body, out formattedJsonBody))
|
||||
{
|
||||
body = formattedJsonBody;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
return "(empty body)";
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryFormatJsonBody(string body, out string jsonBody)
|
||||
{
|
||||
jsonBody = null;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
object parsedObject = JsonConvert.DeserializeObject(body);
|
||||
|
||||
if (parsedObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonBody = JsonConvert.SerializeObject(parsedObject, Formatting.Indented);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Bot.Connector;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper to send chat messages
|
||||
/// </summary>
|
||||
internal class MessageSender
|
||||
{
|
||||
/// <summary>
|
||||
/// Send chat message on a conversation thread with the url as the text message
|
||||
/// </summary>
|
||||
/// <param name="threadId">ThreadId for the conversation that the chat message needs to be sent</param>
|
||||
/// <param name="urlText">Url that needs to be send in the chat message</param>
|
||||
/// <returns></returns>
|
||||
public static async Task SendMessage(string threadId, string urlText)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MessagesController.MessagesServiceUrl == null)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Bot has not received a chat message before. So it cannot send a message back");
|
||||
return;
|
||||
}
|
||||
|
||||
var connector = new ConnectorClient(new Uri(MessagesController.MessagesServiceUrl));
|
||||
IMessageActivity newMessage = Activity.CreateMessageActivity();
|
||||
newMessage.Type = ActivityTypes.Message;
|
||||
newMessage.From = MessagesController.BotAccount;
|
||||
newMessage.Conversation = new ConversationAccount(true, threadId);
|
||||
newMessage.Text = "[Click here for video shots from the conference](" + urlText + ")";
|
||||
await connector.Conversations.SendToConversationAsync((Activity)newMessage);
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"sent message");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, $"{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using FrontEnd.CallLogic;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Bot.Connector;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
[BotAuthentication]
|
||||
[RoutePrefix("api/messages")]
|
||||
public class MessagesController : ApiController
|
||||
{
|
||||
public static string MessagesServiceUrl;
|
||||
public static ChannelAccount BotAccount;
|
||||
|
||||
/// <summary>
|
||||
/// POST: api/Messages
|
||||
/// receive a message from a user and send replies
|
||||
/// </summary>
|
||||
/// <param name="activity"></param>
|
||||
[HttpPost]
|
||||
[Route(HttpRouteConstants.OnIncomingMessageRoute)]
|
||||
public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
|
||||
{
|
||||
//cache the serviceUrl and bot account
|
||||
MessagesServiceUrl = activity.ServiceUrl;
|
||||
BotAccount = activity.Recipient;
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"Received chat message.. checking if there is an active media call for this thread");
|
||||
await RealTimeMediaCall.SendUrlForConversationId(activity.Conversation.Id);
|
||||
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using Microsoft.Bot.Builder.RealTimeMediaCalling;
|
||||
|
||||
namespace FrontEnd.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Service settings to configure the RealTimeMediaCalling
|
||||
/// </summary>
|
||||
public class RealTimeMediaCallingBotServiceSettings : IRealTimeMediaCallServiceSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// The url where the callbacks for the calls to this bot needs to be sent.
|
||||
/// For example "https://testservice.azurewebsites.net/api/calling/callback"
|
||||
/// </summary>
|
||||
public Uri CallbackUrl { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url where the notifications for the calls to this bot needs to be sent.
|
||||
/// For example "https://testservice.azurewebsites.net/api/calling/notification"
|
||||
/// </summary>
|
||||
public Uri NotificationUrl { get; private set; }
|
||||
|
||||
public RealTimeMediaCallingBotServiceSettings()
|
||||
{
|
||||
CallbackUrl = Service.Instance.Configuration.CallControlCallbackUrl;
|
||||
NotificationUrl = Service.Instance.Configuration.NotificationCallbackUrl;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
|
||||
namespace FrontEnd
|
||||
{
|
||||
/// <summary>
|
||||
/// IConfiguration contains the static configuration information the application needs
|
||||
/// to run such as the urls it needs to listen on, credentials to communicate with
|
||||
/// Bing translator, settings for media.platform, etc.
|
||||
///
|
||||
/// The concrete implemenation AzureConfiguration gets the configuration from Azure. However,
|
||||
/// other concrete classes could be created to allow the application to run outside of Azure
|
||||
/// for testing.
|
||||
/// </summary>
|
||||
public interface IConfiguration : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Dns name for this service
|
||||
/// </summary>
|
||||
string ServiceDnsName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of HTTP urls the app should listen on for incoming call
|
||||
/// signaling requests from Skype Platform.
|
||||
/// </summary>
|
||||
IEnumerable<Uri> CallControlListeningUrls { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The base callback URL for this instance. To ensure that all requests
|
||||
/// for a given call go to the same instance, this Url is unique to each
|
||||
/// instance by way of its instance input endpoint port.
|
||||
/// </summary>
|
||||
Uri CallControlCallbackUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The template for call notifications like call state change notifications.
|
||||
/// To ensure that all requests for a given call go to the same instance, this Url
|
||||
/// is unique to each instance by way of its instance input endpoint port.
|
||||
/// </summary>
|
||||
Uri NotificationCallbackUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Base url for this particular azure instance
|
||||
/// </summary>
|
||||
Uri AzureInstanceBaseUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// MicrosoftAppId generated at the time of registration of the bot
|
||||
/// </summary>
|
||||
string MicrosoftAppId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Settings for the bot media platform
|
||||
/// </summary>
|
||||
MediaPlatformSettings MediaPlatformSettings { get; }
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace FrontEnd.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that encapsulates the caller's (creator's) information. This is helpful to provide more context in log statements.
|
||||
/// </summary>
|
||||
public class CallerInfo
|
||||
{
|
||||
private static ConcurrentDictionary<int, string> toStringCache = new ConcurrentDictionary<int, string>();
|
||||
|
||||
/// <summary>
|
||||
/// The name of the method or property of the caller
|
||||
/// </summary>
|
||||
public string MemberName { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full path of the source file of the caller
|
||||
/// </summary>
|
||||
public string FilePath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The line number of the source file of the caller
|
||||
/// </summary>
|
||||
public int LineNumber { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the CallerInfo class
|
||||
/// </summary>
|
||||
public CallerInfo(
|
||||
[CallerMemberName] string memberName = "",
|
||||
[CallerFilePath] string filePath = "",
|
||||
[CallerLineNumber] int lineNumber = 0
|
||||
)
|
||||
{
|
||||
this.MemberName = memberName;
|
||||
this.FilePath = filePath;
|
||||
this.LineNumber = lineNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hashcode for this instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return MemberName.GetHashCode() ^ FilePath.GetHashCode() ^ LineNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String representation of the caller's info
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return toStringCache.GetOrAdd(this.GetHashCode(), hc => String.Format(
|
||||
"{0},{1}({2})",
|
||||
this.MemberName,
|
||||
Path.GetFileName(this.FilePath),
|
||||
this.LineNumber
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
|
||||
namespace FrontEnd.Logging
|
||||
{
|
||||
internal class CorrelationId
|
||||
{
|
||||
private class Holder : MarshalByRefObject
|
||||
{
|
||||
public string Id;
|
||||
}
|
||||
|
||||
internal const string LogicalDataName = "FrontEnd.Logging.CorrelationId";
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current correlation ID. This is necessary to call in event handler callbacks because the event producer
|
||||
/// may not be aware of the call id.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public static void SetCurrentId(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Holder holder = CallContext.LogicalGetData(LogicalDataName) as Holder;
|
||||
if (holder == null)
|
||||
{
|
||||
CallContext.LogicalSetData(LogicalDataName, new Holder { Id = value });
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
holder.Id = value;
|
||||
}
|
||||
catch (AppDomainUnloadedException)
|
||||
{
|
||||
CallContext.LogicalSetData(LogicalDataName, new Holder { Id = value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current correlation id.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetCurrentId()
|
||||
{
|
||||
Holder holder = CallContext.LogicalGetData(LogicalDataName) as Holder;
|
||||
if (holder != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return holder.Id;
|
||||
}
|
||||
catch (AppDomainUnloadedException)
|
||||
{
|
||||
CallContext.FreeNamedDataSlot(LogicalDataName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace FrontEnd.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Different contexts for which log statements are produced. Each of these contexts
|
||||
/// has a corresponding TraceSource entry in the WorkerRole's app.config file.
|
||||
/// </summary>
|
||||
public enum LogContext
|
||||
{
|
||||
AuthToken,
|
||||
FrontEnd,
|
||||
Media
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper class for logging. This class provides a common mechanism for logging throughout the application.
|
||||
/// </summary>
|
||||
public static class Log
|
||||
{
|
||||
private static readonly Dictionary<LogContext, TraceSource> traceSources = new Dictionary<LogContext, TraceSource>();
|
||||
|
||||
static Log()
|
||||
{
|
||||
foreach (LogContext context in Enum.GetValues(typeof(LogContext)))
|
||||
{
|
||||
traceSources[context] = new TraceSource(context.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if Verbose method is on
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsVerboseOn(LogContext context)
|
||||
{
|
||||
TraceSource traceSource = traceSources[context];
|
||||
return traceSource.Switch.Level >= SourceLevels.Verbose || traceSource.Switch.Level == SourceLevels.All;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verbose logging of the message
|
||||
/// </summary>
|
||||
/// <param name="callerInfo"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void Verbose(CallerInfo callerInfo, LogContext context, string format, params object[] args)
|
||||
{
|
||||
Log.Write(TraceEventType.Verbose, callerInfo, context, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Info level logging of the message
|
||||
/// </summary>
|
||||
/// <param name="callerInfo"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void Info(CallerInfo callerInfo, LogContext context, string format, params object[] args)
|
||||
{
|
||||
Log.Write(TraceEventType.Information, callerInfo, context, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warning level logging of the message
|
||||
/// </summary>
|
||||
/// <param name="callerInfo"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void Warning(CallerInfo callerInfo, LogContext context, string format, params object[] args)
|
||||
{
|
||||
Log.Write(TraceEventType.Warning, callerInfo, context, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Error level logging of the message
|
||||
/// </summary>
|
||||
/// <param name="callerInfo"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public static void Error(CallerInfo callerInfo, LogContext context, string format, params object[] args)
|
||||
{
|
||||
Log.Write(TraceEventType.Error, callerInfo, context, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the log trace sources
|
||||
/// </summary>
|
||||
public static void Flush()
|
||||
{
|
||||
foreach (TraceSource traceSource in traceSources.Values)
|
||||
{
|
||||
traceSource.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static void Write(TraceEventType level, CallerInfo callerInfo, LogContext context, string format, params object[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
string correlationId = CorrelationId.GetCurrentId() ?? "-";
|
||||
string callerInfoString = (callerInfo == null) ? "-" : callerInfo.ToString();
|
||||
string tracePrefix = "[" + correlationId + " " + callerInfoString + "] ";
|
||||
if (args.Length == 0)
|
||||
{
|
||||
traceSources[context].TraceEvent(level, 0, tracePrefix + format);
|
||||
}
|
||||
else
|
||||
{
|
||||
traceSources[context].TraceEvent(level, 0, string.Format(tracePrefix + format, args));
|
||||
}
|
||||
|
||||
}catch(Exception ex)
|
||||
{
|
||||
Trace.TraceError("Error in Log.cs" + ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
|
||||
namespace FrontEnd.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an Audio Buffer for Send and also implements Dispose
|
||||
/// </summary>
|
||||
class AudioSendBuffer : AudioMediaBuffer
|
||||
{
|
||||
private bool m_disposed;
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||
|
||||
public AudioSendBuffer(AudioMediaBuffer mediaBuffer, AudioFormat format, ulong timeStamp)
|
||||
{
|
||||
IntPtr unmanagedBuffer = Marshal.AllocHGlobal((int)mediaBuffer.Length);
|
||||
CopyMemory(unmanagedBuffer, mediaBuffer.Data, (uint)mediaBuffer.Length);
|
||||
|
||||
Data = unmanagedBuffer;
|
||||
Length = mediaBuffer.Length;
|
||||
AudioFormat = format;
|
||||
Timestamp = (long)timeStamp;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
Marshal.FreeHGlobal(Data);
|
||||
}
|
||||
|
||||
m_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
|
||||
namespace FrontEnd.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a Video Buffer for Send and also implements Dispose
|
||||
/// </summary>
|
||||
class VideoSendBuffer : VideoMediaBuffer
|
||||
{
|
||||
private bool m_disposed;
|
||||
|
||||
public VideoSendBuffer(byte[] buffer, uint length, VideoFormat format)
|
||||
{
|
||||
IntPtr ptrToBuffer = Marshal.AllocHGlobal(buffer.Length);
|
||||
Marshal.Copy(buffer, 0, ptrToBuffer, buffer.Length);
|
||||
|
||||
Data = ptrToBuffer;
|
||||
Length = length;
|
||||
VideoFormat = format;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
Marshal.FreeHGlobal(Data);
|
||||
Data = IntPtr.Zero;
|
||||
}
|
||||
|
||||
m_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("FrontEnd")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("FrontEnd")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,103 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using FrontEnd.Http;
|
||||
using Microsoft.Owin.Hosting;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
|
||||
namespace FrontEnd
|
||||
{
|
||||
/// <summary>
|
||||
/// Service is the main entry point independent of Azure. Anyone instantiating Service needs to first
|
||||
/// initialize the DependencyResolver. Calling Start() on the Service starts the HTTP server that will
|
||||
/// listen for incoming Conversation requests from the Skype Platform.
|
||||
/// </summary>
|
||||
public class Service
|
||||
{
|
||||
private readonly object _syncLock = new object();
|
||||
private bool _initialized;
|
||||
|
||||
private IDisposable _callHttpServer;
|
||||
private bool _started = false;
|
||||
public readonly string DefaultSendVideoFormat;
|
||||
|
||||
public IConfiguration Configuration { get; private set; }
|
||||
|
||||
public static readonly Service Instance = new Service();
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a custom server (e.g. for testing).
|
||||
/// </summary>
|
||||
/// <param name="listeningUris">HTTP urls to listen for incoming call signaling requests.</param>
|
||||
/// <param name="callProcessor">The call processor instance.</param>
|
||||
public void Initialize(IConfiguration config)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
throw new InvalidOperationException("Service is already initialized");
|
||||
}
|
||||
}
|
||||
|
||||
Configuration = config;
|
||||
|
||||
MediaPlatform.Initialize(config.MediaPlatformSettings);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the service.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
throw new InvalidOperationException("The service is already started.");
|
||||
}
|
||||
|
||||
// Start HTTP server for calls
|
||||
StartOptions callStartOptions = new StartOptions();
|
||||
foreach (Uri url in Configuration.CallControlListeningUrls)
|
||||
{
|
||||
callStartOptions.Urls.Add(url.ToString());
|
||||
}
|
||||
|
||||
this._callHttpServer = WebApp.Start(
|
||||
callStartOptions,
|
||||
(appBuilder) =>
|
||||
{
|
||||
var startup = new CallEndpointStartup();
|
||||
startup.Configuration(appBuilder);
|
||||
});
|
||||
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the service.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (!this._started)
|
||||
{
|
||||
throw new InvalidOperationException("The service is already stopped.");
|
||||
}
|
||||
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
this._callHttpServer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.40306.1554" newVersion="4.0.40306.1554" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.0.127" newVersion="1.0.0.127" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Protocol.Extensions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.40306.1554" newVersion="1.0.40306.1554" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.5.25.0" newVersion="4.5.25.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Applications.Telemetry.Server" publicKeyToken="ffe01d0f25e9b4f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.1.222.0" newVersion="1.1.222.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Applications.Telemetry" publicKeyToken="ffe01d0f25e9b4f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.1.222.0" newVersion="1.1.222.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bot.Builder.Calling" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bot.Builder" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.8.1.0" newVersion="3.8.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup></configuration>
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="3.5.2" targetFramework="net461" />
|
||||
<package id="Bond.Core.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Bond.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Bond.Runtime.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Chronic.Signed" version="0.3.2" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder" version="3.8.1.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder.Calling" version="3.0.4" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder.RealTimeMediaCalling" version="1.0.4-alpha" targetFramework="net461" />
|
||||
<package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.4.403061554" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net452" />
|
||||
<package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security.OpenIdConnect" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Rest.ClientRuntime" version="2.3.2" targetFramework="net461" />
|
||||
<package id="Microsoft.Skype.Bots.Media" version="1.5.0.1177-alpha" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Threading" version="14.1.131" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Validation" version="14.1.111" targetFramework="net461" />
|
||||
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="3.2.1" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net461" />
|
||||
<package id="Owin" version="1.0" targetFramework="net461" />
|
||||
<package id="System.Collections" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Collections.Concurrent" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Debug" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Tracing" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Dynamic.Runtime" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.IdentityModel.Tokens.Jwt" version="4.0.4.403061554" targetFramework="net461" />
|
||||
<package id="System.Linq" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Resources.ResourceManager" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Runtime" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Threading" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Dataflow" version="4.5.25" targetFramework="net461" />
|
||||
</packages>
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>2.9</ProductVersion>
|
||||
<ProjectGuid>CCD83013-9504-4716-ABFB-59881139A531</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MeetingScreenShotsBot</RootNamespace>
|
||||
<AssemblyName>MeetingScreenShotsBot</AssemblyName>
|
||||
<StartDevelopmentStorage>True</StartDevelopmentStorage>
|
||||
<Name>MeetingScreenShotsBot</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<!-- Items for the project -->
|
||||
<ItemGroup>
|
||||
<ServiceDefinition Include="ServiceDefinition.csdef" />
|
||||
<ServiceConfiguration Include="ServiceConfiguration.Local.cscfg" />
|
||||
<ServiceConfiguration Include="ServiceConfiguration.Cloud.cscfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="WorkerRole\WorkerRole.csproj">
|
||||
<Name>WorkerRole</Name>
|
||||
<Project>{DCB04B51-8726-4762-AE57-FACC1D112C99}</Project>
|
||||
<Private>True</Private>
|
||||
<RoleType>Worker</RoleType>
|
||||
<RoleName>WorkerRole</RoleName>
|
||||
<UpdateDiagnosticsConnectionStringOnPublish>True</UpdateDiagnosticsConnectionStringOnPublish>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Profiles" />
|
||||
<Folder Include="WorkerRoleContent\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<DiagnosticsConfiguration Include="WorkerRoleContent\diagnostics.wadcfgx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PublishProfile Include="Profiles\MeetingScreenShotsProduction.azurePubxml" />
|
||||
</ItemGroup>
|
||||
<!-- Import the target files for this project template -->
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition=" '$(VisualStudioVersion)' == '' ">10.0</VisualStudioVersion>
|
||||
<CloudExtensionsDir Condition=" '$(CloudExtensionsDir)' == '' ">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\2.9\</CloudExtensionsDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" />
|
||||
</Project>
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{CC5FD16D-436D-48AD-A40C-5A424C6E3E79}") = "MeetingScreenShotsBot", "MeetingScreenShotsBot.ccproj", "{CCD83013-9504-4716-ABFB-59881139A531}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB} = {E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerRole", "WorkerRole\WorkerRole.csproj", "{DCB04B51-8726-4762-AE57-FACC1D112C99}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontEnd", "FrontEnd\FrontEnd.csproj", "{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CCD83013-9504-4716-ABFB-59881139A531}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CCD83013-9504-4716-ABFB-59881139A531}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CCD83013-9504-4716-ABFB-59881139A531}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CCD83013-9504-4716-ABFB-59881139A531}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DCB04B51-8726-4762-AE57-FACC1D112C99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCB04B51-8726-4762-AE57-FACC1D112C99}.Debug|x64.Build.0 = Debug|x64
|
||||
{DCB04B51-8726-4762-AE57-FACC1D112C99}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCB04B51-8726-4762-AE57-FACC1D112C99}.Release|x64.Build.0 = Release|x64
|
||||
{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}.Debug|x64.Build.0 = Debug|x64
|
||||
{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}.Release|x64.ActiveCfg = Release|x64
|
||||
{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,62 +0,0 @@
|
|||
# MeetingScreenShots sample
|
||||
|
||||
MeetingScreenShots sample shows how to
|
||||
- integrate chat modality with audio-video modality.
|
||||
- subscribe to roster notifications in a conference.
|
||||
- subscribe to dominant speaker notifications in a conference through the Media Platform.
|
||||
- subscribe to a participant's video in the conference and get access to her/his "raw/unencoded" video.
|
||||
|
||||
## Description
|
||||
When MeetingScreenShots bot is added to a conference, it captures the video frame of the dominant speaker at periodic intervals and sends the link to query this frame to the conference. Participants can click on this link and enjoy looking at the expressions of the dominant speaker at different moments of the conference.
|
||||
|
||||
## Test the bot
|
||||
Create a conference/conversation group and add `MeetingScreenShots` bot to the conference. Start an audio-video call on the conference and send a chat message to the `MeetingScreenShots` bot by mentioning the bot with an @. For example, send `@MeetingScreenShots hi`. The bot will reply back with a `Click here for video shots from the conference` message that has a link to the video shots from the conference. The link will show periodic video shots captured from the dominant speaker in the conference. The video shots are sent directly by the bot and are not stored anywhere. The link is available only as long as the call is active.
|
||||
|
||||
## Deploy the bot sample
|
||||
Prerequisites and instructions for deploying are [here](https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-real-time-deploy-visual-studio). Before the sample can be deployed, its configuration needs to be updated.
|
||||
|
||||
### Update Config
|
||||
- In app.config of the WorkerRole, replace $BotHandle$, $MicrosoftAppId$ and $BotSecret$ with values obtained during bot registration.
|
||||
|
||||
```xml
|
||||
<appSettings>
|
||||
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password from your bot registration portal-->
|
||||
<add key="BotId" value="$BotHandle$" />
|
||||
<add key="MicrosoftAppId" value="$MicrosoftAppId$" />
|
||||
<add key="MicrosoftAppPassword" value="$BotSecret$" />
|
||||
</appSettings>
|
||||
```
|
||||
- Substitute the $xxx$ in service configuration (ServiceConfiguration.Cloud.cscfg file) with appropriate values in the config.
|
||||
```xml
|
||||
<Setting name="DefaultCertificate" value="$CertificateThumbprint$" />
|
||||
```
|
||||
|
||||
## How it works
|
||||
Instructions on how to build a bot can be found [here](https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-real-time-audio-video-call-overview).
|
||||
|
||||
As mentioned [here](https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-real-time-media-requirements), real-time media bots are different from chat bots as the real-time media bots are very stateful. The real-time media call is pinned to the virtual machine (VM) instance which accepted the incoming call and hence the subsequent requests for that call are sent to that VM using an `InstanceInputEnpoint`. A chat on the other hand could be handled by any instance in the deployment using constructs from the bot framework. So to integrate chat with the corresponding audio-video call, say make the audio-video call change state on receiving a chat message, the bot developer should route the chat message for that call to the appropriate instance handling the audio-video modality for the same call.
|
||||
|
||||
The Conversation.Id from the incoming Activity when a chat is received and the IncomingCall.ThreadId of RealTimeMediaIncomingCallEvent when an audio-video call is received could be used to link the chat with the corresponding audio-video call.
|
||||
|
||||
```cs
|
||||
[HttpPost]
|
||||
[Route(HttpRouteConstants.OnIncomingMessageRoute)]
|
||||
public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
|
||||
{
|
||||
ThreadId = activity.Conversation.Id; //use to link to the audio-video call
|
||||
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
|
||||
}
|
||||
|
||||
internal class RealTimeMediaCall : IRealTimeMediaCall
|
||||
{
|
||||
private Task OnIncomingCallReceived(RealTimeMediaIncomingCallEvent incomingCallEvent)
|
||||
{
|
||||
ThreadId = incomingCallEvent.IncomingCall.ThreadId; //use this to link to chat thread
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Things to know
|
||||
- A conversation group/conversation must be created with the bot before starting the audio-video call. Escalating to a conference from a 1:1 call with the bot is *not* supported.
|
||||
- This sample can be run only from a single instance deployment. It shows how to link the chat thread and audio-video call, but it does not demonstrate routing of chat messages to the instance that handles audio-video call.
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ServiceConfiguration serviceName="MeetingScreenShotsBot" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6">
|
||||
<Role name="WorkerRole">
|
||||
<Instances count="1" />
|
||||
<ConfigurationSettings>
|
||||
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=$storage$;AccountKey=$storageKey$" />
|
||||
<Setting name="ServiceDnsName" value="$ServiceDnsName$" /> <!-- xyz.cloudapp.net-->
|
||||
<Setting name="ServiceCNAME" value="" /> <!-- CNAME pointing to the .cloudapp.net if available.-->
|
||||
<Setting name="DefaultCertificate" value="$CertificateThumbprint$" />
|
||||
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled" value="true" />
|
||||
</ConfigurationSettings>
|
||||
<Certificates>
|
||||
<Certificate name="Default" thumbprint="$CertificateThumbprint$" thumbprintAlgorithm="sha1" />
|
||||
</Certificates>
|
||||
</Role>
|
||||
<NetworkConfiguration>
|
||||
<AddressAssignments>
|
||||
<InstanceAddress roleName="WorkerRole">
|
||||
<PublicIPs>
|
||||
<PublicIP name="instancePublicIP" domainNameLabel="pip" />
|
||||
</PublicIPs>
|
||||
</InstanceAddress>
|
||||
</AddressAssignments>
|
||||
</NetworkConfiguration>
|
||||
</ServiceConfiguration>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ServiceConfiguration serviceName="MeetingScreenShotsBot" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6">
|
||||
<Role name="WorkerRole">
|
||||
<Instances count="1" />
|
||||
<ConfigurationSettings>
|
||||
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=$storage$;AccountKey=$storageKey$" />
|
||||
<Setting name="ServiceDnsName" value="$ServiceDnsName$" /> <!-- xyz.cloudapp.net-->
|
||||
<Setting name="ServiceCNAME" value="" /> <!-- CNAME pointing to the .cloudapp.net if available.-->
|
||||
<Setting name="DefaultCertificate" value="$CertificateThumbprint$" />
|
||||
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled" value="true" />
|
||||
</ConfigurationSettings>
|
||||
<Certificates>
|
||||
<Certificate name="Default" thumbprint="$CertificateThumbprint$" thumbprintAlgorithm="sha1" />
|
||||
</Certificates>
|
||||
</Role>
|
||||
</ServiceConfiguration>
|
|
@ -1,62 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ServiceDefinition name="MeetingScreenShotsBot" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
|
||||
<WorkerRole name="WorkerRole" vmsize="Standard_D3_v2">
|
||||
<Runtime executionContext="elevated" />
|
||||
<Startup>
|
||||
<Task commandLine="SetupMediaFoundation.cmd" executionContext="elevated" taskType="simple"/>
|
||||
<Task commandLine="Startup.cmd > Startup.cmd.log" executionContext="elevated" taskType="simple">
|
||||
<Environment>
|
||||
<Variable name="PrivateDefaultCallControlPort">
|
||||
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name='DefaultEndpoint']/@port" />
|
||||
</Variable>
|
||||
<Variable name="PrivateInstanceCallControlPort">
|
||||
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name='InstanceCallControlEndpoint']/@port" />
|
||||
</Variable>
|
||||
<Variable name="InstanceIpAddress">
|
||||
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name='InstanceMediaControlEndpoint']/@address" />
|
||||
</Variable>
|
||||
<Variable name="DefaultCertificate">
|
||||
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[@name='DefaultCertificate']/@value" />
|
||||
</Variable>
|
||||
</Environment>
|
||||
</Task>
|
||||
<Task commandLine="InstallNETFX.cmd" executionContext="elevated" taskType="simple">
|
||||
<Environment>
|
||||
<Variable name="NetFxVersion" value="NDP461" />
|
||||
<Variable name="PathToNETFXInstall">
|
||||
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='NETFXInstall']/@path" />
|
||||
</Variable>
|
||||
</Environment>
|
||||
</Task>
|
||||
</Startup>
|
||||
<ConfigurationSettings>
|
||||
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
|
||||
<Setting name="ServiceDnsName" />
|
||||
<Setting name="ServiceCNAME" /> <!-- CNAME pointing to the .cloudapp.net if available-->
|
||||
<Setting name="DefaultCertificate" />
|
||||
</ConfigurationSettings>
|
||||
<Endpoints>
|
||||
<InputEndpoint name="DefaultEndpoint" protocol="tcp" port="443" localPort="9440" />
|
||||
<InstanceInputEndpoint name="InstanceCallControlEndpoint" protocol="tcp" localPort="10100">
|
||||
<AllocatePublicPortFrom>
|
||||
<FixedPortRange max="10199" min="10100" />
|
||||
</AllocatePublicPortFrom>
|
||||
</InstanceInputEndpoint>
|
||||
<InstanceInputEndpoint name="InstanceMediaControlEndpoint" protocol="tcp" localPort="8445">
|
||||
<AllocatePublicPortFrom>
|
||||
<FixedPortRange max="20199" min="20100" />
|
||||
</AllocatePublicPortFrom>
|
||||
</InstanceInputEndpoint>
|
||||
</Endpoints>
|
||||
<LocalResources>
|
||||
<LocalStorage name="NETFXInstall" sizeInMB="1024" cleanOnRoleRecycle="false" />
|
||||
</LocalResources>
|
||||
|
||||
<Certificates>
|
||||
<Certificate name="Default" storeLocation="LocalMachine" storeName="My" />
|
||||
</Certificates>
|
||||
<Imports>
|
||||
<Import moduleName="RemoteForwarder" />
|
||||
</Imports>
|
||||
</WorkerRole>
|
||||
</ServiceDefinition>
|
|
@ -1,331 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using FrontEnd;
|
||||
using FrontEnd.Http;
|
||||
using FrontEnd.Logging;
|
||||
using Microsoft.Azure;
|
||||
using Microsoft.Skype.Bots.Media;
|
||||
using Microsoft.WindowsAzure.ServiceRuntime;
|
||||
|
||||
namespace WorkerRole
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the configuration from service configuration
|
||||
/// </summary>
|
||||
internal class AzureConfiguration : IConfiguration
|
||||
{
|
||||
#region Fields
|
||||
private const string DefaultEndpointKey = "DefaultEndpoint";
|
||||
private const string InstanceCallControlEndpointKey = "InstanceCallControlEndpoint";
|
||||
private const string InstanceMediaControlEndpointKey = "InstanceMediaControlEndpoint";
|
||||
private const string ServiceDnsNameKey = "ServiceDnsName";
|
||||
private const string ServiceCNAMEKey = "ServiceCNAME";
|
||||
private const string DefaultCertificateKey = "DefaultCertificate";
|
||||
private const string MicrosoftAppIdKey = "MicrosoftAppId";
|
||||
private const string MicrosoftAppPasswordKey = "MicrosoftAppPassword";
|
||||
private const string DefaultMicrosoftAppIdValue = "$MicrosoftAppId$";
|
||||
private const string DefaultMicrosoftAppPasswordValue = "$BotSecret$";
|
||||
|
||||
//Prefix of the InstanceId from the RoleEnvironment
|
||||
private const string InstanceIdToken = "in_";
|
||||
|
||||
private static readonly AzureConfiguration s_Configuration = new AzureConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// DomainNameLabel in NetworkConfiguration in .cscfg <PublicIP name="instancePublicIP" domainNameLabel="pip"/>
|
||||
/// If the below changes, please change in the cscfg as well
|
||||
/// </summary>
|
||||
public const string DomainNameLabel = "pip";
|
||||
|
||||
/// <summary>
|
||||
/// localPort specified in <InputEndpoint name="DefaultCallControlEndpoint" protocol="tcp" port="443" localPort="9440" />
|
||||
/// in .csdef. This is needed for running in emulator. Currently only messaging can be debugged in the emulator.
|
||||
/// Media debugging in emulator will be supported in future releases.
|
||||
/// </summary>
|
||||
private const int DefaultPort = 9440;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public string ServiceDnsName { get; private set; }
|
||||
|
||||
public string ServiceCNAME { get; private set; }
|
||||
|
||||
public IEnumerable<Uri> CallControlListeningUrls { get; private set; }
|
||||
|
||||
public Uri CallControlCallbackUrl { get; private set; }
|
||||
|
||||
public Uri NotificationCallbackUrl { get; private set; }
|
||||
|
||||
public Uri AzureInstanceBaseUrl { get; private set; }
|
||||
|
||||
public MediaPlatformSettings MediaPlatformSettings { get; private set; }
|
||||
|
||||
public string MicrosoftAppId { get; private set; }
|
||||
|
||||
public static AzureConfiguration Instance { get { return s_Configuration; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
private AzureConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize from serviceConfig
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
// Collect config values from Azure config.
|
||||
TraceEndpointInfo();
|
||||
ServiceDnsName = GetString(ServiceDnsNameKey);
|
||||
ServiceCNAME = GetString(ServiceCNAMEKey, true);
|
||||
if (string.IsNullOrEmpty(ServiceCNAME))
|
||||
{
|
||||
ServiceCNAME = ServiceDnsName;
|
||||
}
|
||||
|
||||
X509Certificate2 defaultCertificate = GetCertificateFromStore(DefaultCertificateKey);
|
||||
|
||||
RoleInstanceEndpoint instanceCallControlEndpoint = RoleEnvironment.IsEmulated ? null : GetEndpoint(InstanceCallControlEndpointKey);
|
||||
RoleInstanceEndpoint defaultEndpoint = GetEndpoint(DefaultEndpointKey);
|
||||
RoleInstanceEndpoint mediaControlEndpoint = RoleEnvironment.IsEmulated ? null : GetEndpoint(InstanceMediaControlEndpointKey);
|
||||
|
||||
int instanceCallControlInternalPort = RoleEnvironment.IsEmulated ? DefaultPort : instanceCallControlEndpoint.IPEndpoint.Port;
|
||||
string instanceCallControlInternalIpAddress = RoleEnvironment.IsEmulated
|
||||
? IPAddress.Loopback.ToString()
|
||||
: instanceCallControlEndpoint.IPEndpoint.Address.ToString();
|
||||
|
||||
int instanceCallControlPublicPort = RoleEnvironment.IsEmulated ? DefaultPort : instanceCallControlEndpoint.PublicIPEndpoint.Port;
|
||||
int mediaInstanceInternalPort = RoleEnvironment.IsEmulated ? 8445 : mediaControlEndpoint.IPEndpoint.Port;
|
||||
int mediaInstancePublicPort = RoleEnvironment.IsEmulated ? 20100 : mediaControlEndpoint.PublicIPEndpoint.Port;
|
||||
|
||||
string instanceCallControlIpEndpoint = string.Format("{0}:{1}", instanceCallControlInternalIpAddress, instanceCallControlInternalPort);
|
||||
|
||||
MicrosoftAppId = ConfigurationManager.AppSettings[MicrosoftAppIdKey];
|
||||
if (string.IsNullOrEmpty(MicrosoftAppId) || string.Equals(MicrosoftAppId, DefaultMicrosoftAppIdValue))
|
||||
{
|
||||
throw new ConfigurationException("MicrosoftAppId", "Update app.config in WorkerRole with AppId from the bot registration portal");
|
||||
}
|
||||
|
||||
string microsoftAppPassword = ConfigurationManager.AppSettings[MicrosoftAppPasswordKey];
|
||||
if (string.IsNullOrEmpty(microsoftAppPassword) || string.Equals(microsoftAppPassword, DefaultMicrosoftAppPasswordValue))
|
||||
{
|
||||
throw new ConfigurationException("MicrosoftAppPassword", "Update app.config in WorkerRole with BotSecret from the bot registration portal");
|
||||
}
|
||||
|
||||
// Create structured config objects for service.
|
||||
CallControlCallbackUrl = new Uri(string.Format(
|
||||
"https://{0}:{1}/{2}/{3}/",
|
||||
ServiceCNAME,
|
||||
instanceCallControlPublicPort,
|
||||
HttpRouteConstants.CallSignalingRoutePrefix,
|
||||
HttpRouteConstants.OnCallbackRoute));
|
||||
|
||||
NotificationCallbackUrl = new Uri(string.Format(
|
||||
"https://{0}:{1}/{2}/{3}/",
|
||||
ServiceCNAME,
|
||||
instanceCallControlPublicPort,
|
||||
HttpRouteConstants.CallSignalingRoutePrefix,
|
||||
HttpRouteConstants.OnNotificationRoute));
|
||||
|
||||
AzureInstanceBaseUrl = new Uri(string.Format(
|
||||
"https://{0}:{1}/",
|
||||
ServiceCNAME,
|
||||
instanceCallControlPublicPort));
|
||||
|
||||
TraceConfigValue("CallControlCallbackUri", CallControlCallbackUrl);
|
||||
List<Uri> controlListenUris = new List<Uri>();
|
||||
|
||||
if (RoleEnvironment.IsEmulated)
|
||||
{
|
||||
controlListenUris.Add(new Uri("https://" + defaultEndpoint.IPEndpoint.Address + ":" + DefaultPort + "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
controlListenUris.Add(new Uri("https://" + instanceCallControlIpEndpoint + "/"));
|
||||
controlListenUris.Add(new Uri("https://" + defaultEndpoint.IPEndpoint + "/"));
|
||||
};
|
||||
CallControlListeningUrls = controlListenUris;
|
||||
|
||||
foreach (Uri uri in CallControlListeningUrls)
|
||||
{
|
||||
TraceConfigValue("Call control listening Uri", uri);
|
||||
}
|
||||
|
||||
IPAddress publicInstanceIpAddress = RoleEnvironment.IsEmulated
|
||||
? IPAddress.Loopback
|
||||
: GetInstancePublicIpAddress(ServiceDnsName);
|
||||
|
||||
MediaPlatformSettings = new MediaPlatformSettings()
|
||||
{
|
||||
MediaPlatformInstanceSettings = new MediaPlatformInstanceSettings()
|
||||
{
|
||||
CertificateThumbprint = defaultCertificate.Thumbprint,
|
||||
InstanceInternalPort = mediaInstanceInternalPort,
|
||||
InstancePublicIPAddress = publicInstanceIpAddress,
|
||||
InstancePublicPort = mediaInstancePublicPort,
|
||||
ServiceFqdn = ServiceCNAME
|
||||
},
|
||||
|
||||
ApplicationId = MicrosoftAppId
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the configuration
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Helper methods
|
||||
private static void TraceEndpointInfo()
|
||||
{
|
||||
string[] endpoints = RoleEnvironment.IsEmulated
|
||||
? new string[] { DefaultEndpointKey }
|
||||
: new string[] { DefaultEndpointKey, InstanceMediaControlEndpointKey };
|
||||
|
||||
foreach (string endpointName in endpoints)
|
||||
{
|
||||
RoleInstanceEndpoint endpoint = GetEndpoint(endpointName);
|
||||
StringBuilder info = new StringBuilder();
|
||||
info.AppendFormat("Internal=https://{0}, ", endpoint.IPEndpoint);
|
||||
string publicInfo = endpoint.PublicIPEndpoint == null ? "-" : endpoint.PublicIPEndpoint.Port.ToString();
|
||||
info.AppendFormat("PublicPort={0}", publicInfo);
|
||||
TraceConfigValue(endpointName, info);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TraceConfigValue(string key, object value)
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, $"{key} ->{value}");
|
||||
}
|
||||
|
||||
private static RoleInstanceEndpoint GetEndpoint(string name)
|
||||
{
|
||||
RoleInstanceEndpoint endpoint;
|
||||
if (!RoleEnvironment.CurrentRoleInstance.InstanceEndpoints.TryGetValue(name, out endpoint))
|
||||
{
|
||||
throw new ConfigurationException(name, "No endpoint with name '{0}' was found.", name);
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
private static string GetString(string key, bool allowEmpty = false)
|
||||
{
|
||||
string s = CloudConfigurationManager.GetSetting(key);
|
||||
|
||||
TraceConfigValue(key, s);
|
||||
|
||||
if (!allowEmpty && string.IsNullOrWhiteSpace(s))
|
||||
{
|
||||
throw new ConfigurationException(key, "The configuration value is null or empty.");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static List<string> GetStringList(string key)
|
||||
{
|
||||
return GetString(key).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
|
||||
private static X509Certificate2 GetCertificateFromStore(string key)
|
||||
{
|
||||
string thumbprint = GetString(key);
|
||||
|
||||
X509Certificate2 cert;
|
||||
|
||||
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
try
|
||||
{
|
||||
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: false);
|
||||
if (certs.Count != 1)
|
||||
{
|
||||
throw new ConfigurationException(key, "No certificate with thumbprint {0} was found in the machine store.", thumbprint);
|
||||
}
|
||||
|
||||
cert = certs[0];
|
||||
}
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the PIP for this instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static IPAddress GetInstancePublicIpAddress(string publicFqdn)
|
||||
{
|
||||
int instanceNumber;
|
||||
//get the instanceId for the current instance. It will be of the form XXMediaBotRole_IN_0. Look for IN_ and then extract the number after it
|
||||
//Assumption: in_<instanceNumber> will the be the last in the instanceId
|
||||
string instanceId = RoleEnvironment.CurrentRoleInstance.Id;
|
||||
int instanceIdIndex = instanceId.IndexOf(InstanceIdToken, StringComparison.OrdinalIgnoreCase);
|
||||
if (!Int32.TryParse(instanceId.Substring(instanceIdIndex + InstanceIdToken.Length), out instanceNumber))
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Couldn't extract Instance index from {0}", instanceId);
|
||||
throw new Exception("Couldn't extract Instance index from " + instanceId);
|
||||
}
|
||||
|
||||
//for example: instance0 for fooservice.cloudapp.net will have hostname as pip.0.fooservice.cloudapp.net
|
||||
string instanceHostName = DomainNameLabel + "." + instanceNumber + "." + publicFqdn;
|
||||
IPAddress[] instanceAddresses = Dns.GetHostEntry(instanceHostName).AddressList;
|
||||
if(instanceAddresses.Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Could not resolve the PIP hostname. Please make sure that PIP is properly configured for the service");
|
||||
}
|
||||
return instanceAddresses[0];
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when the configuration is not correct
|
||||
/// </summary>
|
||||
internal sealed class ConfigurationException : Exception
|
||||
{
|
||||
internal ConfigurationException(string parameter, string message, params object[] args)
|
||||
: base(string.Format(message, args))
|
||||
{
|
||||
Parameter = parameter;
|
||||
}
|
||||
|
||||
public string Parameter { get; private set; }
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format(
|
||||
"Parameter name: {0}\r\n{1}",
|
||||
Parameter,
|
||||
base.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Parameter name: {0}\r\n{1}", Parameter, base.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
Windows Registry Editor Version 5.00
|
||||
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification]
|
||||
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification]
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,*]
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,*]
|
|
@ -1,22 +0,0 @@
|
|||
# Error handling
|
||||
trap
|
||||
{
|
||||
Write-Output "Error Hit: $_"
|
||||
Write-Output "Error File: $($_.InvocationInfo.ScriptName)"
|
||||
Write-Output "Error Line #: $($_.InvocationInfo.ScriptLineNumber)"
|
||||
Write-Output ""
|
||||
Write-Output "Exception: $($_.Exception)"
|
||||
Write-Output ""
|
||||
Write-Output "Exception.InnerException: $($_.Exception.InnerException)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Output "Checking if Media Foundation is installed"
|
||||
if((Get-WindowsFeature Server-Media-Foundation).Installed -eq 0)
|
||||
{
|
||||
Write-Output "Installing Media Foundation."
|
||||
Add-WindowsFeature Server-Media-Foundation
|
||||
|
||||
Write-Output "Rebooting VM for changes to take effect."
|
||||
Restart-Computer
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
REM Code Courtesy https://azure.microsoft.com/en-us/documentation/articles/cloud-services-dotnet-install-dotnet/
|
||||
REM Set the value of netfx to install appropriate .NET Framework.
|
||||
REM ***** To install .NET 4.5.2 set the variable netfx to "NDP452" *****
|
||||
REM ***** To install .NET 4.6 set the variable netfx to "NDP46" *****
|
||||
REM ***** To install .NET 4.6.1 set the variable netfx to "NDP461" *****
|
||||
set netfx="%NetFxVersion%"
|
||||
|
||||
REM ***** Needed to correctly install .NET 4.6.1, otherwise you may see an out of disk space error *****
|
||||
set TMP=%PathToNETFXInstall%
|
||||
set TEMP=%PathToNETFXInstall%
|
||||
|
||||
REM ***** Setup .NET filenames and registry keys *****
|
||||
if %netfx%=="NDP461" goto NDP461
|
||||
if %netfx%=="NDP46" goto NDP46
|
||||
set netfxinstallfile="NDP452-KB2901954-Web.exe"
|
||||
set netfxregkey="0x5cbf5"
|
||||
goto logtimestamp
|
||||
|
||||
:NDP46
|
||||
set netfxinstallfile="NDP46-KB3045560-Web.exe"
|
||||
set netfxregkey="0x60051"
|
||||
goto logtimestamp
|
||||
|
||||
:NDP461
|
||||
set netfxinstallfile="NDP461-KB3102438-Web.exe"
|
||||
set netfxregkey="0x6041f"
|
||||
|
||||
:logtimestamp
|
||||
REM ***** Setup LogFile with timestamp *****
|
||||
set timehour=%time:~0,2%
|
||||
set timestamp=%date:~-4,4%%date:~-10,2%%date:~-7,2%-%timehour: =0%%time:~3,2%
|
||||
md "%PathToNETFXInstall%\log"
|
||||
set startuptasklog="%PathToNETFXInstall%log\startuptasklog-%timestamp%.txt"
|
||||
set netfxinstallerlog="%PathToNETFXInstall%log\NetFXInstallerLog-%timestamp%"
|
||||
|
||||
echo Logfile generated at: %startuptasklog% >> %startuptasklog%
|
||||
echo TMP set to: %TMP% >> %startuptasklog%
|
||||
echo TEMP set to: %TEMP% >> %startuptasklog%
|
||||
|
||||
REM ***** Check if .NET is installed *****
|
||||
echo Checking if .NET (%netfx%) is installed >> %startuptasklog%
|
||||
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release | Find %netfxregkey%
|
||||
if %ERRORLEVEL%== 0 goto end
|
||||
|
||||
REM ***** Installing .NET *****
|
||||
echo Installing .NET: start /wait %~dp0%netfxinstallfile% /q /serialdownload /log %netfxinstallerlog% >> %startuptasklog%
|
||||
start /wait %~dp0%netfxinstallfile% /q /serialdownload /log %netfxinstallerlog% >> %startuptasklog% 2>>&1
|
||||
|
||||
:end
|
||||
echo install.cmd completed: %date:~-4,4%%date:~-10,2%%date:~-7,2%-%timehour: =0%%time:~3,2% >> %startuptasklog%
|
Двоичный файл не отображается.
|
@ -1,42 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WorkerRole")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WorkerRole")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("DCB04B51-8726-4762-AE57-FACC1D112C99")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,3 +0,0 @@
|
|||
echo Launching Powershell to install Media Foundation
|
||||
PowerShell -ExecutionPolicy Unrestricted .\InstallMediaFoundation.ps1 >> InstallMediaFoundation.log 2>&1
|
||||
EXIT /B 0
|
|
@ -1,130 +0,0 @@
|
|||
/**************************************************
|
||||
* *
|
||||
* © Microsoft Corporation. All rights reserved. *
|
||||
* *
|
||||
**************************************************/
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FrontEnd.Logging;
|
||||
using FrontEnd;
|
||||
using Microsoft.WindowsAzure.ServiceRuntime;
|
||||
|
||||
namespace WorkerRole
|
||||
{
|
||||
public class WorkerRole : RoleEntryPoint
|
||||
{
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||
private readonly ManualResetEvent runCompleteEvent = new ManualResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// Keep the service running until OnStop is called
|
||||
/// </summary>
|
||||
public override void Run()
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, "WorkerRole is running");
|
||||
|
||||
try
|
||||
{
|
||||
this.RunAsync(this.cancellationTokenSource.Token).Wait();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.runCompleteEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize and start the service when workerrole is started
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool OnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Wire up exception handling for unhandled exceptions (bugs).
|
||||
AppDomain.CurrentDomain.UnhandledException += this.OnAppDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += this.OnUnobservedTaskException;
|
||||
|
||||
// Set the maximum number of concurrent connections
|
||||
ServicePointManager.DefaultConnectionLimit = 12;
|
||||
AzureConfiguration.Instance.Initialize();
|
||||
|
||||
// Create and start the environment-independent service.
|
||||
Service.Instance.Initialize(AzureConfiguration.Instance);
|
||||
Service.Instance.Start();
|
||||
|
||||
bool result = base.OnStart();
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, "WorkerRole has been started");
|
||||
|
||||
return result;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Exception on startup: {0}", e.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup when WorkerRole is stopped
|
||||
/// </summary>
|
||||
public override void OnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, "WorkerRole is stopping");
|
||||
|
||||
this.cancellationTokenSource.Cancel();
|
||||
this.runCompleteEvent.WaitOne();
|
||||
|
||||
base.OnStop();
|
||||
|
||||
Log.Info(new CallerInfo(), LogContext.FrontEnd, "WorkerRole has stopped");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Exception on shutdown: {0}", e.ToString());
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException -= this.OnAppDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException -= this.OnUnobservedTaskException;
|
||||
Log.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log UnObservedTaskExceptions
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||
{
|
||||
Log.Error(new CallerInfo(), LogContext.FrontEnd, "Unobserved task exception: " + e.Exception.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log any unhandled exceptions that are raised in the service
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Log.Error(new CallerInfo(), FrontEnd.Logging.LogContext.FrontEnd, "Unhandled exception: " + e.ExceptionObject.ToString());
|
||||
Log.Flush(); // process may or may not be terminating so flush log just in case.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,366 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props" Condition="Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{DCB04B51-8726-4762-AE57-FACC1D112C99}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>WorkerRole</RootNamespace>
|
||||
<AssemblyName>WorkerRole</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<RoleType>Worker</RoleType>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=3.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.Attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.Attributes.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.IO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Core.CSharp.4.2.1\lib\net45\Bond.IO.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Bond.JSON, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Bond.Runtime.CSharp.4.2.1\lib\net45\Bond.JSON.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Chronic, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3bd1f1ef638b0d3c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Builder.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.Autofac, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Builder.Autofac.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.Calling, Version=3.0.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.Calling.3.0.4\lib\net46\Microsoft.Bot.Builder.Calling.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.RealTimeMediaCalling, Version=1.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.RealTimeMediaCalling.1.0.4-alpha\lib\net46\Microsoft.Bot.Builder.RealTimeMediaCalling.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Connector, Version=3.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.8.1.0\lib\net46\Microsoft.Bot.Connector.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Edm, Version=5.6.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.OData, Version=5.6.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Services.Client, Version=5.6.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Protocol.Extensions, Version=1.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.4.403061554\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Hosting, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Rest.ClientRuntime.2.3.2\lib\net45\Microsoft.Rest.ClientRuntime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Skype.Bots.Media, Version=1.5.0.1177, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=AMD64">
|
||||
<HintPath>..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\lib\Microsoft.Skype.Bots.Media.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<SpecificVersion>True</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=2.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Storage, Version=4.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsAzure.Storage.4.3.0\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IdentityModel.Tokens.Jwt, Version=4.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IdentityModel.Tokens.Jwt.4.0.4.403061554\lib\net45\System.IdentityModel.Tokens.Jwt.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Spatial, Version=5.6.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Dataflow, Version=4.5.25.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Dataflow.4.5.25\lib\dotnet\System.Threading.Tasks.Dataflow.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.Owin, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AzureConfiguration.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="WorkerRole.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\InstallMPServiceImpCounters.ps1">
|
||||
<Link>skype_media_lib\InstallMPServiceImpCounters.ps1</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.ini">
|
||||
<Link>skype_media_lib\MediaPerf.ini</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPlatformStartupScript.bat">
|
||||
<Link>skype_media_lib\MediaPlatformStartupScript.bat</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default.tmx">
|
||||
<Link>skype_media_lib\TraceFormat\default.tmx</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default_media.tmx">
|
||||
<Link>skype_media_lib\TraceFormat\default_media.tmx</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="InstallMediaFoundation.ps1">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="InstallNETFX.cmd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="SetupMediaFoundation.cmd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="startup.cmd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\EtlReader.dll">
|
||||
<Link>skype_media_lib\EtlReader.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.dll">
|
||||
<Link>skype_media_lib\MediaPerf.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MediaPerf.h">
|
||||
<Link>skype_media_lib\MediaPerf.h</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Applications.Telemetry.dll">
|
||||
<Link>skype_media_lib\Microsoft.Applications.Telemetry.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Applications.Telemetry.Server.dll">
|
||||
<Link>skype_media_lib\Microsoft.Applications.Telemetry.Server.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Bond.dll">
|
||||
<Link>skype_media_lib\Microsoft.Bond.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Bond.Interfaces.dll">
|
||||
<Link>skype_media_lib\Microsoft.Bond.Interfaces.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.ClsContracts.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.ClsContracts.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.ClsLite.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.ClsLite.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.Internal.Media.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.Internal.Media.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Rtc.Internal.Media.MediaApi.dll">
|
||||
<Link>skype_media_lib\Microsoft.Rtc.Internal.Media.MediaApi.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Microsoft.Skype.ECS.Client.dll">
|
||||
<Link>skype_media_lib\Microsoft.Skype.ECS.Client.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPAzAppHost.dll">
|
||||
<Link>skype_media_lib\MPAzAppHost.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPServiceHostLib.dll">
|
||||
<Link>skype_media_lib\MPServiceHostLib.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\MPServiceImp.dll">
|
||||
<Link>skype_media_lib\MPServiceImp.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\rtmcodecs.dll">
|
||||
<Link>skype_media_lib\rtmcodecs.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\RtmMvrCs.dll">
|
||||
<Link>skype_media_lib\RtmMvrCs.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\rtmpal.dll">
|
||||
<Link>skype_media_lib\rtmpal.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Skype.ECS.Criteria.dll">
|
||||
<Link>skype_media_lib\Skype.ECS.Criteria.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\Skype.ECS.Utilities.dll">
|
||||
<Link>skype_media_lib\Skype.ECS.Utilities.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\SkypeRT.dll">
|
||||
<Link>skype_media_lib\SkypeRT.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\src\skype_media_lib\TraceFormat\default.xml">
|
||||
<Link>skype_media_lib\TraceFormat\default.xml</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="NDP461-KB3102438-Web.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FrontEnd\FrontEnd.csproj">
|
||||
<Project>{E0FC03A1-FD3C-43BD-BAA0-1AA418EC6DCB}</Project>
|
||||
<Name>FrontEnd</Name>
|
||||
<SpecificVersion>True</SpecificVersion>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<!-- Setting AutoUnifyAssemblyReferences to false will allow the ResolveAssemblyReferences task to
|
||||
create warnings when detecting version missmatches among references.
|
||||
-->
|
||||
<AutoUnifyAssemblyReferences>false</AutoUnifyAssemblyReferences>
|
||||
</PropertyGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets" Condition="Exists('..\packages\Bond.CSharp.4.2.1\build\Bond.CSharp.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets" Condition="Exists('..\packages\Microsoft.Skype.Bots.Media.1.5.0.1177-alpha\build\Microsoft.Skype.Bots.Media.targets')" />
|
||||
</Project>
|
|
@ -1,99 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<source name="FrontEnd" switchValue="Verbose">
|
||||
<listeners>
|
||||
<add name="AzureDiagnostics" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="Media" switchValue="Verbose">
|
||||
<listeners>
|
||||
<add name="AzureDiagnostics" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="AuthToken" switchValue="Verbose">
|
||||
<listeners>
|
||||
<add name="AzureDiagnostics" />
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
|
||||
<!--Add for botframework traces-->
|
||||
<sharedListeners>
|
||||
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
|
||||
<filter type="" />
|
||||
</add>
|
||||
</sharedListeners>
|
||||
|
||||
<switches>
|
||||
<add name="logLevel" value="4" />
|
||||
</switches>
|
||||
<trace autoflush="false" indentsize="4">
|
||||
<listeners>
|
||||
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
|
||||
</add>
|
||||
</listeners>
|
||||
</trace>
|
||||
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.40306.1554" newVersion="4.0.40306.1554" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.0.127" newVersion="1.0.0.127" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Protocol.Extensions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.40306.1554" newVersion="1.0.40306.1554" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Dataflow" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.5.25.0" newVersion="4.5.25.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Skype.ECS.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.131.0" newVersion="1.0.131.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Applications.Telemetry.Server" publicKeyToken="ffe01d0f25e9b4f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.1.222.0" newVersion="1.1.222.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Applications.Telemetry" publicKeyToken="ffe01d0f25e9b4f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.1.222.0" newVersion="1.1.222.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Rest.ClientRuntime" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bot.Builder.Calling" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bot.Builder" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.8.1.0" newVersion="3.8.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<appSettings>
|
||||
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password from your bot registration portal-->
|
||||
<add key="BotId" value="MeetingScreenShots" />
|
||||
<add key="MicrosoftAppId" value="51968134-4ab6-4ca0-b980-334a71b972aa" />
|
||||
<add key="MicrosoftAppPassword" value="Fxh4As31KWUV5kzbqQYbcmG" />
|
||||
</appSettings>
|
||||
</configuration>
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="3.5.2" targetFramework="net461" />
|
||||
<package id="Bond.Core.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Bond.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Bond.Runtime.CSharp" version="4.2.1" targetFramework="net461" />
|
||||
<package id="Chronic.Signed" version="0.3.2" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder" version="3.8.1.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder.Calling" version="3.0.4" targetFramework="net461" />
|
||||
<package id="Microsoft.Bot.Builder.RealTimeMediaCalling" version="1.0.4-alpha" targetFramework="net461" />
|
||||
<package id="Microsoft.Data.Edm" version="5.6.2" targetFramework="net452" />
|
||||
<package id="Microsoft.Data.OData" version="5.6.2" targetFramework="net452" />
|
||||
<package id="Microsoft.Data.Services.Client" version="5.6.2" targetFramework="net452" />
|
||||
<package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.4.403061554" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Owin.Security.OpenIdConnect" version="3.0.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Rest.ClientRuntime" version="2.3.2" targetFramework="net461" />
|
||||
<package id="Microsoft.Skype.Bots.Media" version="1.5.0.1177-alpha" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Threading" version="14.1.131" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Validation" version="14.1.111" targetFramework="net461" />
|
||||
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="3.2.1" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net461" />
|
||||
<package id="Owin" version="1.0" targetFramework="net461" />
|
||||
<package id="System.Collections" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Collections.Concurrent" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Debug" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Tracing" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Dynamic.Runtime" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.IdentityModel.Tokens.Jwt" version="4.0.4.403061554" targetFramework="net461" />
|
||||
<package id="System.Linq" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Resources.ResourceManager" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Runtime" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Spatial" version="5.6.2" targetFramework="net452" />
|
||||
<package id="System.Threading" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks" version="4.0.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Dataflow" version="4.5.25" targetFramework="net461" />
|
||||
<package id="WindowsAzure.Storage" version="4.3.0" targetFramework="net452" />
|
||||
</packages>
|
|
@ -1,23 +0,0 @@
|
|||
REM --- Move to this scripts location ---
|
||||
pushd "%~dp0"
|
||||
|
||||
REM --- Print out environment variables for debugging ---
|
||||
set
|
||||
|
||||
REM--- Register media perf dlls ---
|
||||
powershell .\skype_media_lib\MediaPlatformStartupScript.bat
|
||||
|
||||
REM --- Delete existing certificate bindings and URL ACL registrations ---
|
||||
netsh http delete sslcert ipport=%InstanceIpAddress%:%PrivateDefaultCallControlPort%
|
||||
netsh http delete sslcert ipport=%InstanceIpAddress%:%PrivateInstanceCallControlPort%
|
||||
netsh http delete urlacl url=https://%InstanceIpAddress%:%PrivateDefaultCallControlPort%/
|
||||
netsh http delete urlacl url=https://%InstanceIpAddress%:%PrivateInstanceCallControlPort%/
|
||||
|
||||
REM --- Delete new URL ACLs and certificate bindings ---
|
||||
netsh http add urlacl url=https://%InstanceIpAddress%:%PrivateDefaultCallControlPort%/ user="NT AUTHORITY\NETWORK SERVICE"
|
||||
netsh http add urlacl url=https://%InstanceIpAddress%:%PrivateInstanceCallControlPort%/ user="NT AUTHORITY\NETWORK SERVICE"
|
||||
netsh http add sslcert ipport=%InstanceIpAddress%:%PrivateDefaultCallControlPort% "appid={00000000-0000-0000-0000-000000000001}" cert=%DefaultCertificate%
|
||||
netsh http add sslcert ipport=%InstanceIpAddress%:%PrivateInstanceCallControlPort% "appid={00000000-0000-0000-0000-000000000001}" cert=%DefaultCertificate%
|
||||
|
||||
popd
|
||||
exit /b 0
|
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<DiagnosticsConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
|
||||
<PublicConfig xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
|
||||
<WadCfg>
|
||||
<DiagnosticMonitorConfiguration overallQuotaInMB="4096">
|
||||
<DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Verbose" />
|
||||
<Directories scheduledTransferPeriod="PT1M">
|
||||
<IISLogs containerName="wad-iis-logfiles" />
|
||||
<FailedRequestLogs containerName="wad-failedrequestlogs" />
|
||||
</Directories>
|
||||
<PerformanceCounters scheduledTransferPeriod="PT1M">
|
||||
<PerformanceCounterConfiguration counterSpecifier="\Memory\Available MBytes" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\ISAPI Extension Requests/sec" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\Bytes Total/Sec" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Requests/Sec" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Errors Total/Sec" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Queued" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Rejected" sampleRate="PT3M" />
|
||||
<PerformanceCounterConfiguration counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT3M" />
|
||||
</PerformanceCounters>
|
||||
<WindowsEventLog scheduledTransferPeriod="PT1M">
|
||||
<DataSource name="Application!*[System[(Level=1 or Level=2 or Level=3)]]" />
|
||||
<DataSource name="Windows Azure!*[System[(Level=1 or Level=2 or Level=3 or Level=4)]]" />
|
||||
</WindowsEventLog>
|
||||
<CrashDumps dumpType="Full">
|
||||
<CrashDumpConfiguration processName="WaAppAgent.exe" />
|
||||
<CrashDumpConfiguration processName="WaIISHost.exe" />
|
||||
<CrashDumpConfiguration processName="WindowsAzureGuestAgent.exe" />
|
||||
<CrashDumpConfiguration processName="WaWorkerHost.exe" />
|
||||
<CrashDumpConfiguration processName="DiagnosticsAgent.exe" />
|
||||
<CrashDumpConfiguration processName="w3wp.exe" />
|
||||
</CrashDumps>
|
||||
<Logs scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Verbose" />
|
||||
</DiagnosticMonitorConfiguration>
|
||||
</WadCfg>
|
||||
<StorageAccount />
|
||||
</PublicConfig>
|
||||
<PrivateConfig xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
|
||||
<StorageAccount endpoint="" />
|
||||
</PrivateConfig>
|
||||
<IsEnabled>true</IsEnabled>
|
||||
</DiagnosticsConfiguration>
|
Загрузка…
Ссылка в новой задаче