3

Info: I'm creating game using C# in Visual Studio 2017

How can I stop music thread? Is it possible even from different form? I used this code to create thread which plays music in background

MediaPlayer bg;

public void main()
{
    IntializeComponent();
    Bg_music();
}

private void Bg_music()
{
    new System.Threading.Thread(() =>
    {
        bg = new System.Windows.Media.MediaPlayer();
        bg.Open(new System.Uri(path + "Foniqz_-_Spectrum_Subdiffusion_Mix_real.wav"));
        bg.Play();
    }).Start();                        
}

When I try to stop the thread using this code, it stops window which is currently open and music/thread keeps playing music

bg.Dispatcher.Invoke(() =>
{
    bg.Close();
});

also this didn't work

bg.Dispatcher.Invoke(() =>
{
    bg.Stop();
});
Miicat
  • 49
  • 5
  • 8
    First things first, don't use threads anymore, these have been superseeded by TPL `Task`. `Task` have numerous benefits and improvements on managing the `Thread` yourself. – Liam Aug 01 '18 at 13:21
  • Why is it in a separate thread to begin with? Removing the thread will simplify the code, and possibly also solve the issue at hand. – Flater Aug 01 '18 at 13:22
  • Possible duplicate of [How do I abort/cancel TPL Tasks?](https://stackoverflow.com/questions/4783865/how-do-i-abort-cancel-tpl-tasks) – Liam Aug 01 '18 at 13:22
  • 1
    Don't use a thread at all. `Play()` won't block the UI – Panagiotis Kanavos Aug 01 '18 at 13:22
  • I'm guessing @Flater (as this is a game) so that it doesn't lock the UI thread – Liam Aug 01 '18 at 13:22
  • @Liam: Why is a task needed at all here? Media players inherently don't block the UI. – Flater Aug 01 '18 at 13:22
  • Not sure, I'm just saying that why I guess the OP is using a thread here. I don't write games... – Liam Aug 01 '18 at 13:23
  • @Liam: Why tell OP to use tasks if you don't know why they are needed in the first place? It seems like you're blindly pasting a "convert threads to tasks!" comment before even checking if it's applicable to the question at hand. – Flater Aug 01 '18 at 13:24
  • 1
    @Miicat What are you trying to do? `Play()` won't block and you are better of using the MediaPlayerElement tag anyway. Check [Play audio and video with MediaPlayer](https://learn.microsoft.com/el-gr/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer) tag anyway – Panagiotis Kanavos Aug 01 '18 at 13:24
  • There is literally no need to use `Thread` anymore. They're just harder to use. `Task` is just better (always) – Liam Aug 01 '18 at 13:25
  • 1
    @Liam Play doesn't block. No tasks are needed. The question is a bit ... unclear – Panagiotis Kanavos Aug 01 '18 at 13:26
  • Looking though OPs question history it seems they are using a thread because [of this](https://stackoverflow.com/questions/6240002/play-two-sounds-simultaneusly). Probably worth pointing out that the [best answer](https://stackoverflow.com/a/6241289/542251) on that is 7 years old! A lot has changed since 2011. – Liam Aug 01 '18 at 13:32
  • @Liam And the author states: *This code demonstrates the two sounds playing on separate threads on top of each other, which is sort of pointless since the playback doesn't block anyway* – Jimi Aug 01 '18 at 15:28
  • Just don't use a thread at all. Your `bg` variable needs to be a field of the class instead of a local variable so you can simply call its Stop() and/or Close() method. Do note that MediaPlayer is not in general good enough in game programming. Okay for plain song playback but it does not have a decent way to mix sound effects. Lots of libraries out there, Bass tends to get mentioned. – Hans Passant Aug 02 '18 at 11:57

2 Answers2

2

Assuming you really need a background thread (because the MediaPlayer it's non-blocking on WPF) you may want to use one of the following paths in C#:

  1. Use Cancelation Token & Tasks:

        MediaPlayer bg;
    readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
    public MainWindow()
    {
        InitializeComponent();
        Bg_music();
    }
    
    private void Bg_music()
    {
    
        Task.Run(() =>
        {
            bg = new MediaPlayer();
            bg.Open(new Uri(@"D:\Songs\201145-Made_In_England__Elton_John__320.mp3"));
            bg.Play();
            bg.Play();
            while (true)
            {
                if (tokenSource.Token.IsCancellationRequested)
                {
                    bg.Stop();
                    break;
                }
            }
    
        }, tokenSource.Token);
    
    }
    
    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
           tokenSource.Cancel();
    }
    

    }

or

  1. Use Events to communicate through Tasks. (Stop using threads, we have tasks now)
Dragos Stoica
  • 1,753
  • 1
  • 21
  • 42
  • Will it continue playing music, if other sound is played at the same time/simultaneously? Here's link to the code how I first solved how to play two sounds simultaneously: https://stackoverflow.com/questions/50425310/how-i-can-play-two-sounds-simultaneously-in-c-sharp – Miicat Aug 02 '18 at 17:08
  • How I can stop it from other form? – Miicat Jan 11 '19 at 16:38
-1

Cross-thread object access might be tricky.

Once you create MediaPlayer instance in another thread other than the UI thread, accessing this object inside the UI thread will throw InvalidOperationException since the object doesn't belong to UI thread.

    private void Bg_music()
    {
        bg = new System.Windows.Media.MediaPlayer();
        new System.Threading.Thread(() =>
        {
            bg.Dispatcher.Invoke(()=>{
                bg.Open(new System.Uri(path + "Foniqz_-_Spectrum_Subdiffusion_Mix_real.wav"));
                bg.Play();
            });

        }).Start();                        
    }

Now you don't have to use Dispatcher to stop the MediaPlayer when calling it inside the UI thread.

Edit: Even if the implemented method is not the best practice, still worth to be answered to advert some theorical information.

Ferhat
  • 19
  • 1