Windows Phone后台音樂播放本地代理實現討論


前一篇文章討論的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)
            {

            }
        }
    }
View Code

我不知道我上面的實現有問題還是怎么,我遇到了很多莫名奇妙的問題:

1、我有時候能播放歌曲,但是播放到部分就報錯,有時候也能連續播放歌曲,但是大部分時候是不能播放歌曲的,希望大家在測試我代碼的時候在AudioPlayer.cs的OnError里面打一個斷點。

2、因為每次報錯都進入了OnError,並且每次的異常消息都是一串數字,搞得我不知道哪里出錯。

問題原因分析:

在OnError的備注里有這么一句話"每次播放出錯(如 AudioTrack 未正確下載)時調用",所以我猜測是我的數據沒有正確返回導致錯誤的。

還有就是在監聽處理函數里面我會得到相同的請求,我想可能因為在WP里面HTTP的請求都是異步的,因為異步是非阻塞的,所以當我的數據還沒有返回的時候,BackgroudAudiaPlayer沒有收到就繼續發送同一個請求,

一般在收到兩個之后程序就會產生異常,並且進入OnError。所以我猜測如果有同步請求是不是就會正確(貌似安卓就是同步請求實現的),調試了幾天都沒解決,希望大家看看我的思路是否可行,或者還是我的實現有問題,

望指點。 歡迎關注我的微博@多了特 一起討論

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM