HttpWebRequest от AudioPlayerAgent

Я создаю приложение, которое воспроизводит бесконечный аудиопоток. Существует отдельная веб-служба, которую я могу запросить, чтобы получить название и исполнителя воспроизводимой в данный момент дорожки. Я хочу запрашивать эту службу каждые 20 секунд, а затем соответственно устанавливать название трека / исполнителя. В настоящее время я использую фоновый AudioPlayerAgent, чтобы поток можно было воспроизводить вне моего приложения. Вот код, который у меня есть:

public AudioPlayer()
    {
        if (!_classInitialized)
        {
            _classInitialized = true;
            // Subscribe to the managed exception handler
            Deployment.Current.Dispatcher.BeginInvoke(delegate
            {
                Application.Current.UnhandledException += AudioPlayer_UnhandledException;

            });
            trackTimer = new Timer(TrackTimerTick, null, 1000, 5000);
        }
    }

    public void TrackTimerTick(object state) {             
            // Create a HttpWebrequest object to the desired URL.
            HttpWebRequest trackRequest = (HttpWebRequest)HttpWebRequest.Create("<stream url>");
            // Start the asynchronous request.
            IAsyncResult result = (IAsyncResult)trackRequest.BeginGetResponse(new AsyncCallback(TrackCallback), trackRequest);
    }

    public void TrackCallback(IAsyncResult result) {
        if (BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing && result != null) {
            try {
                // State of request is asynchronous.
                HttpWebRequest trackRequest = (HttpWebRequest)result.AsyncState;
                HttpWebResponse trackResponse = (HttpWebResponse)trackRequest.EndGetResponse(result);
                using (StreamReader httpwebStreamReader = new StreamReader(trackResponse.GetResponseStream())) {
                    string results = httpwebStreamReader.ReadToEnd();
                    StringReader str = new StringReader(results);
                    XDocument trackXml = XDocument.Load(str);

                    string title = (from t in trackXml.Descendants("channel") select t.Element("title").Value).First<string>();
                    string artist = (from t in trackXml.Descendants("channel") select t.Element("artist").Value).First<string>();
                    if (BackgroundAudioPlayer.Instance.Track != null) {
                        AudioTrack track = BackgroundAudioPlayer.Instance.Track;
                        track.BeginEdit();
                        track.Title = title;
                        track.Artist = artist;
                        track.EndEdit();
                    }

                }
                trackResponse.Close();
                NotifyComplete();
            } catch (WebException e) {
                Debug.WriteLine(e);
                Debug.WriteLine(e.Response);
            } catch (Exception e) {
                Debug.WriteLine(e);
            }
        }  
    }

Веб-исключение выдается каждый раз, когда я пытаюсь прочитать ответ от HttpWebRequest. Это правильный способ сделать это? Есть ли у кого-нибудь предложения, как я могу это исправить?


person bfink    schedule 06.05.2012    source источник
comment
Не ловите исключения. stackoverflow.com/questions/1742940/ msdn.microsoft.com/en-us/library /ms182137%28v=vs.100%29.aspx   -  person Lukasz Madon    schedule 07.05.2012
comment
Комментарий @Sedgwickz, кажется, частично исправляет это, теперь я могу правильно получить данные трека. Однако, как только я вызываю NotifyComplete (), таймер больше не тикает - какие-нибудь советы, как это исправить?   -  person bfink    schedule 07.05.2012


Ответы (2)


Вы не закрываете HttpWebResponse, что является необходимостью. Кроме того, существует перегрузка XDocument.Load(), которая требует Stream, поэтому вам вообще не нужно использовать StreamReader.

РЕДАКТИРОВАТЬ: Извините, я пропустил вызов Close() в конце. Но другой комментарий по-прежнему актуален.

Если это не решит проблему, по крайней мере, это сделает ваш код более чистым:

public void TrackCallback(IAsyncResult result) {
    if (BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing && result != null) {
        try {
            // State of request is asynchronous.
            HttpWebRequest trackRequest = (HttpWebRequest)result.AsyncState;
            using (HttpWebResponse trackResponse = (HttpWebResponse)trackRequest.EndGetResponse(result)){
                XDocument trackXml = XDocument.Load(trackResponse.GetResponseStream());

                string title = (from t in trackXml.Descendants("channel") select t.Element("title").Value).First<string>();
                string artist = (from t in trackXml.Descendants("channel") select t.Element("artist").Value).First<string>();
                if (BackgroundAudioPlayer.Instance.Track != null) {
                    AudioTrack track = BackgroundAudioPlayer.Instance.Track;
                    track.BeginEdit();
                    track.Title = title;
                    track.Artist = artist;
                    track.EndEdit();
                }
            }
            }
            NotifyComplete();
        } catch (WebException e) {
            Debug.WriteLine(e);
            Debug.WriteLine(e.Response);
        } catch (Exception e) {
            Debug.WriteLine(e);
        }
    }  
}
person Steven Liekens    schedule 06.05.2012
comment
Спасибо за ответ. К сожалению, это все еще не работает, но мой код выглядит лучше :) - person bfink; 07.05.2012

Это связано с тем, что AudioPlayer выходит за рамки после того, как начинает воспроизведение музыки. AudioPlayer живет только часть времени и прекращает работу после вызова NotifyComplete

Взгляните на мой ответ на это сообщение: AudioPlayerAgent, таймер и веб-сервис

Дополнительная информация: фоновый аудиопоток будет "приостановлен" после вызова NotifyComplete. Обратный путь - это когда пользователь меняет воспроизведение (OnUserAction) или когда песня заканчивается (OnPlayStateChanged). Если вы продолжите играть, получите новую информацию в методе OnPlayStateChanged.

person Shawn Kendrot    schedule 15.05.2012
comment
Спасибо за ответ. Вы хотите сказать, что если я создам таймер внутри класса Songs, на который вы ссылаетесь в своем ответе, этот таймер будет продолжать работать? - person bfink; 16.05.2012
comment
Я пробовал, как я думаю, это должно работать, но таймер и любые асинхронные вызовы HttpWebRequest по-прежнему завершаются, когда я вызываю NotifyComplete. Какие-нибудь советы по размещению их в фоновом потоке, который не завершается при вызове NotifyComplete? - person bfink; 16.05.2012
comment
Проблема в том, что поток бесконечно длинный, поэтому OnPlayStateChanged никогда не будет вызван. Я чувствую, что единственный способ решить мою проблему - это использовать где-нибудь таймер. Любые идеи? - person bfink; 16.05.2012
comment
Только другой способ - в основном потоке пользовательского интерфейса или через запланированный агент. Но агент срабатывает примерно каждые 30 минут. - person Shawn Kendrot; 16.05.2012
comment
Подскажите, как разместить это в основной ветке пользовательского интерфейса? Есть ли в этом недостаток? - person bfink; 17.05.2012
comment
Основной поток пользовательского интерфейса - это поток вашего приложения (например, MainPage.xaml.cs). Основным недостатком этого является то, что название песен не будет обновляться, когда пользователь уже существует в приложении. - person Shawn Kendrot; 17.05.2012