wp8 Soundeffect can't stop - windows-phone-7

I use soundeffect to play sound from byte array and all things go alright, but i cant stop playing the sound because no method called stop() in Soundeffect, how i can stop it ?
The code:
private void playFile(byte[] file)
{
try
{
if (file == null || file.Length == 0) return;
SoundEffect se = new SoundEffect(file, microphone.SampleRate, AudioChannels.Mono);
SoundEffect.MasterVolume = 0.7f;
if (stop != 1)
{
FrameworkDispatcher.Update();
se.Play();
}
else
{
//Here should stop, how !
}
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
}

Have you tried calling .Dispose() on your SoundEffect object? According to the documentation,
When a SoundEffect object is destroyed, all SoundEffectInstance
objects previously created by that SoundEffect will stop playing and
become invalid.
Additionally, Microsoft recommends using MediaElement instead, unless you're developing with XNA Game Studio 4.0. So if that applies to you, you may want to consider using MediaElement which does have Play, Pause, and Stop functions.

try using SoundEffectInstance
Sound effect instance
Here's a link to the solution
Sound Effect Instance
More over SoundEffectInstance implements IDisposeable so it will have a dispose() method as well as stop() for the sound effect .

Create a variable for SoundEffectInstance as shown below
SoundEffectInstance soundEffectInstance;
then create an instance of your soundEffect after loading the file..
soundEffectInstance = se.CreateInstance();
after that use this soundEffectInstance to Stop, Play or Pause where ever you want in particular scope.
soundEffectInstance.Play();
Note that SoundEffect is used for fire and forget type instances, if you want to control any particular instance of a SoundEffect you will need to use SoundEffectInstance.
I agree with Benoit Catherinet. If you are trying to stop a particular sound on some event then you must place the stoping code in that event method and for that your SoundEffect instance must be global and not local.
We can better help you if you can explain about what you are trying to achieve.

Related

How to delay loading the scene to play the sound

How to delay loading the scene to play the sound?
I'm trying to delay loading a scene so I can play the sound, but the sound stops in the middle or doesn't exist at all and the scene changes immediately
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MeinMenu : MonoBehaviour
{
static AudioSource audioScr;
public void NewGame()
{
SoundManagerScript.PlaySound("clik");
DontDestroyOnLoad(audioScr.gameObject);
SceneManager.LoadScene("level 1");
}
public void LoadGame()
{
SceneManager.LoadScene(PlayerPrefs.GetInt("SavedScene"));
}
}
Happens when the scene loads faster than the sound can finish playing.
When a scene loads by default, it destroys all objects on the previous scene, which includes your audio source.
One way is to mark your audio-source with DontDestroyOnLoad
// Somewhere after your audio source have loaded...
DontDestroyOnLoad(yourAudioSource.gameObject);
Note that this means you are likely to end up with a singular instance of Audio Source, as this audio source (or the game-object attached to it, to be exact) will only be destroyed manually via script.
The other is to just do a coroutine that does nothing until the audio source have finished playing:
IEnumerator LoadSceneWithSoundCoroutine()
{
yourAudioSource.Play();
// Denies loading while audio source is playing.
while (yourAudioSource.isPlaying)
{
yield return null;
}
SceneManager.LoadScene("Your scene")
}
// ...
StartCoroutine(LoadSceneWithSoundCoroutine());

MediaPlayer.Play() causes UI to freeze

Everytime MediaPlayer.Play() is executed from the UI thread the UI freezes for a significant amount of time. I don't think you can do anything about the time it takes to start playing the SongCollection but at least the UI should stay responsive.
Running MediaPlayer.Play() from another thread obviously doesn't work.
The MediaPlayer is a component from the Xna Namespace. If you are using this feature in a game, you are most certain running a GameLoop to prevent this freeze from happening: GameLoop
If you use this component in an App, you can simulate this behavior your own
public MainPage()
{ InitializeComponent();
// Timer to simulate the XNA Game Studio game loop (Microphone is from XNA Game Studio)
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(33);
dt.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
dt.Start();
}
(see complete sample on how to run a microphone outside a gameloop: msdn)

Background Audio Playback Agent terminates during playback Windows Phone 7.5

So I have a problem with the Background Audio Playback agent in WP 7.5, where I think it is getting terminated by the OS randomly during playback.
I have an app which implements a BAP agent which plays a number of mp3 files based the selected chapter in UI. Each chapter has multiple verses, these verses have an associated mp3 file in isolated storage.
Once a chapter has been selected in the UI and the user presses the play button BackgroundAudio.Instance.Play() is called and the first verse (mp3 file) for that chapter is loaded as an AudioTrack. When the track has ended the next track is loaded in the OnPlayStateChanged event method under the TrackEnded state.
I also have some logic in the TrackEnded which checks if the end of the chapter has been reached (i.e. the last mp3 file for the current chapter has been played) and if so the first mp3 file for the next chapter will retrieved.
Now all the above works fine when using the Windows Phone 7 Emulator (both 512Mb and 256Mb Emulators), the mp3 files are played correctly and when the end of a chapter has been reached the next mp3 file for the next chapter is correctly loaded and played.
The problem I encounter is when I deploy this app to a Win 8 Device (Lumia 920), the audio starts playing fine and the suddenly and seemingly randomly the audio stops! No error messages, the app does NOT crash, just the Audio Stops playing. Also when I click on the UVC buttons on the device NO AudioTrack info is displayed as is the case during audio playback or audio has been paused (just the volume info shows).
I have no idea what’s going on, I think the OS may be terminating the Background Audio Playback agent but I have no idea why (I don’t think I am reaching any of the memory limitations but I can not confirm this as I don’t know how to check if I am).
Any advice/help will be appreciated.
Thanks
Update 14/01/14
To confirm that the memory limit of 15Mb(WP7) and 20Mb(WP8) was not being reached by my BAP I implemented some code which logged the current memory usage of the BAP at various stages through out its execution.
The memory usage does not reach anywhere near the limits imposed by the OS on the BAP, the peak i reach is 7Mb the issue I described above is still occurring, I can see from the log that the next track has already been set but the state Trackready is never hit, also no exceptions/errors are thrown. This has really stumped me!
Update 15/01/14
Below is an example of how I have implemented the 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
}
Update 24/01/2014 ISSUE RESOLVED
I finally got some time to get around to attempting what #Soonts recommended in the answer I marked as the answer, and firstly I'm using a WP8 device so I skipped the first setp that he mentioned, next i did as was mentioned in step 2 and again the max memory usage was only 8Mb.
Then a few days back there was an update for my WP8 device (WP8 Update 3), after I installed this update I attempted to reproduce the problem and guess what! The issue DOES NOT OCCUR ANY MORE!, I had my audio on continuous play for over an hour with no issues! also the memory usage was stable at around 8Mb. So it looks like there may have been a silent update to the BG Audio.
The reason why I marked #snoots answer as the answer was because he mentioned in that answer that the issue may be fixed by a silent update.
This may happen on unhandled exceptions. Subscribe for Application.Current.UnhandledException (and if you're using async-await for TaskScheduler.UnobservedTaskException) and log them somewhere. Also, override OnError method of your agent, and log.
This may happen if forget to call BackgroundAgent.NotifyComplete() after you've finished processing the requests (i.e. for player agent, the OnPlayStateChanged and OnUserAction). In this case, the OS consludes you was unable to process the request in a timely manner, and terminates the BAP process.
RAM issues, but you've figured it out.
P.S. Here's the relevant part of my Sky.fm player application. It doesn't play local MP3s , instead it streams the music from the Internets, however the player agent code should be more or less the same.
/// <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 );
}
If I were you, I would probably do the following, in that order:
Ensure you have the latest OS updates. They have silently fixed some BAP-related memory issues in their 7.8 update. If you're not using the latest OS, upgrade and try to reproduce.
Place breakpoints in every place of your GUI process code that interacts with BAP, to make sure you’re not mistakenly calling e.g. BackgroundAudioPlayer.Stop() or BackgroundAudioPlayer.Track=null, try to reproduce.
Instead of “logging current memory usage of the BAP at various stages”, in static constructor of some agent class, create a thread that, in the endless loop, appends to some CSV file in the isolated storage, logging current timestamp + current memory , then sleeps for 500-1000 milliseconds. Reproduce the problem, use ISETool.exe to download the log, use Excel to build the RAM usage graph…
If (3) won’t show RAM usage approaching the limit, Implement tracing to either isolated storage or network (BTW, I’ve implemented a SysLog RFC 5426 client in my WP7 code, and installed free software called “SysRose Syslog Desktop” on my PC), then try to do printf-style debugging.

