public void ResponseData(DownloaderRequest pDownloaderRequest, DownloaderResponse pDownloaderResponse) { if (pDownloaderResponse != null && pDownloaderResponse.ResponseStream != null) { pDownloaderResponse.ResponseStream.Dispose(); } }
public void ResponseData(DownloaderRequest pDownloaderRequest, DownloaderResponse pDownloaderResponse) { System.Diagnostics.Debug.WriteLine("ResponseData"); // you can use the return data and store it in the disk. // Application might hold the instance of ResponseStream for a while and dispose it later, it is up to Application’s implementation. // Once app knows it doesn’t need the response stream any more, it can add below code to dispose the ResponseStream; if (pDownloaderResponse != null && pDownloaderResponse.ResponseStream != null) { System.Diagnostics.Debug.WriteLine("Response for url: " + pDownloaderResponse.Uri + " Content: " + pDownloaderResponse.ContentType.ToString() + " length: " + pDownloaderResponse.ContentLength.ToString()); // pDownloaderResponse.ResponseStream.Dispose(); //System.Diagnostics.Debug.WriteLine("Response for url: "); } }
/* // Not used public void CompleteTask( IAsyncOperation<DownloaderResponse> asyncInfo, AsyncStatus asyncStatus ) { System.Diagnostics.Debug.WriteLine("CompleteTask"); // System.Diagnostics.Debug.WriteLine("Request url completed "); } */ public IAsyncOperation<DownloaderResponse> RequestAsync(DownloaderRequest pDownloaderRequest) { // This is a basic implimentation. The downloader plugin has multiple functions. In high level it has two functions. // When you register for a downloader plugin all the out going http requests first send to the downloader plugin. // Downloader plugin can take two actions at that moment; response with data to the request or return a new URL or same URL. // When there is a data resposne, SDK uses this data and doesn't go to network. // If the downloader respsonse with null data and with a URL (optionally it can include http headers and cookies) SDK uses the URl and goes to network and tries to download the data by own. // At that moment there will be a responsedata and this will be send to plugin. Plugin can use the resposne data to store for future usage. // The below sample has the basics just show how the plugin interface works. // It simply gets the requests and return the excat URL back. When you get the request, you can download the data by yourself using any protocol or serve it from cache (disk/memory)including and send the data back. // The API also alows you send different data to different quality requests and signal that you changed the data. // DownloaderRequest Class AlternativeUris will identify which quality levels can be returned back to the request http://msdn.microsoft.com/en-us/library/jj822798(v=vs.90).aspx // DownloaderResponse Class Uri-when you modify the quality you need to signal it using the Uri. You can also bypass the BypassBandwidthMeasurement http://msdn.microsoft.com/en-us/library/jj822671(v=vs.90).aspx //System.Diagnostics.Debug.WriteLine("Smooth Streming Request Url: " + pDownloaderRequest.RequestUri.ToString()); System.Diagnostics.Debug.WriteLine("RequestAsync"); ManifestCache mc = this.Get(pDownloaderRequest.RequestUri); // Is Manifest request if ((mc != null)&&(mc.manifestBuffer!=null)&&(mc.manifestBuffer.Length>0)) { System.Diagnostics.Debug.WriteLine("Cache received manifest request for Url : " + pDownloaderRequest.RequestUri.ToString()); TaskCompletionSource <DownloaderResponse> respTmp = new TaskCompletionSource<DownloaderResponse>(); if (respTmp.TrySetResult(new DownloaderResponse(pDownloaderRequest.RequestUri, (new MemoryStream(mc.manifestBuffer)).AsInputStream(), (ulong)mc.manifestBuffer.Length, "text/xml", null, true)) == true) { Windows.Foundation.IAsyncOperation<DownloaderResponse> resp = respTmp.Task.AsAsyncOperation(); // resp.Completed = CompleteTask; System.Diagnostics.Debug.WriteLine("Manifest found in the cache, data: " + mc.manifestBuffer.Length.ToString() + " bytes for Url: " + pDownloaderRequest.RequestUri.ToString()); return resp; } System.Diagnostics.Debug.WriteLine("Manifest not found in the cache"); } else { // Is Chunk request string BaseUrl = ManifestCache.GetBaseUri(pDownloaderRequest.RequestUri.ToString()); mc = this.GetFromBaseUri(new Uri(BaseUrl)); if (mc !=null) { string type = string.Empty; ulong time = 0; if (GetTimeAndType(pDownloaderRequest.RequestUri, out type, out time)) { System.Diagnostics.Debug.WriteLine("Cache received Chunk Request for time: " + time.ToString() + " url: " + pDownloaderRequest.RequestUri.ToString()); ChunkCache cc = null; if(type.Equals(mc.VideoTemplateUrlType)) cc = mc.GetVideoChunkCache(time); else if (type.Equals(mc.AudioTemplateUrlType)) cc = mc.GetAudioChunkCache(time); if ((cc != null)&&(cc.GetLength()>0)) { TaskCompletionSource<DownloaderResponse> respTmp = new TaskCompletionSource<DownloaderResponse>(); System.Collections.Generic.Dictionary<string, string> d = new System.Collections.Generic.Dictionary<string, string>(); d.Add("Content-Type", "video/mp4"); d.Add("Content-Length", cc.GetLength().ToString()); if (respTmp.TrySetResult(new DownloaderResponse(pDownloaderRequest.RequestUri, (new MemoryStream(cc.chunkBuffer)).AsInputStream(), (ulong)cc.GetLength(), "video/mp4", d, true)) == true) { Windows.Foundation.IAsyncOperation<DownloaderResponse> respb = respTmp.Task.AsAsyncOperation(); // respb.Completed = CompleteTask; System.Diagnostics.Debug.WriteLine("Chunk found in the cache, data: " + cc.GetLength().ToString() + " bytes for Url: " + pDownloaderRequest.RequestUri.ToString()); return respb; } } else { byte[] buffer = null; if (type.Equals(mc.VideoTemplateUrlType)) buffer = diskCache.GetVideoChunkBuffer(mc.StoragePath,time); else if (type.Equals(mc.AudioTemplateUrlType)) buffer = diskCache.GetAudioChunkBuffer(mc.StoragePath, time); if((buffer!=null)&&(buffer.Length>0)) { TaskCompletionSource<DownloaderResponse> respTmp = new TaskCompletionSource<DownloaderResponse>(); System.Collections.Generic.Dictionary<string, string> d = new System.Collections.Generic.Dictionary<string, string>(); d.Add("Content-Type", "video/mp4"); d.Add("Content-Length", cc.GetLength().ToString()); if (respTmp.TrySetResult(new DownloaderResponse(pDownloaderRequest.RequestUri, (new MemoryStream(buffer)).AsInputStream(), (ulong)buffer.Length, "video/mp4", d, true)) == true) { Windows.Foundation.IAsyncOperation<DownloaderResponse> respb = respTmp.Task.AsAsyncOperation(); // respb.Completed = CompleteTask; System.Diagnostics.Debug.WriteLine("Chunk found in the cache, data: " + buffer.Length.ToString() + " bytes for Url: " + pDownloaderRequest.RequestUri.ToString()); return respb; } } } } System.Diagnostics.Debug.WriteLine("Chunk not found in the cache"); } } System.Diagnostics.Debug.WriteLine("Default behavior (no cache) for url: " + pDownloaderRequest.RequestUri.ToString()); TaskCompletionSource<DownloaderResponse> respTmpb = new TaskCompletionSource<DownloaderResponse>(); DownloaderResponse dr = new DownloaderResponse(pDownloaderRequest.RequestUri, null, null); respTmpb.TrySetResult(dr); Windows.Foundation.IAsyncOperation<DownloaderResponse> respc = respTmpb.Task.AsAsyncOperation(); // respc.Completed = CompleteTask; return respc; }
public void ResponseData(DownloaderRequest pDownloaderRequest, DownloaderResponse pDownloaderResponse) { // nothing to save here }
public async Task<DownloaderResponse> RequestAsyncHelper(DownloaderRequest pDownloaderRequest) { DownloaderResponse response; /* * The first call that the player makes is to request the manifest for the video to play. * The response of this call is an xml with information about the video. * Encrypted videos have an extra element called <Protection> that contains decryption information such as the initialization vector (IV). * This <Protection> element currently not recognized by the player framework and will generate a parse error if it is returned, * so in this prototype, the <Protection> element is deleted. * In a full implementation, the <Protection> element would be read to get the IV. For the prototype, the IV is hardcoded, and the decryption key * is loaded from a hardcoded unsecured URL. */ if (pDownloaderRequest.RequestUri.AbsolutePath.IndexOf("manifest", StringComparison.OrdinalIgnoreCase) >= 0) { WebRequest manifestRequest = WebRequest.Create(pDownloaderRequest.RequestUri); using (WebResponse webResponseManifest = await manifestRequest.GetResponseAsync()) { var responseStream = webResponseManifest.GetResponseStream(); XDocument xmlDocument = XDocument.Load(responseStream); var protectionElement = (from xmlElement in xmlDocument.Descendants("Protection") select xmlElement).FirstOrDefault(); if (protectionElement != null) { XNamespace sea = "urn:mpeg:dash:schema:sea:2012"; //XNamespace sea = "urn:microsoft:azure:mediaservices:contentkeyidentifier"; var cryptoPeriodElement = (from xmlElement in protectionElement.Descendants(sea + "CryptoPeriod") select xmlElement).FirstOrDefault(); if (cryptoPeriodElement != null) { var ivAtrribute = cryptoPeriodElement.Attribute("IV"); var keyUriTemplateAttribute = cryptoPeriodElement.Attribute("keyUriTemplate"); var location = keyUriTemplateAttribute.Value.IndexOf("kid="); var keyGuid = keyUriTemplateAttribute.Value.Substring(location + 4); if (key.Length == 0) { key = await KeyLoader.LoadKey(new Uri(keyUriTemplateAttribute.Value),keyGuid); iv = StringToByteArray(ivAtrribute.Value.Substring(2)); } } protectionElement.Remove(); } Stream output = new MemoryStream(); xmlDocument.Save(output); output.Position = 0; // Return an input stream of the modified xml. return new DownloaderResponse(pDownloaderRequest.RequestUri, output.AsInputStream(), (ulong)output.Length, webResponseManifest.ContentType, null, false); } } if (key.Length == 0) { // load the key from the known URL and parse the known IV from a string. This will eventually be taken from the manifest file instead. //key = await LoadKey(); //iv = StringToByteArray("123456789abcdef0123456789abcdef0"); // IV } /* * A workaround is currently needed to truncate the encrypted stream to the length of the unecrypted stream. * For some reason, the encrypted stream has 1-6 extra bytes on each response that corrupt the ability to play the video. * Truncating the encrypted stream to the length of the clear stream resolves this problem, but it requires an extra server call. */ //Uri clearUri = new Uri(pDownloaderRequest.RequestUri.AbsoluteUri.Replace("encrypted", "clear") + "?test=test"); WebRequest request = WebRequest.Create(pDownloaderRequest.RequestUri); //WebRequest requestClear = WebRequest.Create(clearUri); using (WebResponse webResponse = await request.GetResponseAsync()) //using (WebResponse webResponseClear = await requestClear.GetResponseAsync()) { var responseStream = webResponse.GetResponseStream(); /* * Read the encrypted response into a byte array for decrption */ byte[] responseBytes = ReadToEnd(responseStream); /* * Perform the decryption */ byte[] decryptedBytes; this.Decrypt(responseBytes, out decryptedBytes); /* * Write out the decrypted bytes to a MemoryStream so it can be returned as a DownloaderResponse. * Note, the constructor MemoryStream(byte[] bytes) cannot be used here since that prevents the GetBuffer method from being usable. * The player framework uses GetBuffer to read from the input stream. */ MemoryStream ms = new MemoryStream(); ms.Write(decryptedBytes, 0, (int)decryptedBytes.Length); ms.Position = 0; response = new DownloaderResponse(pDownloaderRequest.RequestUri, ms.AsInputStream(), (ulong) ms.Length, webResponse.ContentType, null, false); } return response; }
public void ResponseData(DownloaderRequest pDownloaderRequest, DownloaderResponse pDownloaderResponse) { downloaderPluginBase.ResponseData(pDownloaderRequest, pDownloaderResponse); }
public void ResponseData(DownloaderRequest pDownloaderRequest, DownloaderResponse pDownloaderResponse) { // Nothind to do here }
public async Task <DownloaderResponse> RequestAsyncHelper(DownloaderRequest pDownloaderRequest) { DownloaderResponse response; /* * The first call that the player makes is to request the manifest for the video to play. * The response of this call is an xml with information about the video. * Encrypted videos have an extra element called <Protection> that contains decryption information such as the initialization vector (IV). * This <Protection> element currently not recognized by the player framework and will generate a parse error if it is returned, * so in this prototype, the <Protection> element is deleted. * In a full implementation, the <Protection> element would be read to get the IV. For the prototype, the IV is hardcoded, and the decryption key * is loaded from a hardcoded unsecured URL. */ if (pDownloaderRequest.RequestUri.AbsolutePath.IndexOf("manifest", StringComparison.OrdinalIgnoreCase) >= 0) { WebRequest manifestRequest = WebRequest.Create(pDownloaderRequest.RequestUri); using (WebResponse webResponseManifest = await manifestRequest.GetResponseAsync()) { var responseStream = webResponseManifest.GetResponseStream(); XDocument xmlDocument = XDocument.Load(responseStream); var protectionElement = (from xmlElement in xmlDocument.Descendants("Protection") select xmlElement).FirstOrDefault(); if (protectionElement != null) { XNamespace sea = "urn:mpeg:dash:schema:sea:2012"; //XNamespace sea = "urn:microsoft:azure:mediaservices:contentkeyidentifier"; var cryptoPeriodElement = (from xmlElement in protectionElement.Descendants(sea + "CryptoPeriod") select xmlElement).FirstOrDefault(); if (cryptoPeriodElement != null) { var ivAtrribute = cryptoPeriodElement.Attribute("IV"); var keyUriTemplateAttribute = cryptoPeriodElement.Attribute("keyUriTemplate"); var location = keyUriTemplateAttribute.Value.IndexOf("kid="); var keyGuid = keyUriTemplateAttribute.Value.Substring(location + 4); if (key.Length == 0) { key = await KeyLoader.LoadKey(new Uri(keyUriTemplateAttribute.Value), keyGuid); iv = StringToByteArray(ivAtrribute.Value.Substring(2)); } } protectionElement.Remove(); } Stream output = new MemoryStream(); xmlDocument.Save(output); output.Position = 0; // Return an input stream of the modified xml. return(new DownloaderResponse(pDownloaderRequest.RequestUri, output.AsInputStream(), (ulong)output.Length, webResponseManifest.ContentType, null, false)); } } if (key.Length == 0) { // load the key from the known URL and parse the known IV from a string. This will eventually be taken from the manifest file instead. //key = await LoadKey(); //iv = StringToByteArray("123456789abcdef0123456789abcdef0"); // IV } /* * A workaround is currently needed to truncate the encrypted stream to the length of the unecrypted stream. * For some reason, the encrypted stream has 1-6 extra bytes on each response that corrupt the ability to play the video. * Truncating the encrypted stream to the length of the clear stream resolves this problem, but it requires an extra server call. */ //Uri clearUri = new Uri(pDownloaderRequest.RequestUri.AbsoluteUri.Replace("encrypted", "clear") + "?test=test"); WebRequest request = WebRequest.Create(pDownloaderRequest.RequestUri); //WebRequest requestClear = WebRequest.Create(clearUri); using (WebResponse webResponse = await request.GetResponseAsync()) //using (WebResponse webResponseClear = await requestClear.GetResponseAsync()) { var responseStream = webResponse.GetResponseStream(); /* * Read the encrypted response into a byte array for decrption */ byte[] responseBytes = ReadToEnd(responseStream); /* * Perform the decryption */ byte[] decryptedBytes; this.Decrypt(responseBytes, out decryptedBytes); /* * Write out the decrypted bytes to a MemoryStream so it can be returned as a DownloaderResponse. * Note, the constructor MemoryStream(byte[] bytes) cannot be used here since that prevents the GetBuffer method from being usable. * The player framework uses GetBuffer to read from the input stream. */ MemoryStream ms = new MemoryStream(); ms.Write(decryptedBytes, 0, (int)decryptedBytes.Length); ms.Position = 0; response = new DownloaderResponse(pDownloaderRequest.RequestUri, ms.AsInputStream(), (ulong)ms.Length, webResponse.ContentType, null, false); } return(response); }