AudioPlayerAgent, таймер и веб-сервис
Мое приложение прочитало shoutcast.
Метаданные воспроизводимой музыки собраны с веб-сервиса, который возвращает мне Json (поэтому мне не нужно декодировать поток). Я вызываю веб-сервис каждые 20 секунд с таймером, это работает в моем приложении, но не работает в AudioPlayer.cs
//Timer
private DispatcherTimer timer;
/// <remarks>
/// AudioPlayer instances can share the same process.
/// Static fields can be used to share state between AudioPlayer instances
/// or to communicate with the Audio Streaming agent.
/// </remarks>
public AudioPlayer()
{
if (!_classInitialized)
{
_classInitialized = true;
// Subscribe to the managed exception handler
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
Application.Current.UnhandledException += AudioPlayer_UnhandledException;
});
}
//I activate the timer
timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(20) // <------- Error here UnauthorizedAccessException was unhandled. Invalid cross-thread access.
};
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
HttpWebRequest request = WebRequest.Create("http://127.0.0.81:8003/getmeta") as HttpWebRequest;
request.BeginGetResponse(new AsyncCallback(AsyncBack), request);
}
private void AsyncBack(IAsyncResult ias)
{
HttpWebRequest req = (HttpWebRequest)ias.AsyncState;
try
{
using (HttpWebResponse res = req.EndGetResponse(ias) as HttpWebResponse)
{
StreamReader stream = new StreamReader(res.GetResponseStream());
String jsonToParse = stream.ReadToEnd();
JObject jObject = JObject.Parse(jsonToParse);
AudioTrack track = BackgroundAudioPlayer.Instance.Track;
track.BeginEdit();
track.Title = (string) jObject["title"];
track.Artist = (string) jObject["artist"];
track.Album = (string) jObject["album"];
track.EndEdit();
res.Close();
}
}
catch (WebException e)
{
timer.Stop();
}
}
Спасибо тебе за помощь
1 ответ
Класс AudioPlayer довольно уникален. Он живет только в течение небольшого периода времени. В приложении, которое использует BackgroundAudioPlayer, ваша реализация класса AudioPlayer останется в живых только для выполнения задачи по изменению состояния воспроизведения. Поэтому, когда пользователь начинает что-то воспроизводить, будет создан экземпляр вашего класса AudioPlayer, чтобы выполнить задачу начала воспроизведения. Как только вы вызываете NotifyComplete() в OnUserAction или OnPlayStateChanged, экземпляр вашего AudioPlayer исчезает.
Фоновый поток, с которым связан AudioPlayer, все еще будет активным, и в этом потоке могут быть живы другие объекты, но AudioPlayer будет прерван. Созданный по умолчанию AudioPlayer намекает на это с помощью поля _classInitialized. Это статично, потому что AudioPlayer будет создаваться много раз, но мы хотим подключиться к этому событию только один раз.
Я хотел бы предложить одну из двух вещей. Первый - получить ответ json только тогда, когда вам нужно перейти к следующей песне. Вы не будете вызывать NotifyComplete() до тех пор, пока не вернется ответ. Вот некоторый псевдокод:
override OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
GetJsonResponse();
}
private void GetJsonResponce()
{
// async call to your service
// When async completes:
track.BeginEdit();
track.Title = (string) jObject["title"];
track.Artist = (string) jObject["artist"];
track.Album = (string) jObject["album"];
track.EndEdit();
NotifyComplete();
}
Вторым было бы иметь класс, который делает это в фоновом режиме. Этот класс будет иметь статическое свойство для получения экземпляра, который является живым в потоке. Тогда ваш AudioPlayer получит необходимую информацию от этого объекта
public class Songs
{
static Songs _instance;
public static Songs Instance
{
get { return _instance ?? new Songs(); }
}
// Do you timer stuff here
// Allow the ability to access the timer stuff also.
}
// in AudioPlayer
override OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
Songs.Instance.GetStuff
NotifyComplete();
}