以前在 WP8.1 / UAP 時候如果要支援 Http Live Streaming (HLS) and Dynamic Adaptive Streaming over HTTP (DASH),需要藉由第三方元件:Windows Phone Streaming Media 的協助。但是到了 UWP 開始 SDK 中的 AdaptiveMediaSource 已經支援了這些内容的處理。該篇文章將加以説明以及如何使用。
〉Windows.Media.Streaming.Adaptive namespace:
該 namespace 定義支援多種不同的 adaptive streaming protocols,例如:Http Live Streaming (HLS) 或是 Dynamic Adaptive Streaming over HTTP (DASH)。重要的類別與列舉如下:
Type | Name | Description |
---|---|---|
Classes | AdaptiveMediaSource | Represents the source of adaptive streaming content. |
AdaptiveMediaSourceCreationResult | Represents the result of the creation of a AdaptiveMediaSource object. | |
AdaptiveMediaSourceDownloadBitrateChangedEventArgs | Provides data for the DownloadBitrateChanged event. | |
AdaptiveMediaSourceDownloadCompletedEventArgs | Provides data for the DownloadCompleted event. | |
AdaptiveMediaSourceDownloadFailedEventArgs | Provides data for the DownloadFailed event. | |
AdaptiveMediaSourceDownloadRequestedDeferral | Represents a deferral that can be used to defer the completion of the DownloadRequested event so that the app can asynchronously download media content. | |
AdaptiveMediaSourceDownloadRequestedEventArgs | Provides data for the DownloadRequested event. | |
AdaptiveMediaSourceDownloadResult | Represents the results of a resource download operation. | |
AdaptiveMediaSourcePlaybackBitrateChangedEventArgs | Provides data for the PlaybackBitrateChanged event. |
Type | Name | Description | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Enumerations | AdaptiveMediaSourceCreationStatus | Specifies the result of an attempt to create a AdaptiveMediaSource object. | ||||||||||||||||||||||||
| ||||||||||||||||||||||||||
AdaptiveMediaSourceResourceType | Specifies the type of an adaptive media resource. | |||||||||||||||||||||||||
|
上表簡單從 MSDN 上的説明截取下來,接著往下説明如何使用這些元素。
〉AdaptiveMediaSource:
代表顯示 adaptive streaming content 的 source 類別。針對 http live streaming 或是其他 content 的操作都是透過該類別。
可藉由提供的 event 與 properties 得到操作,主要説明如下:
Event | Description |
DownloadBitrateChanged | Occurs when the CurrentDownloadBitrate changes. 這個可用於處理當下載的 bitrate 低到某個程度時可以提示用戶網路相關問題。 |
DownloadCompleted | Occurs when a resource download operation completes. |
DownloadFailed | Occurs when a resource download operation fails. |
DownloadRequested | Occurs when a resource download operation is requested. |
PlaybackBitrateChanged | Occurs when the CurrentPlaybackBitrate changes. 這個 event 相關于目前播放的 bitrate 是否有改變。 |
Method | Description |
CreateFromStreamAsync(IInputStream,Uri,String) | Asynchronously creates a AdaptiveMediaSource object from the provided input stream. 第三個參數爲 content-type,同 MIME content type,可能的值爲 Http Live Streaming (HLS) or a Dynamic Adaptive Streaming over HTTP (DASH) content type. |
CreateFromStreamAsync(IInputStream,Uri,String,HttpClient) | Asynchronously creates a AdaptiveMediaSource object from the provided input stream. 參數多給了 HttpClient,代表該 Uri 需要下載 resource,并且可以設定相關的 Http header 或是其他參數。 |
CreateFromUriAsync(Uri) | Asynchronously creates a AdaptiveMediaSource object from the Uniform Resource Identifier (URI) of the source. |
CreateFromUriAsync(Uri,HttpClient) | Asynchronously creates a AdaptiveMediaSource object from the Uniform Resource Identifier (URI) of the source. 參數多給了 HttpClient,代表該 Uri 需要下載 resource,并且可以設定相關的 Http header 或是其他參數。 |
IsContentTypeSupported | Determines whether the content type of the source is supported. |
Property | Access type | Description |
AudioOnlyPlayback | Read-only | Gets a value indicating if the content streamed by the media source contains only audio. |
AvailableBitrates | Read-only | Gets the available adaptive bit rates of the adaptive streaming manifest that is the source of the adaptive streaming object. |
CurrentDownloadBitrate | Read-only | Gets a value indicating the current download bitrate for the media source. |
CurrentPlaybackBitrate | Read-only | Gets a value indicating the current playback bitrate for the media source. |
DesiredLiveOffset | Read/write | Gets or sets the desired starting offset for the live playback of the media source. |
DesiredMaxBitrate | Read/write | Gets or sets the desired maximum bitrate for the media source. |
DesiredMinBitrate | Read/write | Gets or sets the desired minimum bitrate for the media source. |
InboundBitsPerSecond | Read-only | Gets a value indicating the inbound bits per second statistic over the time window specified by the InboundBitsPerSecondWindow property. |
InboundBitsPerSecondWindow | Read/write | Gets or sets the time span over which the InboundBitsPerSecond property is calculated. |
InitialBitrate | Read/write | Gets and sets the initial bit rate to use for playback of the media source. |
IsLive | Read-only | Gets a value that indicates whether the media source is live. |
〉AdaptiveMediaSourceCreationResult:
代表由 AdaptiveMediaSource 利用 CreateFromUriAsyc 或是 CreateFromStreamAsync 的建立結果。
主要藉由 AdaptiveMediaSourceCreationStatus 判斷是否建立 MediaSource 成功。另外,HttpResponseMessage 得知使用過的 URI 是否請求成功。如果成功的話就會拿到一個可播放的 AdptiveMediaSource。
Property | Access type | Description |
HttpResponseMessage | Read-only | Gets the HTTP response message, if any, returned from an attempt to create a AdaptiveMediaSource object. |
MediaSource | Read-only | Gets the AdaptiveMediaSource object that represents the source of adaptive streaming content. |
Status | Read-only | Gets the status of an attempt to create a AdaptiveMediaSource object. |
〉AdaptiveMediaSourceDownloadResult:
作用在注冊 DownloadRequested event
Property | Access type | Description |
Buffer | Read/write | Gets or sets a buffer containing the downloaded resource. |
ContentType | Read/write | Gets or sets a string that identifies the MIME content type of the downloaded resource. |
ExtendedStatus | Read/write | Gets or sets an integer value that represents extended status information about the resource download operation. |
InputStream | Read/write | Gets or sets an input stream containing the downloaded resource. |
ResourceUri | Read/write | Gets or sets the Uniform Resource Identifier (URI) of the downloaded resource. |
上述的説明加以整理一下,歸納幾個重點:
1. 利用 AdativeMediaSource 將要使用的 Uri 或是 InputStream 建立成 MediaSource。
2. 搭配 AdativeMediaSourceCreationResult 判斷是否建立成功。
3. 如果在建立 AdativeMediaSource 時希望一并下載内容的話,需要給一個 HttpClient 才會觸發 Download 的相關事件。
【範例】
我以 hichannel 提供的 m3u8 綫上廣播爲 live stream source 當作範例來加以説明。
詳細的 code 在<https://github.com/poumason/DotblogsSampleCode>。
1. 取得想要聽的 hichannel,得到 HSL 的網址:
1: private async Task<Uri> GetHitChannelHSL(String url, String tag)
2: {
3: Uri resultUri = null;
4: try
5: {
6: HttpWebRequest request = HttpWebRequest.CreateHttp(url);
7: request.CookieContainer = new CookieContainer();
8: request.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
9: request.AllowReadStreamBuffering = true;
10:
11: var resposne = await request.GetResponseAsync();
12:
13: using (StreamReader stream = new StreamReader(resposne.GetResponseStream()))
14: {
15: while (stream.Peek() >= 0)
16: {
17: String strLine = stream.ReadLine();
18: Debug.WriteLine(strLine);
19: if (strLine.Contains(tag))
20: {
21: String[] para = strLine.Split('\'');
22: String urlStr = para[1].Replace("\\", "");
23: resultUri = new Uri(urlStr);
24: break;
25: }
26: }
27: }
28: }
29: catch (Exception)
30: {
31: throw;
32: }
33: return resultUri;
34: }
2. 使用 AdativeMediaSource.CreateFromUriAsyc 取得 MediaSource,并且指定給 MediaElement 進行播放:
1: private AdaptiveMediaSource _source;
2:
3: private async void OnPlayClick(object sender, RoutedEventArgs e)
4: {
5: String url = txtURL.Text;
6: String tag = "ra000001";
7: // get m3u8 URL
8: Uri hsl = await GetHitChannelHSL(url, tag);
9:
10: if (hsl != null)
11: {
12: // request create AdaptiveMediaSource from Uri
13: AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(hsl);
14: if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
15: {
16: _source = result.MediaSource;
17: _source.DownloadRequested += _source_DownloadRequested;
18: _source.DownloadCompleted += _source_DownloadCompleted;
19: _source.DownloadFailed += _source_DownloadFailed;
20: _source.DownloadBitrateChanged += _source_DownloadBitrateChanged;
21: _source.PlaybackBitrateChanged += _source_PlaybackBitrateChanged;
22:
23: // set MediaSource to MediaElement
24: mediaPlayer.SetMediaStreamSource(result.MediaSource);
25: }
26: }
27: }
3. 加入提供給 Phone 版可以使用 BackgroundTask 來播放 Background Audio 的機制:
3-1. 先調整取得 m3u8 之後轉交給 BackgroundMediaPlayer:
1: private async void OnPlayClick(object sender, RoutedEventArgs e)
2: {
3: String url = txtURL.Text;
4: String tag = "ra000001";
5: Uri hsl = await GetHitChannelHSL(url, tag);
6: if (hsl != null)
7: {
8: // check is phone
9: ValueSet msg = new ValueSet();
10: msg.Add("Play", hsl.OriginalString);
11: BackgroundMediaPlayer.SendMessageToBackground(msg);
12: }
13: }
3-2. 建立一個 Windows Runtime Component 的 BackgroundTask,專門處理來自 MessageReceivedFromForeground 訊息:
1: async void BackgroundMediaPlayer_MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e)
2: {
3: foreach (string key in e.Data.Keys)
4: {
5: switch (key.ToLower())
6: {
7: case "play":
8: String url =e.Data[key].ToString();
9: await PlayHLS(new Uri(url, UriKind.RelativeOrAbsolute));
10: break;
11: case "stop":
12: BackgroundMediaPlayer.Current.Pause();
13: break;
14: case "wakup_background_player":
15: break;
16: default:
17: break;
18: }
19: }
20: }
21:
22: private async Task PlayHLS(Uri hsl)
23: {
24: AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(hsl);
25: if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
26: {
27: _source = result.MediaSource;
28: _source.DownloadRequested += _source_DownloadRequested;
29: _source.DownloadCompleted += _source_DownloadCompleted;
30: _source.DownloadFailed += _source_DownloadFailed;
31: _source.DownloadBitrateChanged += _source_DownloadBitrateChanged;
32: _source.PlaybackBitrateChanged += _source_PlaybackBitrateChanged;
33:
34: BackgroundMediaPlayer.Current.SetMediaSource(result.MediaSource);
35: }
36: }
[補充]
1. 常見的直播串流格式:
- Http live streaming (HLS)
- Smooth steaming
- MPEG-DASH
看完該篇文章的介紹你會發現 UWP 要整合 HLS 或是其他 live streaming 變得容易許多。
另外,微軟本身還有提供 Smooth Streaming 的機制,在 Azure 上也有提供 Smooth Streaming 的串流機制,
有興趣可以參考<Smooth Streaming Technical Overview>的説明。
References:
〉Windows.Media.Streaming.Adaptive namespace
〉A Windows 8 Smooth Streaming Media Player with Stream Selection
〉How to Build a Smooth Streaming Windows Store Application
〉Smooth Streaming Technical Overview
〉AdaptiveSourceManager Class
〉Microsoft Universal Smooth Streaming Client SDK
〉A Simple Windows 8 Smooth Streaming Media Player
〉Building Audio/Video Applications based on Player Framework v2.0 for Windows Phone 8, Windows 8.1 and Windows Phone 8.1
〉Using .NET HttpClient to capture partial Responses
沒有留言:
張貼留言