Poor performance on song playback start in WP7

I have an XNA arcade game which runs over Silverlight environment. The game has a few sound clips which are played in random order as background music.
As stated in http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.media.songcollection.aspx, a developer cannot have full control over Media Player. Particularly, developers cannot create their song collections or add songs to the playback queue. There is a recommendation to play songs one at a time by calling MediaPlayer.Play().
That’s exactly what I'm doing but I experience a performance flaw each time when another song starts playing. The game hangs on for a moment when I call MediaPlayer.Play() despite all sound clips are loaded during game initialization, not in runtime. This happens only on some devices (e.g. HTC Mozart). In contrast, if I disable game sounds and play the same clips in phone’s music player while running the game, there are no performance issues during song changes. I also don’t experience performance problems if we play the clips using SoundEffect class. However, I'm strongly willing to use MediaPlayer for background sound purposes due to 2 reasons:
- SoundEffect doesn’t issue notification when playback is completed
- SoundEffect doesn’t seem to work with .mp3 files, and using .wav files is very expensive
I've also run profiling tests which confirmed that the poor performance time frame starts in a few milliseconds after MediaPlayer.Play() and continues during about 0,4 seconds. During this time my game doesn't execute any heavy-weight operations, just regular game timer's Update() function.
Here is my code snippets:
public void PlayBackgroundMusic(Song song)
{
if ((!(App.Current as App).AppModel.SoundDisabled) && (song != null))
{
if (MediaPlayer.State != MediaState.Stopped)
{
StopBackgroundMusic();
}
MediaPlayer.Play(song);
}
}
public void StopBackgroundMusic()
{
MediaPlayer.Stop();
}
and the handler:
private void OnMediaStateChanged(object sender, EventArgs e)
{
if (MediaPlayer.State != MediaState.Playing)
{
if (!AppModel.SoundDisabled)
{
int index = soundRandomizer.Next(0, sounds.Length - 1);
PlayBackgroundMusic(sounds[index]);
}
}
}
Are there any suggestions?
After all, I found a solution which I'm satisfied with. It eliminates jiggling almost completely. Its idea is to use every MediaPlayer API in a separate thread obtained from thread pool. I'm not aware how it fixes the problem but this really works for me:
public void PlayBackgroundMusic(Song song)
{
if ((!(App.Current as App).AppModel.SoundDisabled) && (song != null))
{
if (MediaPlayer.State != MediaState.Stopped)
{
StopBackgroundMusic();
}
ThreadPool.QueueUserWorkItem((o) =>
{
MediaPlayer.Play(song);
}
}
}
public void StopBackgroundMusic()
{
ThreadPool.QueueUserWorkItem((o) =>
{
MediaPlayer.Stop();
}
}

Serializing data by GameStateManagment on Windows phone

I am trying to serialize my game data. In case the user presses the Windows button, everything should be saved. I know that we should override the OnExiting event in the game class. but am using the Game State Management , I want to serialize game data in my GamePlayScreen class. I did override the Serialize and DeSerialize methods, but they didnt work.
hers my code:
public override void Serialize(Stream stream)
{
gameState.HumanPlayer = HumanPlayer;
gameState.Player1 = AIPlayer1;
gameState.Player2 = AIPlayer2;
gameState.Player3 = AIPlayer3;
XmlSerializer serializer = new XmlSerializer(typeof(GameState));
serializer.Serialize(stream, gameState);
base.Serialize(stream);
}
public override void Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(GameState));
gameState = (GameState)serializer.Deserialize(stream);
if (gameState.HumanPlayer != null)
HumanPlayer = gameState.HumanPlayer;
if (gameState.Player1 != null)
AIPlayer1 = gameState.Player1;
if (gameState.Player2 != null)
AIPlayer2 = gameState.Player2;
if (gameState.Player3 != null)
AIPlayer3 = gameState.Player3;
base.Deserialize(stream);
}
I tried to create my own IsolatedStorageFile instead of the provided stream object, but it didnt work.
I tried to write the same code in the Load and Unload event. it works fine there, but in case of pressing the back button. i need to serialize if the user pressed the windows button or the search button.
It looks like you need to handle the OnDeactivated and OnActivated events. Just do the same thing as is done in the OnExiting event and the Constructor. I would have thought the sample would do this as proper handling of tombstone/rehydrate is such a big thing for WP7, however it seems it has been neglected. Note that OnActivated is NOT called when the app is launched and OnDeactivated is NOT called when the app is closed manually or exited using the Back button.
Note that Activated and Deactivated area also available as events on PhonApplicationServices.Current, along with Launching and Closing, which are ONLY called on actual open and exit situations.
EDIT
Ok, I take it back. OnDeactivated and OnActivated are not required. It seems that OnExiting is fired for both Deactivate and Exit scenarios. I downloaded the sample you linked (XNA4 WP7, not Mango version) and put this code into the GameplayScreen:
public override void Serialize(System.IO.Stream stream)
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(string));
serializer.Serialize(stream, "Blah de blah blah");
base.Serialize(stream);
}
public override void Deserialize(System.IO.Stream stream)
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(string));
string testStr = (string)serializer.Deserialize(stream);
base.Deserialize(stream);
}
A break point shows that the Deserialize method is being hit functioning correctly, so your problem must be in how you apply your loaded data, or perhaps you've edited other code that has broken it.

Resources