所以我在 WP 7.5 中遇到了后台音频播放代理的问题,我认为它在播放过程中被操作系统随机终止。
我有一个应用程序,它实现了一个 BAP 代理,该代理根据 UI 中选定的章节播放多个 mp3 文件。每章都有多个经文,这些经文在独立存储中都有一个关联的 mp3 文件。
在 UI 中选择章节并且用户按下播放按钮后,将调用 BackgroundAudio.Instance.Play()
,并且该章节的第一节(mp3 文件)将作为AudioTrack。当轨道结束时,下一首轨道将在 TrackEnded
状态下的 OnPlayStateChanged
事件方法中加载。
我在 TrackEnded
中还有一些逻辑,它检查是否已到达章节末尾(即,当前章节的最后一个 mp3 文件已播放),如果是,则检查第一个 mp3 文件将检索下一章。
现在,使用 Windows Phone 7 模拟器(512Mb 和 256Mb 模拟器)时,上述所有操作都可以正常工作,mp3 文件可以正确播放,并且当到达章节末尾时,下一章的下一个 mp3 文件也可以正确播放已加载并播放。
我遇到的问题是,当我将此应用程序部署到 Win 8 设备 (Lumia 920) 时,音频开始正常播放,然后音频突然且看似随机地停止了!没有错误消息,应用程序不会崩溃,只是音频停止播放。此外,当我单击设备上的 UVC 按钮时,不会显示 AudioTrack
信息,就像音频播放期间或音频已暂停的情况一样(仅显示音量信息)。
我不知道发生了什么事,我认为操作系统可能正在终止后台音频播放代理,但我不知道为什么(我认为我没有达到任何内存限制,但我无法确认这一点我不知道如何检查我是否是)。
任何建议/帮助将不胜感激。
谢谢
更新 2014 年 1 月 14 日
为了确认我的 BAP 未达到 15Mb(WP7) 和 20Mb(WP8) 的内存限制,我实现了一些代码,记录了 BAP 在执行过程中各个阶段的当前内存使用情况。
内存使用量没有达到操作系统对 BAP 施加的限制附近的任何地方,我达到的峰值是 7Mb,我上面描述的问题仍然发生,我可以从日志中看到下一个轨道已经设置但状态 Trackready
永远不会被命中,也不会抛出异常/错误。这实在是难倒了我!
更新 2014 年 1 月 15 日 下面是我如何实现 BAP 的示例:
public AudioPlayer()
{
if (!_classInitialized)
{
_classInitialized = true;
// Subscribe to the managed exception handler
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
Application.Current.UnhandledException += AudioPlayer_UnhandledException;
});
lastPlayedVerse = currentVerseNumber;
}
}
/// Code to execute on Unhandled Exceptions
private void AudioPlayer_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
//Helper class to help log any exceptions
IsolatedStore.WriteToIS("unhandeled Ex: " + e.ExceptionObject.Message, IsolatedStore.MemLogFileName);
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
protected override void OnError(BackgroundAudioPlayer player, AudioTrack track, Exception error, bool isFatal)
{
//Helper class to help log any exceptions
IsolatedStore.WriteToIS("OnError Called: " + error.Message, IsolatedStore.MemLogFileName);
if (isFatal)
{
Abort();
}
else
{
NotifyComplete();
}
}
protected override void OnPlayStateChanged(BackgroundAudioPlayer player, AudioTrack track, PlayState playState)
{
switch (playState)
{
case PlayState.TrackEnded:
track = null;
IsolatedStore.AppendToFileIS(string.Format("Track Ended::Time: {0}",DateTime.Now.ToLongTimeString()), IsolatedStore.MemLogFileName);
#region Track Ended logic
//IN here I have some logic to determine what the next track should be and then I call a function that returns an AudioTrack
player.Track = GetNextTrack(); //this method returns an AudioTrack
#endregion
break;
case PlayState.TrackReady:
IsolatedStore.AppendToFileIS(string.Format("Track Ready::Time: {0}, Track: {1}", DateTime.Now.ToLongTimeString(),track.Title), IsolatedStore.MemLogFileName);
//Put this try catch in here becoz i thought that this is where the issue was (not sure if its needed as any exception should be caught by the AudioPlayer_UnhandledException function.
try
{
player.Play();
}
catch (Exception ex)
{
IsolatedStore.AppendToFileIS(string.Format("Track Ready play exception: {0}", ex.Message), IsolatedStore.MemLogFileName);
}
break;
}
NotifyComplete();
}
protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
switch (action)
{
case UserAction.Play:
if (player.PlayerState != PlayState.Playing)
{
IsolatedStore.AppendToFileIS(string.Format("UA-PLAY::Time: {0}, Track: {1}", DateTime.Now.ToLongTimeString(),track.Title), IsolatedStore.MemLogFileName);
player.Play();
}
break;
}
NotifyComplete();
}
private AudioTrack GetNextTrack(int audioType2Get, string filePath, int verserNum, bool incrementTrackCount)
{
#region Memusage
//Code to log the memory usage
long currMemUsage = (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");
currMemUsage = (currMemUsage / 1024) / 1024;
long peakMemUsage = (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage");
peakMemUsage = (peakMemUsage / 1024) / 1024;
IsolatedStore.AppendToFileIS(string.Format("Getting Track-Time: {0}, Curr:{1}, Track: {2}", DateTime.Now.ToLongTimeString(), currMemUsage, verserNum), IsolatedStore.MemLogFileName);
#endregion
AudioTrack track = null;
#region AudioTrack Set region
//Some logic to return the AudioTrack
#endregion
}
更新 2014 年 1 月 24 日问题已解决
我终于有时间尝试一下@Soonts在我标记为答案的答案中推荐的内容,首先我使用的是WP8设备,所以我跳过了他提到的第一个setp,接下来我按原样做了在步骤 2 中再次提到最大内存使用量仅为 8Mb。
几天前,我的 WP8 设备有更新 (WP8 Update 3) ,安装此更新后,我尝试重现该问题,你猜怎么着!这个问题不再发生!,我的音频连续播放了一个多小时,没有任何问题!内存使用也稳定在8Mb左右。所以看来 BG Audio 可能进行了静默更新。
我之所以将@snoots答案标记为答案,是因为他在该答案中提到该问题可以通过静默更新来解决。
最佳答案
这可能发生在未处理的异常上。订阅
Application.Current.UnhandledException
(如果您对TaskScheduler.UnobservedTaskException
使用async-await)并将它们记录在某处。另外,重写代理的 OnError 方法并记录。如果在处理完请求后忘记调用BackgroundAgent.NotifyComplete()(即对于玩家代理,OnPlayStateChanged 和OnUserAction),可能会发生这种情况。在这种情况下,操作系统认为您无法及时处理请求,并终止 BAP 进程。
RAM 问题,但您已经解决了。
附注这是我的 Sky.fm 播放器应用程序的相关部分。它不播放本地 MP3,而是从 Internet 传输音乐,但播放器代理代码应该大致相同。
/// <summary>This class wraps AudioPlayerAgent API into the async-friendly abstract class.</summary>
/// <remarks>Logging and exception handling are added, as well.</remarks>
public abstract class PlayerAgentAsync: AudioPlayerAgent
{
static PlayerAgentAsync()
{
UnhandledExceptionHandler.subscribe();
}
public PlayerAgentAsync()
{
Logger.info( "constructed" );
}
protected override void OnError( BackgroundAudioPlayer player, AudioTrack track, Exception ex, bool isFatal )
{
if( isFatal )
{
BackgroundErrorNotifier.addError( ex );
ex.log();
Abort();
}
else
{
ex.logWarning();
try
{
// Force the track to stop
// http://blogs.msdn.com/b/wpukcoe/archive/2012/02/11/background-audio-in-windows-phone-7-5-part-3.aspx
player.Track = null;
}
catch (System.Exception ex2)
{
ex2.logWarning( "Exception while trying to stop da playa" );
}
NotifyComplete();
}
}
/// <summary>Called when the play state changes, except for the error state.</summary>
protected override async void OnPlayStateChanged( BackgroundAudioPlayer player, AudioTrack track, PlayState playState )
{
Logger.info( "new playState = {0}", playState.ToString() );
try
{
await this.playStateChangedAsync( player, track, playState ).ConfigureAwait( false );
NotifyComplete();
}
catch (System.Exception ex)
{
this.onException( ex );
}
}
/// <summary>Called when the user requests an action using some application-provided UI or the Universal Volume Control (UVC) and the application has requested notification of the action.</summary>
protected override async void OnUserAction( BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param )
{
Logger.info( "action = {0};", action.ToString() );
try
{
await this.userActionAsync( player, track, action, param ).ConfigureAwait( false );
NotifyComplete();
}
catch( System.Exception ex )
{
this.onException( ex );
}
}
private void onException( Exception ex )
{
if( ex.shouldBeIgnored() )
{
ex.logWarning();
this.NotifyComplete();
return;
}
ex.log();
BackgroundErrorNotifier.addError( ex );
this.Abort();
}
protected override void OnCancel()
{
Logger.trace();
base.OnCancel();
}
/// <summary>Handle OnPlayStateChanged asyncronously.</summary>
/// <param name="player">The Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer.</param>
/// <param name="track">The track playing at the time that the play state changed.</param>
/// <param name="playState">The new state of the player.</param>
protected abstract Task playStateChangedAsync( BackgroundAudioPlayer player, AudioTrack track, PlayState playState );
/// <summary>Handle OnUserAction asyncronously</summary>
/// <param name="player">The Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer.</param>
/// <param name="track">The track playing at the time of the user action.</param>
/// <param name="action">The action that the user has requested.</param>
/// <param name="param">The data associated with the requested action.</param>
protected abstract Task userActionAsync( BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param );
}
关于windows-phone-7 - 后台音频播放代理在播放过程中终止 Windows Phone 7.5,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20990638/