Reputation: 3967
I'm building an app with optional audio support, and it will feature some kind of background sounds (like a looping soundtrack that keeps on playing in every page).
What I did is to create an audio manager that allows me to manage my sounds, and this should mute/unmute the audio based on user's settings.
Unfortunately this doesn't happen, and the audio keeps on playing even if the user disables it.
This is a sample of my code:
public static async Task StartSoundManager()
{
// Get audio stream from app folder
// ...
BackgroundSound.SetSource(currentStream, currentFile.ContentType);
BackgroundSound.IsLooping = true;
ToggleSounds();
}
public static void ToggleSounds()
{
BackgroundSound.IsMuted = !Settings.IsAudioOn;
}
public bool IsAudioOn
{
// standard getter
set
{
// save value
SoundManager.ToggleSounds();
}
}
After some tests, IsMuted
is set correctly (I've also tried setting volume to 0) but nothing happens when changing settings.
Do you guys have any idea on why such a simple task is not working as expected? It seems to me that you can't change volume after setting the source, and this feels really wrong.
EDIT: more complete class
public static class AudioManager
{
public const string BACKGROUND = "BACKGROUND.mp3";
private static readonly MediaElement BackgroundSound = new MediaElement();
public static async Task StartSoundManager()
{
// Get folder
var folder =
await (await Package.Current.InstalledLocation.GetFolderAsync("Assets")).GetFolderAsync("Audio");
var currentFile = await folder.GetFileAsync(BACKGROUND);
var currentStream = await currentFile.OpenAsync(FileAccessMode.Read);
BackgroundSound.SetSource(currentStream, currentFile.ContentType);
// Set mode and volume
BackgroundSound.IsLooping = true;
ToggleSounds();
}
public static void ToggleSounds()
{
BackgroundSound.IsMuted = !Settings.IsAudioOn; // IsAudioOn is false, still the sound plays
}
}
Upvotes: 0
Views: 1222
Reputation: 441
I have a similar situation. I have a ToggleMenuFlyoutItem for turning sounds on and off app-wide that writes to the local settings:
Here is the XAML:
<Button IsTabStop="False" Style="{StaticResource qButtonStyleFinal}" TabIndex="2" x:Name="btnMore" BorderBrush="{x:Null}" Foreground="{x:Null}"
Content="1" Grid.Column="37" Margin="5" HorizontalAlignment="Center" Grid.Row="1" Grid.RowSpan="4" Grid.ColumnSpan="2" MaxWidth="60" MaxHeight="60">
<Button.Background>
<ImageBrush ImageSource="ms-appx:///Assets/more_project.png" Stretch="Uniform" />
</Button.Background>
<Button.Flyout>
<MenuFlyout>
<ToggleMenuFlyoutItem x:Name="mfiToggleSounds" Text="sound effects" IsChecked="{x:Bind Mode=TwoWay, Path=Model.Sounds}"></ToggleMenuFlyoutItem>
<MenuFlyoutItem x:Name="mfiExportExcel" Text="export to Excel" Tapped="mfiExportExcel_Tapped" />
<MenuFlyoutItem x:Name="mfiExportCSV" Text="export to CSV" Tapped="mfiExportCSV_Tapped" />
<MenuFlyoutItem x:Name="mfiEmailDeveloper" Text="email developer" Tapped="mfiEmailDeveloper_Tapped" />
</MenuFlyout>
</Button.Flyout>
</Button>
Changes are handled in the property set event:
private bool _sounds = true;
public bool Sounds
{
get => _sounds;
set
{
_sounds = value;
NotifyPropertyChanged();
var localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["sounds"] = _sounds;
}
}
Setting is loaded on the main page Page_Loaded event as follows:
// retrieve settings
var localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.ContainsKey("sounds"))
{
clsGlobal.statModel.Sounds = (bool)localSettings.Values["sounds"];
}
And when I play a sound, a simple if condition is included:
if (clsGlobal.statModel.Sounds && clsGlobal.fileInputs.ContainsKey("problem.wav"))
{
var snd1 = clsGlobal.fileInputs["problem.wav"];
if (snd1 != null)
{
snd1.Reset();
snd1.Start();
}
}
I am using the AudioGraph API for my sounds. Works better than the MediaPlayer route since that was giving me a weird situation where the sounds would not play sometimes on the first request. AudioGraph works better for me and is really fast to play sounds.
Upvotes: 0
Reputation: 15758
MediaElement is a XAML control, to make MediaElement.IsMuted property work, we need to add MediaElement
into Visual Tree. For example, in your code, we can change BackgroundSound
to a public field like:
public static readonly MediaElement BackgroundSound = new MediaElement();
And then in a page (e.g. MainPage) add it to the page:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await AudioManager.StartSoundManager();
rootGrid.Children.Add(AudioManager.BackgroundSound);
}
After this, your ToggleSounds
method should be able to work.
But since you want to keep on playing in every page, add MediaElement
into the page may be not a good practice, here I'd suggest you use MediaPlayer class instead of MediaElement like:
public static class AudioManager
{
public const string BACKGROUND = "BACKGROUND.mp3";
private static readonly MediaPlayer BackgroundSound = new MediaPlayer();
public static void StartSoundManager()
{
BackgroundSound.Source = MediaSource.CreateFromUri(new Uri($"ms-appx:///Assets/Audio/{BACKGROUND}"));
BackgroundSound.IsLoopingEnabled = true;
ToggleSounds();
BackgroundSound.Play();
}
public static void ToggleSounds()
{
BackgroundSound.IsMuted = !Settings.IsAudioOn; // IsAudioOn is false, still the sound plays
}
}
For more info, please see Play audio and video with MediaPlayer.
Upvotes: 1