前一篇文章討論的wp平台音樂播放的一些遇到的問題,經過苦思冥想和多方參考安卓實現;發現我們可以考慮一種本地代理的思想來完成我們的邊聽邊存,並且流暢拖動進度條。希望大家一起討論。可以下載我的代碼一同研究
安卓實現本地代理文章參考:
Android MediaPlayer與Http Proxy結合之基礎篇
Android MediaPlayer與Http Proxy結合之提高篇 如果我們也能這樣實現的話,我們還能實現緩沖進度條
玩轉 Android MdeiaPlayer之Meida Proxy
通過上面的參考我的思路如下:
1、首先我將BackGroundAudiaoPlayer的AudiaoTrack地址設為本地代理的地址,請求本地代理;
2、本地代理受到請求,將同樣的請求發送給遠程服務器;
3、遠程服務器響應流給本地代理,
4、本地代理將流返回BackGroundAudiaoPlayer;
接下來我們先來看看我抓包分析BackGroundAudiaoPlayer直接請求遠程服務器的過程,他包括兩個過程,第一個請求:
在我聽歌一段時間后,它會繼續發一個Range請求:
BackGroundAudiaoPlayer直接請求遠程服務器的兩個過程,一幫應該是發送上面兩個請求,如果文件大的話可能第二步會重復。
接下來就是我的實現過程:
1、首先我將遠程地址替換成本地地址,並且啟動本地監聽:
//啟動本地代理監聽 MediaProxy mp = new MediaProxy(); mp.StartSocketListener(); //在服務器地址前面加上本地地址和端口,讓他請求本地代理 string mp3Url = @"http://127.0.0.1:33123/qq.djwma.com/mp3/江南style_最新dj版.mp3"; BackgroundAudioPlayer.Instance.Track = new AudioTrack(new Uri(mp3Url, UriKind.Absolute), "江南Style", "棒子", null, null, null, EnabledPlayerControls.All); BackgroundAudioPlayer.Instance.Play();
第二步我在本地代理里面處理相關的請求MdeiaProxy.cs:

/// <summary> /// 代理類 /// </summary> public class MediaProxy { StreamSocketListener socketListener; public void StartSocketListener() { socketListener = new StreamSocketListener();//創建一個本地StreamSocketListener監聽 socketListener.ConnectionReceived += socketListener_ConnectionReceived; socketListener.BindServiceNameAsync("33123"); } void socketListener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) { StreamSocket s = args.Socket; RequestHttp(s); } /// <summary> /// 遠程請求服務器 /// </summary> /// <param name="obj"></param> private async void RequestHttp(object obj) { StreamSocket s = obj as StreamSocket; // bool hasRange = false;//用於標記第二次請求 try { DataReader reader = new DataReader(s.InputStream); reader.InputStreamOptions = InputStreamOptions.Partial; uint numStrBytes = await reader.LoadAsync(5120); string requestStr = reader.ReadString(numStrBytes); // using (IOutputStream output = args.Socket.OutputStream) Stream outputStream = s.OutputStream.AsStreamForWrite(); { string[] requestHeaders = requestStr.Split(new char[] { '\r', '\n' }); string requestMethod = requestHeaders[0]; string[] requestParts = requestMethod.Split(' '); string httpServer = "http:/"; string url = httpServer + requestParts[1];//組裝遠程mp3地址 HttpWebRequest webRequest = WebRequest.CreateHttp(url); webRequest.AllowReadStreamBuffering = false;//這里設置為false,可以避免下載全部的流才得到相應 #region HTTP頭部信息處理 Dictionary<string, string> pragmaDic = new Dictionary<string, string>(); for (int i = 1; i < requestHeaders.Length; i++) { if (!string.IsNullOrWhiteSpace(requestHeaders[i])) { string[] head = requestHeaders[i].Split(':'); if (head.Length == 2 && head[0] != "Host") { if (head[0].ToLower() == "accept") { webRequest.Accept = head[1]; continue; } //第一次請求不包含Range //if (head[0].ToLower() == "range") //{ // webRequest.Headers[head[0]] = head[1]; // hasRange = true; // continue; //} if (head[0].ToLower() == "contentlength") { webRequest.ContentLength = long.Parse(head[1]); continue; } if (head[0].ToLower() == "contenttype") { webRequest.ContentType = head[1]; continue; } if (head[0].ToLower() == "user-agent") { webRequest.UserAgent = head[1]; continue; } if (head[0].ToLower() == "pragma") { pragmaDic.Add(head[1], head[1]); continue; } webRequest.Headers[head[0]] = head[1]; } } } if (pragmaDic.Count > 0) { string pragma = string.Empty; foreach (string p in pragmaDic.Values) { pragma += p; } webRequest.Headers["Pragma"] = pragma; } #endregion webRequest.BeginGetResponse((res) => { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { HttpWebRequest request = res.AsyncState as HttpWebRequest; HttpWebResponse response = request.EndGetResponse(res) as HttpWebResponse; WebHeaderCollection headerCollection = response.Headers; string codeEn = response.StatusCode.ToString(); int codeNum = (int)response.StatusCode; //第一種響應頭:將服務器返回的頭信息全部返回給播放器 //string header =string.Format("HTTP/1.1 {0} {1}\r\n{2}" ,codeNum,codeEn, headerCollection.ToString()); //第二種響應頭:將自定義頭部 string header1 = String.Format(@"HTTP/1.1 200 OK\r\nContent-Type: audio/mpeg\r\nConnection: keep-alive\r\nContent-Length: {0}\r\n\r\n", response.ContentLength); Stream stream = response.GetResponseStream(); // using (Stream stream = response.GetResponseStream()) { byte[] headerArray = Encoding.UTF8.GetBytes(header1); outputStream.WriteAsync(headerArray, 0, headerArray.Length); stream.CopyToAsync(outputStream); outputStream.FlushAsync(); } }); }, webRequest); } } catch (Exception ex) { } } }
我不知道我上面的實現有問題還是怎么,我遇到了很多莫名奇妙的問題:
1、我有時候能播放歌曲,但是播放到部分就報錯,有時候也能連續播放歌曲,但是大部分時候是不能播放歌曲的,希望大家在測試我代碼的時候在AudioPlayer.cs的OnError里面打一個斷點。
2、因為每次報錯都進入了OnError,並且每次的異常消息都是一串數字,搞得我不知道哪里出錯。
問題原因分析:
在OnError的備注里有這么一句話"每次播放出錯(如 AudioTrack 未正確下載)時調用",所以我猜測是我的數據沒有正確返回導致錯誤的。
還有就是在監聽處理函數里面我會得到相同的請求,我想可能因為在WP里面HTTP的請求都是異步的,因為異步是非阻塞的,所以當我的數據還沒有返回的時候,BackgroudAudiaPlayer沒有收到就繼續發送同一個請求,
一般在收到兩個之后程序就會產生異常,並且進入OnError。所以我猜測如果有同步請求是不是就會正確(貌似安卓就是同步請求實現的),調試了幾天都沒解決,希望大家看看我的思路是否可行,或者還是我的實現有問題,
望指點。 歡迎關注我的微博@多了特 一起討論