所以我在WP 7.5中遇到了背景音频播放代理问题,我认为在播放过程中它会被操作系统随机终止。
我有一个实现BAP代理的应用程序,该代理根据UI中选定的章节播放大量mp3文件。每章都有多个经文,这些经文在隔离存储中有一个相关的mp3文件。
一旦在UI中选择了章节并且用户按下播放按钮BackgroundAudio.Instance.Play()
被调用,该章的第一节(mp3文件)将被加载为AudioTrack
。当曲目结束后,下一首曲目将加载到OnPlayStateChanged
状态下的TrackEnded
事件方法中。
我在TrackEnded
中也有一些逻辑来检查是否已经到达章节的结尾(即当前章节的最后一个mp3文件已被播放),如果是,那么第一个mp3文件用于下一个章节将被检索。
现在,使用Windows Phone 7仿真器(512Mb和256Mb仿真器)时,以上所有工作正常,mp3文件正确播放,当到达章节结束时,下一章的下一个mp3文件正确加载和播放。
我遇到的问题是当我将此应用程序部署到Win 8设备(Lumia 920)时,音频开始播放正常,突然且看似随机的音频停止!没有错误消息,应用程序不会崩溃,只是音频停止播放。此外,当我单击设备上的UVC按钮时,会显示NO 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
}
更新24/01/2014解决问题
我终于有时间来尝试@Soonts在我标记为答案的答案中推荐的内容,首先我使用的是WP8设备,所以我跳过他提到的第一个setp,接下来我做的就是在步骤2中提到并且最大内存使用量仅为8Mb。
然后几天前我的WP8设备(WP8 Update 3)发生了更新,安装此更新后我尝试重现问题并猜测是什么!这个问题不会发生任何问题!我连续播放音频超过一个小时没有问题!内存使用量也稳定在8Mb左右。所以看起来可能已经对BG Audio进行了静音更新。
我之所以将@snoots的答案标记为答案是因为他在答案中提到可以通过静默更新修复该问题。
答案 0 :(得分:2)
这可能发生在未处理的异常上。订阅Application.Current.UnhandledException
(如果您正在使用TaskScheduler.UnobservedTaskException
的async-await)并将其记录在某处。此外,覆盖代理的OnError方法,并记录。
如果在处理完请求后忘记调用BackgroundAgent.NotifyComplete()(即播放器代理,OnPlayStateChanged和OnUserAction),则可能会发生这种情况。在这种情况下,操作系统包含您无法及时处理请求,并终止BAP流程。
RAM问题,但你已经弄明白了。
P.S。这是我的Sky.fm播放器应用程序的相关部分。它不播放本地MP3,而是播放来自互联网的音乐,但播放器代理代码应该或多或少相同。
/// <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 );
}
答案 1 :(得分:1)
如果我是你,我可能会按照以下顺序执行以下操作: