Search code examples
c#.netmauimaui-windows

Sound not being played at the end of timer .NET MAUI


I have a piece of code at which when a timer runs out, a sound is played. This is done through this package Plugin.SimpleAudioPlayer. This is portrayed by the PlaySound function. The issue is when it reaches the end of the timer and tries to play the sound I get thie error on var player (check code below): System.NotImplementedException: 'This functionality is not implemented in the .NET standard version of this assembly. Reference the NuGet package from your platform-specific (head) application project in order to reference the platform-specific implementation.' . If there are better ways to achieve this please let me know.

Code:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Microsoft.Maui.Controls;
using Plugin.SimpleAudioPlayer;

namespace CookOff.Models
{
    public class Step : INotifyPropertyChanged
    {
        private bool isSelected;
        private TimeSpan timer;
        private bool isTimerRunning;
        private bool isTimerPaused;
        private TimeSpan originalTimer;

        public int RecipeID { get; set; }
        public string Description { get; set; }
        public bool TimerRequired { get; set; }
        public TimeSpan Timer
        {
            get => timer;
            set
            {
                timer = value;
                OnPropertyChanged();
            }
        }
        public bool IsSelected
        {
            get => isSelected;
            set
            {
                isSelected = value;
                OnPropertyChanged();
            }
        }

        public ICommand StartTimerCommand { get; }
        public ICommand PauseTimerCommand { get; }
        public ICommand StopTimerCommand { get; }

        public Step()
        {
            StartTimerCommand = new Command(StartTimer);
            PauseTimerCommand = new Command(PauseTimer);
            StopTimerCommand = new Command(StopTimer);
        }

        public Step(int recipeID, string description, bool timerRequired, TimeSpan timer)
        {
            RecipeID = recipeID;
            Description = description;
            TimerRequired = timerRequired;
            Timer = timer;

            StartTimerCommand = new Command(StartTimer);
            PauseTimerCommand = new Command(PauseTimer);
            StopTimerCommand = new Command(StopTimer);
        }

        private void StartTimer()
        {
            if (!isTimerRunning || isTimerPaused)
            {
                isTimerRunning = true;
                isTimerPaused = false;
                originalTimer = Timer;
                Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    if (!isTimerRunning)
                        return false;

                    Timer = Timer.Subtract(TimeSpan.FromSeconds(1));
                    if (Timer <= TimeSpan.Zero)
                    {
                        Timer = TimeSpan.Zero;
                        isTimerRunning = false;
                        // PLAY SOUND WHEN TIMER RUNS OUT
                        PlaySound();
                    }
                    return isTimerRunning;
                });
            }
        }

        private void PauseTimer()
        {
            isTimerPaused = true;
            isTimerRunning = false;
        }

        private void StopTimer()
        {
            isTimerRunning = false;
            isTimerPaused = false;
            Timer = originalTimer;
        }

        private void PlaySound() //ISSUE HERE
        {
            var player = CrossSimpleAudioPlayer.Current;
            player.Load("Resources/Raw/timer_end.mp3");
            player.Play();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

UPDATE FIXED:

Thanks Jason for the tip to use Plugin.Maui.Audio. I have used the straighforward implementation as on their GitHub.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Microsoft.Maui.Controls;
using Plugin.Maui.Audio;

namespace CookOff.Models
{
    public class Step : INotifyPropertyChanged
    {
        private bool isSelected;
        private TimeSpan timer;
        private bool isTimerRunning;
        private bool isTimerPaused;
        private TimeSpan originalTimer;

        public int RecipeID { get; set; }
        public string Description { get; set; }
        public bool TimerRequired { get; set; }
        public TimeSpan Timer
        {
            get => timer;
            set
            {
                timer = value;
                OnPropertyChanged();
            }
        }
        public bool IsSelected
        {
            get => isSelected;
            set
            {
                isSelected = value;
                OnPropertyChanged();
            }
        }

        public ICommand StartTimerCommand { get; }
        public ICommand PauseTimerCommand { get; }
        public ICommand StopTimerCommand { get; }

        public Step()
        {
            StartTimerCommand = new Command(StartTimer);
            PauseTimerCommand = new Command(PauseTimer);
            StopTimerCommand = new Command(StopTimer);
        }

        public Step(int recipeID, string description, bool timerRequired, TimeSpan timer)
        {
            RecipeID = recipeID;
            Description = description;
            TimerRequired = timerRequired;
            Timer = timer;

            StartTimerCommand = new Command(StartTimer);
            PauseTimerCommand = new Command(PauseTimer);
            StopTimerCommand = new Command(StopTimer);
        }

        private void StartTimer()
        {
            if (!isTimerRunning || isTimerPaused)
            {
                isTimerRunning = true;
                isTimerPaused = false;
                originalTimer = Timer; // Store the original time when the timer starts
                Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    if (!isTimerRunning)
                        return false;

                    Timer = Timer.Subtract(TimeSpan.FromSeconds(1));
                    if (Timer <= TimeSpan.Zero)
                    {
                        Timer = TimeSpan.Zero;
                        isTimerRunning = false;
                        // Play sound
                        PlaySound();
                    }
                    return isTimerRunning;
                });
            }
        }

        private void PauseTimer()
        {
            isTimerPaused = true;
            isTimerRunning = false;
        }

        private void StopTimer()
        {
            isTimerRunning = false;
            isTimerPaused = false;
            Timer = originalTimer; 
        }

        private async void PlaySound()
        {
            try
            {
                Debug.WriteLine("Attempting to play sound in PlaySound method");

                // STRAIGHTFORWARD AUDIO PLAYER
                var audioPlayer = AudioManager.Current.CreatePlayer(await FileSystem.OpenAppPackageFileAsync("Resources/Raw/timer_end.mp3"));

                if (audioPlayer == null)
                {
                    Debug.WriteLine("AudioPlayer creation failed");
                    return;
                }

                audioPlayer.Play();
                Debug.WriteLine("Sound played");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Exception in PlaySound method: {ex.Message}");
                Debug.WriteLine(ex.StackTrace);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


Solution

  • UPDATE FIXED:

    Thanks Jason for the tip to use Plugin.Maui.Audio. I have used the straighforward implementation as on their GitHub.

    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Windows.Input;
    using Microsoft.Maui.Controls;
    using Plugin.Maui.Audio;
    
    namespace CookOff.Models
    {
        public class Step : INotifyPropertyChanged
        {
            private bool isSelected;
            private TimeSpan timer;
            private bool isTimerRunning;
            private bool isTimerPaused;
            private TimeSpan originalTimer;
    
            public int RecipeID { get; set; }
            public string Description { get; set; }
            public bool TimerRequired { get; set; }
            public TimeSpan Timer
            {
                get => timer;
                set
                {
                    timer = value;
                    OnPropertyChanged();
                }
            }
            public bool IsSelected
            {
                get => isSelected;
                set
                {
                    isSelected = value;
                    OnPropertyChanged();
                }
            }
    
            public ICommand StartTimerCommand { get; }
            public ICommand PauseTimerCommand { get; }
            public ICommand StopTimerCommand { get; }
    
            public Step()
            {
                StartTimerCommand = new Command(StartTimer);
                PauseTimerCommand = new Command(PauseTimer);
                StopTimerCommand = new Command(StopTimer);
            }
    
            public Step(int recipeID, string description, bool timerRequired, TimeSpan timer)
            {
                RecipeID = recipeID;
                Description = description;
                TimerRequired = timerRequired;
                Timer = timer;
    
                StartTimerCommand = new Command(StartTimer);
                PauseTimerCommand = new Command(PauseTimer);
                StopTimerCommand = new Command(StopTimer);
            }
    
            private void StartTimer()
            {
                if (!isTimerRunning || isTimerPaused)
                {
                    isTimerRunning = true;
                    isTimerPaused = false;
                    originalTimer = Timer; // Store the original time when the timer starts
                    Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                    {
                        if (!isTimerRunning)
                            return false;
    
                        Timer = Timer.Subtract(TimeSpan.FromSeconds(1));
                        if (Timer <= TimeSpan.Zero)
                        {
                            Timer = TimeSpan.Zero;
                            isTimerRunning = false;
                            // Play sound
                            PlaySound();
                        }
                        return isTimerRunning;
                    });
                }
            }
    
            private void PauseTimer()
            {
                isTimerPaused = true;
                isTimerRunning = false;
            }
    
            private void StopTimer()
            {
                isTimerRunning = false;
                isTimerPaused = false;
                Timer = originalTimer; 
            }
    
            private async void PlaySound()
            {
                try
                {
                    Debug.WriteLine("Attempting to play sound in PlaySound method");
    
                    // STRAIGHTFORWARD AUDIO PLAYER
                    var audioPlayer = AudioManager.Current.CreatePlayer(await FileSystem.OpenAppPackageFileAsync("Resources/Raw/timer_end.mp3"));
    
                    if (audioPlayer == null)
                    {
                        Debug.WriteLine("AudioPlayer creation failed");
                        return;
                    }
    
                    audioPlayer.Play();
                    Debug.WriteLine("Sound played");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Exception in PlaySound method: {ex.Message}");
                    Debug.WriteLine(ex.StackTrace);
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }