转:waveOutReset的N种死法, 及其解决方案

waveInReset/waveOutReset死锁原因与解决方案 问题背景 录音播音实际需求1、随时终止2、录音并非文件,而是形成rtp发送3、播音并非源于文件,而是源于rtp 因此Waveform audio使用的buffer较小,不断的装载/发送 buffer,终止的时候Reset并且close.大致如下调用的循环 录音waveInUnprepareHeaderwaveInPrepareHeaderwa 阅读详情

waveOutReset的N种死法, 及其解决方案
2009年06月08日 星期一 13:14

我遭遇到了调用waveOutReset死锁的问题,在GOOGLE上一搜,遇到同样问题的人还真不少,但没有人很明确地找到造成DEADLOCK的原因,都是糊里糊涂就把问题解决了,然后把运行OK的代码一贴完事。我花了四五个小时才彻底摸清楚规律,把这经验拿出来共享

原则:
(1) waveOutReset不是立即返回的函数, 而需要等待驻留在WAVEDEV里的音频BUFFER全部标记为WOM_DONE,经过callback proc处理完毕后, waveOutReset才会返回. 
(2) 在waveOutReset调用到返回之间的这段时间内, 禁止任何线程对处于reset中的HWAVEOUT调用任何WAVE API, 否则立刻造成死锁.

把握住这两个原则就可以根治waveOutReset死锁问题了. 不过为了把事情描述得更具体些, 我把网上多数人造成死锁的情况列一下, 并给出解决方法

第一种死法:
在回调处理函数WaveCallbackFunc中,对标记为WOM_DONE的BUFFER进行waveOutUnprepareHeader

错误分析:
调用waveOutReset后, 系统内所有未播放的buffer全部被标记为WOM_DONE返回给WaveCallbackFunc, 这属于waveOurReset处理过程的一部分, 此时waveOurReset还未返回. 所以这时如果调用到waveOutUnprepareHeader, 就会立刻造成死锁. 我自己也是犯的这个错误。

解决方法:
在调用waveOurReset之前设置一个FLAG, 然后在WaveCallbackFunc里要调用waveOutUnprepareHeader之前判断一下这个FLAG, 如果处于reset过程中就跳过waveOutUnprepareHeader. 范例代码:

static CRITICAL_SECTION g_CS;
static BOOL g_bResetting = FALSE;

void Reset()
{
        EnterCriticalSection(&g_CS); //之前InitializeCriticalSection一下
        g_bResetting = TRUE;
        LeaveCriticalSection(&g_CS);
        
        waveOutReset();

        g_bResetting = FALSE; //RESET后就不会调WaveCallbackFunc了,所以不需要锁
}

VOID CALLBACK WaveCallbackFunc(HWAVEOUT hwo, UINT32 uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
       EnterCriticalSection(&g_CS);   //防止g_bResetting在if判断之后, waveOutUnprepareHeader之前被设成1了, callback和reset处于不同线程
        
        if( (uMsg == WOM_DONE) && !g_bResetting )
        {
                waveOutUnprepareHeader(hWaveOut, pWaveHdr, sizeof(WAVEHDR));
        }
        
        LeaveCriticalSection(&g_CS);
}
        
另外, 如果使用了每个BUFFER定长的BUFFER-CHAIN来做生产者-消费者模型, 那么在BUFFER-CHAIN初始化的时候顺便把所有WAVEHDR都PREPARE好, 而只在BUFFER-CHAIN全部释放的时候才做UNPREPARE, 那么在每次waveOutWrite和WOM_DONE的循环里就不需要PREPARE/UNPREPARE了,这也能避开上述情况造成的死锁


第二种死法: 某些人喜欢在在回调处理函数WaveCallbackFunc中,调用waveOutWrite往系统里填充新BUFFER.
错误分析: 同情况一, 在waveOutReset过程中,如果WaveCallbackFunc调用了waveOutWrite, 同样会造成死锁.
解决方法: 同情况一, 设置FLAG和临界区配合来防止. 不过比较建议在另外的线程中调waveOutWrite写入BUFFER, 这才符合生产-消费模型.

第三种死法: 在另外一个线程中调用waveOurWrite, 但是waveOutReset之前, 没有停下那个线程
错误分析: RESET过程中,还有waveOurWrite调用
解决方法: 把waveOurWrite那个线程suspend或退出, 或者在waveOutWrite前面用FLAG+临界区判断

第四种死法: 也是最匪夷所思的死法, 从UI的某个按钮一路调用到waveOutReset(处于同线程中), 而在WaveCallbackFunc中,同线程调用SetWindowText之类UI函数
错误分析: 事实是:
(1) 如果是在WindowProc的某个CASE里调用SetWindowText, 调用者和SetWindowText处于同线程中,那么运行正常, 多数UI也都会这么写;
(2) 如果处于Thread1的UI调用了waveOutReset, 导致处于Thread2中的WaveCallbackFunc运行并调用SetWindowText, 试图设置处于Thread1的UIcallbackProc, 那么SetWindowText会死锁, 导致WaveCallbackFunc死掉, 最后表面上看起来就是waveOutReset死掉.其实我也不明白为什么这样也能死,要问就去问盖茨大叔吧.
解决方法:
在WaveCallbackFunc中,用RESET FLAG + 临界区的方法保护UI调用函数, 使其在waveOutReset过程中不被调用, 或者用PostMessage这样的异步函数,实在不得不同步影响UI的话就忍一忍等waveOurReset函数返回后再做吧.

 

程序在放音的同时,一旦通过系统的调音量键改变音量大小,程序就会死掉,这和什么有关系?

C++实现声卡正弦波发生器:从DSP原理到WaveOut实战 数字信号处理(DSP)是连接数字世界与模拟世界的核心技术,其核心原理是通过采样与量化将连续信号转换为离散数据。在音频领域,这一技术使得计算机能够生成和处理声音信号,广泛应用于音频测试、通信仿真和嵌入式系统开发。通过理解奈奎斯特采样定理和PCM编码原理,开发者可以构建高精度、低延迟的实时音频应用。本文以声卡作为硬件载体,深入探讨如何利用C++和Windows原生API实现一个正弦波发生器,涵盖双缓冲区机制、相位连续性处理等工程实践,为音频编程和信号处理应用提供基础框架。 阅读详情

相关推荐

微纳加工技术中的自对准硅化物(Silicide)工艺:关键步骤与应用场景解析

本文深入解析了微纳加工技术中的自对准硅化物(Silicide)工艺,详细介绍了其关键步骤与应用场景。从表面清洁、金属沉积到两步退火法,全面拆解工艺全流程,并探讨了不同技术节点下的工艺演进。文章还提供了实际应用中的问题排查方法和新兴技术对Silicide工艺的挑战,为芯片制造领域的工程师提供了实用参考。

weixin_30613727的博客 431

waveOutReset的N种死法, 及其解决方案

我遭遇到了调用waveOutReset死锁的问题,在GOOGLE上一搜,遇到同样问题的人还真不少,但没有人很明确地找到造成DEADLOCK的原因,都是糊里糊涂就把问题解决了,然后把运行OK的代码一贴完事。我花了四五个小时才彻底摸清楚规律,把这经验拿出来共享原则:(1) waveOutReset不是立即返回的函数, 而需要等待驻留在WAVEDEV里的音频BUFFER全部标记为

bloghome的专栏 1026

遥感图像融合实战:5分钟搞懂全色与多光谱图像如何提升分辨率(附Python代码)

本文通过实战案例,详细解析了如何利用全色锐化技术融合全色与多光谱遥感图像,以提升图像分辨率。文章深入浅出地介绍了核心概念、环境配置、经典GS融合算法的Python代码实现,并对比了不同算法的优劣,最后提供了效果评估方法与实战陷阱分析,帮助读者快速掌握遥感图像融合的关键技术。

weixin_29041195的博客 394

WinAPI: waveOutReset - 重置输出

提示: 函数会终止输入, 位置清0; 放弃未处理的缓冲区并返回给程序. //声明: waveOutReset( hWaveOut: HWAVEOUT {设备句柄} ): MMRESULT; {成功返回 0; 可能的错误值见下:} MMSYSERR_INVALHANDLE = 5; {设备句柄无效} MMSYSERR_HANDLEBUSY = 12; ...

weixin_33728268的博客 131

Anolis龙蜥内核升级实战:从查询到配置的全流程指南

本文提供了一份详尽的Anolis龙蜥操作系统内核升级实战指南。文章从升级的必要性出发,逐步讲解了升级前的系统检查与备份、从官方源获取正确内核包、分步安装与验证、配置默认启动项以及升级后的功能验证与安全回滚方案。旨在帮助运维人员安全、平稳地完成内核升级,以获取性能提升、新硬件支持及重要的安全漏洞修复。

qq_27496129的博客 572

OpenWRT端口转发与NAT环回冲突的排查与解决

本文详细解析了OpenWRT路由器中端口转发与NAT环回功能冲突导致的内网访问故障。通过生活化类比阐明两者工作原理,提供从基础诊断到内核参数调整、LuCI选项配置及手动编写iptables规则的多套解决方案,并给出进阶排查思路,帮助用户彻底解决内网无法通过公网地址访问服务的常见问题。

weixin_29243279的博客 507

waveOutReset

The waveOutReset function stops playback on the given waveform-audio output device and resets the current position to zero. All pending playback buffers are marked as done (WHDR_DONE) and returned to ...

wmnmtm的专栏 205

【AI Agent 实战】OpenClaw 全面解析 + 全平台一键部署教程(本地 AI 智能体)

本文收录于 AI 智能体 & 自动化实战系列,手把手带你从零部署本地可控的 AI 执行助手关键词:OpenClaw、AI Agent、本地 AI 部署、自动化助手、Docker 部署

