WinForm 如何检测音频播放完成并自动播放下一个音频

148 阅读2分钟

前言

程序在预警时,会发出报警音,当报警音频播放时间,超过预警频率时,就会像我们打印文档一样,像打印机发送10次打印任务。

当打出第1张纸的时候,这时候想取消打印。就不能在电脑端通过软件操作了。

因此为了避免这种事情发生,就只有等打印机打完一张,再发下一个任务。这样的话,可以随时发起取消打印任务。

如果实现在报警音频结束前,不再给任务。

正文

SoundPlayer

在C#中,SoundPlayer 类本身没有直接提供事件或属性来检测音频是否播放完成。

不过,你可以通过以下方法来实现这一功能:PlaySync 方法会阻塞当前线程,直到音频播放完成。

你可以将播放操作放在一个单独的线程中,以避免阻塞主线程。 满足不了我想要的功能

using System;
using System.Media;
using System.Threading;

class Program
{
    static void Main()
    {
        string[] audioFiles = { "audio1.wav", "audio2.wav", "audio3.wav" };
        SoundPlayer player = new SoundPlayer();

        foreach (string file in audioFiles)
        {
            //TODO 如果任务取消,break 跳出循环
            player.SoundLocation = file;
            player.Load(); // 加载音频文件
            player.PlaySync(); // 阻塞播放,直到当前音频播放完成
            Console.WriteLine($"播放完成: {file}");
        }

        Console.WriteLine("所有音频播放完成");
    }
}

优点:

实现简单,代码直观。

不需要额外的事件处理。

缺点:

PlaySync会阻塞当前线程,可能导致UI线程卡住(如果是在UI线程中运行)。

NAudio

NAudio库提供了更强大的音频处理功能,可以通过PlaybackStopped事件来实现连续播放

NAudio 中,WaveOutEvent 是一个用于播放音频的类,它封装了底层的音频设备资源。如果在使用完毕后没有调用 Dispose() 方法,垃圾回收器(GC)会在对象被回收时调用其析构函数(Finalize),但此时可能已经无法正确释放资源,从而导致错误。

using System;
using System.Collections.Generic;
using NAudio.Wave;

public class MyForm : Form
{
    private Label myLabel;

    public MyForm()
    { 
 
    }
    
    WaveOutEvent waveOut;
    
    List<string> audioFiles = new List<string> { "audio1.wav", "audio2.wav", "audio3.wav" };
    
    private void OnLineCustodyOrderFrm_Load(object sender, EventArgs e)
    {
        waveOut = new WaveOutEvent();
        waveOut.PlaybackStopped += WaveOut_PlaybackStopped;
        PlayNextAudio();
    }   

    private void WaveOut_PlaybackStopped(object sender, StoppedEventArgs e)
    {
        //播放结束,要释放资源
        if (waveOut != null && waveOut.PlaybackState == PlaybackState.Stopped)
        {
            waveOut.Dispose();
        }
        Console.WriteLine($"播放完成: {audioFiles[currentIndex - 1]}");
        PlayNextAudio();
    }
    
    private void PlayNextAudio()
    {
        if (currentIndex < audioFiles.Count)
        {
            var audioFile = new AudioFileReader(audioFiles[currentIndex]);            
            waveOut.Init(audioFile);
            waveOut.Play();
            Console.WriteLine($"开始播放: {audioFiles[currentIndex]}");
            currentIndex++;
        }
        else
        {
            Console.WriteLine("所有音频播放完成");
        }
    }

    private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        //窗体关系,要释放资源
        if (waveOut != null)
        {
            waveOut.Stop();
            waveOut.Dispose(); // 确保控件被释放
            waveOut = null; // 防止重复释放和内存泄漏问题
        }
    }
}

关键点

显式释放资源

在每次音频播放完成后,调用 waveOut.Dispose() 释放当前的 WaveOutEvent 对象。

在程序退出前,确保释放所有资源。

重新创建 WaveOutEvent

每次播放新的音频文件时,重新创建一个新的 WaveOutEvent 对象,而不是复用之前的对象。

释放 AudioFileReader

如果使用了 AudioFileReader,也需要确保在播放完成后释放它。

总结

WinForm 中实现音频播放完成检测并自动播放下一个音频,可以使用SoundPlayer或NAudio库。

通过PlaybackStopped事件检测播放完成,并结合音频文件列表实现自动播放下一个音频。

优化方面可添加异常处理、播放控制按钮等功能,提升用户体验。代码简洁高效,易于扩展。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:VipSoft

出处:cnblogs.com/vipsoft/p/18711375

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!