Not a member of Pastebin yet?
                        Sign Up,
                        it unlocks many cool features!                    
                - /// <summary>
 - /// It's controller that will serve as proxy for iOS video playback via Azure Media Services.
 - /// Such playback does not work out-f-the-box.
 - ///
 - /// In a nutshell, this "service" will change underlying playlist and substitute it modified version where
 - /// auth token is embedded into the URI, so that the iOS device can just query the URI w/o Auth header, as
 - /// auth token will the in query string and AMS can authorize the request.
 - ///
 - /// Here are the links that describes the problem and the solution.
 - /// https://azure.microsoft.com/en-us/blog/how-to-make-token-authorized-aes-encrypted-hls-stream-working-in-safari/
 - ///
 - /// The code is almost w/o changes taken from here.
 - /// https://github.com/AzureMediaServicesSamples/HLSSafariProxy/blob/master/HLSProxy/HLSManifestProxyDemo/Controllers/ManifestProxyController.cs
 - /// </summary>
 - [AllowAnonymous]
 - [RoutePrefix("AzureMediaServicesManifestProxy")]
 - public class AzureMediaServicesManifestProxyController : ApiController
 - {
 - private static LoggingService _log = LoggingService.GetCurrentClassInstance();
 - /// <summary>
 - /// GET /AzureMediaservicesManifestProxy/TopLevel(playbackUrl,token)
 - /// </summary>
 - [Route("TopLevel")]
 - public HttpResponseMessage GetTopLevelHslPlaylist(string playbackUrl, string token)
 - {
 - _log.Info($"TopLevel({playbackUrl}, {token})");
 - if (playbackUrl.ToLowerInvariant().EndsWith("manifest"))
 - {
 - playbackUrl += "(format=m3u8-aapl)";
 - }
 - string secondLevelProxyUrl = GetBaseUrl() + "/AzureMediaServicesManifestProxy/SecondLevel";
 - var modifiedTopLeveLManifest = GetTopLevelManifestForToken(playbackUrl, token, secondLevelProxyUrl);
 - var response = this.Request.CreateResponse();
 - response.Content = new StringContent(modifiedTopLeveLManifest, Encoding.UTF8, "application/vnd.apple.mpegurl");
 - response.Headers.Add("X-Content-Type-Options", "nosniff");
 - response.Headers.Add("Cache-Control", "max-age=259200");
 - //_log.Info($"TopLevelResult: {modifiedTopLeveLManifest}");
 - return response;
 - }
 - /// <summary>
 - /// GET /AzureMediaservicesManifestProxy/SecondLevel(playbackUrl,token)
 - /// </summary>
 - [Route("SecondLevel")]
 - public HttpResponseMessage GetSecondLevelHslPlaylist(string playbackUrl, string token)
 - {
 - _log.Info($"SecondLevel({playbackUrl}, {token})");
 - // get rid of "Bearer=" or "Bearer " prefixes
 - if (token.StartsWith("Bearer", StringComparison.OrdinalIgnoreCase))
 - {
 - token = token.Substring("Bearer".Length + 1).Trim();
 - }
 - string encodedToken = HttpUtility.UrlEncode(token);
 - const string qualityLevelRegex = @"(QualityLevels\(\d+\))";
 - const string fragmentsRegex = @"(Fragments\([\w\d=-]+,[\w\d=-]+\))";
 - const string urlRegex = @"("")(https?:\/\/[\da-z\.-]+\.[a-z\.]{2,6}[\/\w \.-]*\/?[\?&][^&=]+=[^&=#]*)("")";
 - string baseUrl = playbackUrl.Substring(0, playbackUrl.IndexOf(".ism", System.StringComparison.OrdinalIgnoreCase)) + ".ism";
 - string content = GetRawContent(playbackUrl);
 - string newContent = Regex.Replace(content, urlRegex, string.Format(CultureInfo.InvariantCulture, "$1$2&token={0}$3", encodedToken));
 - Match match = Regex.Match(playbackUrl, qualityLevelRegex);
 - if (match.Success)
 - {
 - var qualityLevel = match.Groups[0].Value;
 - newContent = Regex.Replace(newContent, fragmentsRegex, m => string.Format(CultureInfo.InvariantCulture, baseUrl + "/" + qualityLevel + "/" + m.Value));
 - }
 - HttpResponseMessage response = this.Request.CreateResponse();
 - response.Content = new StringContent(newContent, Encoding.UTF8, "application/vnd.apple.mpegurl");
 - //_log.Info($"SecondLevelResult: {newContent}");
 - return response;
 - }
 - #region Private methods
 - private string GetTopLevelManifestForToken(string topLeveLManifestUrl, string token, string secondLevelManifestProxyBaseUrl)
 - {
 - const string qualityLevelRegex = @"(QualityLevels\(\d+\)/Manifest\(.+\))";
 - string topLevelManifestContent = GetRawContent(topLeveLManifestUrl);
 - string topLevelManifestBaseUrl = topLeveLManifestUrl.Substring(0, topLeveLManifestUrl.IndexOf(".ism", System.StringComparison.OrdinalIgnoreCase)) + ".ism";
 - string urlEncodedTopLeveLManifestBaseUrl = HttpUtility.UrlEncode(topLevelManifestBaseUrl);
 - string urlEncodedToken = HttpUtility.UrlEncode(token);
 - MatchEvaluator encodingReplacer = (Match m) => $"{secondLevelManifestProxyBaseUrl}?playbackUrl={urlEncodedTopLeveLManifestBaseUrl}{HttpUtility.UrlEncode("/" + m.Value)}&token={urlEncodedToken}";
 - string newContent = Regex.Replace(topLevelManifestContent, qualityLevelRegex, encodingReplacer);
 - return newContent;
 - }
 - private string GetBaseUrl()
 - {
 - Uri requestUri = Request.RequestUri;
 - string baseUrl = Request.RequestUri.GetLeftPart(UriPartial.Authority);
 - return baseUrl;
 - }
 - private string GetRawContent(string uri)
 - {
 - var httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(uri));
 - httpRequest.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
 - httpRequest.Timeout = 30000;
 - using (WebResponse httpResponse = httpRequest.GetResponse())
 - using (Stream stream = httpResponse.GetResponseStream())
 - using (var reader = new StreamReader(stream))
 - {
 - return reader.ReadToEnd();
 - }
 - }
 
Advertisement
 
                    Add Comment                
                
                        Please, Sign In to add comment