爱人爱己,风生水起 7954

C语言里的out函数,c语言 vc 用waveout函数写wave文件播放器

用WaveOut函数写wave文件播放器要炒菜的话,就得先准备工具,如锅、铲子、炉灶等。对程序来说,就是各种函数的应用。WaveOut函数在windowsAPI中属于低阶接口,用来播放的话需要用到下面几个:waveOutOpen – 打开波形输出设备waveOutPrepareHeader – 准备播放缓冲区waveOutUnprepareHeader – 取消播放缓冲区waveOutWrite ...

weixin_28699741的博客 1044

Python模拟发送SOME/IP消息(Scapy模块)

SOMEIP提供服务、订阅、响应、通知等Python代码示例

liluo0815481的博客 3069

【零基础入门unity游戏开发——3D篇】3D物理关节 —— Joint相关组件

【零基础入门unity游戏开发——3D篇】3D物理关节 —— Joint相关组件

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1202

转载 waveOutReset的N种死法, 及其解决方案

为什么80%的码农都做不了架构师?>>> ...

weixin_33953249的博客 184

小波变换(深入浅出)

小波变换

weixin_46713695的博客 3万+

【转】waveOutReset的N种死法, 及其解决方案

【转】waveOutReset的N种死法, 及其解决方案 2011-11-16 20:43 http://www.cnblogs.com/walzer/archive/2007/12/17/1002800.html Posted on 2007-12-17 12:05 Walzer 我遭遇到了调用waveOutReset死锁的问题,在GOOGLE上一搜,遇到同样

aristolto的专栏 1452

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

waveOutReset 停止播放并重置管理器

原则:(1) waveOutReset不是立即返回的函数, 而需要等待驻留在WAVEDEV里的音频BUFFER全部标记为WOM_DONE,经过callback proc处理完毕后, waveOutReset才会返回. (2) 在waveOutReset调用到返回之间的这段时间内, 禁止任何线程对处于reset中的HWAVEOUT调用任何WAVE API, 否则立刻造成死锁.把握住这两个

Lisa的专栏 2020

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

关于waveInReset/waveOutReset锁死问题

在调用waveInReset/waveOutReset期间,系统调用了回调函数,如果设置bStop标志,使回调函数在这时什么都不做直接返回,问题就解决了。          注意,发出了停止指令后,回调函数所做的第一件事就是返回,哪怕做了一件与声音无关的事,也要产生意外 。

星星之火,可以燎原!...... 1940

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++ 使用waveOut实现声音播放

在Windows上实现声音播放比较简单的方法是使用winmm,其中的waveOut模块就可以打开声音设备,播放PCM数据。本文将介绍waveOut声音播放的具体实现,其实现相较于waveIn的采集简单很多,不需要通过开启子线程避免死锁,对于消息也只需要监听WOM_DONE。

codeofcc的博客 3915

NAudio用法详解(4)底层库详解_waveOutOpen

本篇翻译自以下地址: https://docs.microsoft.com/zh-cn/windows/win32/api/mmeapi/nf-mmeapi-waveoutopen 为了便于大家批评指正,原文大部分并未删除。为了简单理解,有些复杂的描述,并未翻译,大部分情况下不影响使用。方框内的内容为本人额外的补充说明。 The waveOutOpen function opens the given waveform-audio output device for playback. waveOutOpe

赵解放的专栏 2670

VC中用低级音频函数WaveX播放声音

Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。1. 播放声音文件的其它方法  在介绍wavex系列之前,我先来介绍之外的其它几种方法:  1.1 MCI方法简介  用MCI方法是很方便的,它对媒体设备控制主要通过命令接口函数mciSendCommand()

seawt的专栏 1288

WaveOut播放声音死锁问题原因

1.首先我们复习下造成死锁的几个充要条件: 1)互斥:互斥资源,只能被一个进程使用 2)不剥夺:非抢占式调度,不能强行抢用其他进程资源 3)请求和保持:占有着资源不释放,同时申请其他资源 4)环路等待:没什么可说的在WaveOutReset时回调函数内调用waveout函数,极易发生死锁。 首先假设我们播放缓冲区有三个语音包, 线程1: waveOutReset();

qq422243639的博客 1428

waveOutReset锁死问题

今天想利用waveOutReset实现停止放音的功能,但是之前只要此函数经调用就会出现死锁,上网找了一大堆资料都没能解决这个问题。 后面发现在回调函数中不能有wave函数(如waveOutClose...)的相关操作,否则会导致死锁,具体原因不明。 void CSoundBase::OnWOM_DONE(WPARAM wParam, LPARAM lParam) { // 回调函数waveOu

skywalker_leo的专栏 2340
上一篇: 二叉树遍历_常数空间
下一篇: 转:好文章《 Linux 平台下多线程编程的高效开发经验》
KWHOK
博客等级 码龄20年 6粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值