转: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实现一个正弦波发生器,涵盖双缓冲区机制、相位连续性处理等工程实践,为音频编程和信号处理应用提供基础框架。 阅读详情

相关推荐

为何LPDDR4支持on-die ECC,但是DDR4却不支持呢?

DRAM的ECC,目前的编码方式都是128bit data,产生8bit parity或者ECC code. 而且必须要128bit才行。这8bit的ECC code是要被写入到DRAM内存里面的,从而read的时候,可以读取这8bit ECC code来判定read data是否有错,如果是SBF,就可以纠错了,如果是double bit,大部分时候是可以detect到错误,即所谓的SEC(Single Error Correct) + DED(Double Error Detect).

一个DRAM从业者的告白 1556

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

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

bloghome的专栏 1026

【Allegro学习笔记】常规标贴封装创建-0402封装创建实例

摘要 本文主要介绍如何使用Allegro制作表面贴装封装。 所使用的软件 使用Allegro制作常规贴片封装主要使用的软件有Pad Designer和Allegro 1 0402类封装制作 1.1 0402类封装焊盘分析 0402封装尺寸图如图1...

Honglong 1万+

WinAPI: waveOutReset - 重置输出

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

weixin_33728268的博客 131

STM32 USB2.0 转 Type-C 接口设计与实现

本文详细介绍了STM32 USB2.0转Type-C接口的设计与实现方案,涵盖硬件电路设计、软件配置及调试技巧。重点解析Type-C接口的CC引脚配置和电源管理,提供设备模式、主机模式及双角色模式的实现方法,帮助开发者解决实际应用中的连接稳定性和ESD防护等问题,提升产品可靠性和兼容性。

blockchain9miner的博客 1020

Android功耗系列专题理论之二十一:Power Monitor测功耗详细说明和注意事项

本文详细介绍了PowerMonitor手机功耗测试仪的功能与使用方法。该设备通过硬件连接替代手机电池,实时监测电流、电压等参数,适用于研发测试、软件优化等场景。文章包含设备接线说明(电源、USB、手机供电等接口)、驱动安装步骤及常见问题排查,并详细讲解了功耗测量操作流程,包括电压设置、开机步骤、数据采集与导出方法。特别强调了测量注意事项,如固定屏幕亮度、关闭后台应用、确保稳定连接等,以确保测试数据准确性。最后提供了简易测量步骤和详细测量流程指导。

600

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

【目标检测-YOLO】YOLOv5-v5.0-yolov5s网络架构详解(第一篇)

源码:GitHub - ultralytics/yolov5 at v5.0 由于YOLO v5 代码库在持续更新,如上图,有多个版本,每个版本的网络结构不尽相同。以下内容以 v5.0 为准,网络结构选用 yolov5s。 为了方便画图和理解网络结构,选用可视化工具:Netron 网页版进行可视化, 然后使用PPT作图。 在Releases · ultralytics/yolov5 · GitHub找到 v5.0中的Assets 中的yolov5s.pt并下载该权重。 下图为直接......

博观约取,厚积薄发 2万+

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

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

weixin_28699741的博客 1044

Claude Code 100个真实案例 - 用AI设计Arduino PCB电路板(硬件小白也能画板)

本案例展示如何使用 Claude Code 配合 KiCad 的 Python 脚本接口,从零设计一块 Arduino 传感器扩展板 PCB。从原理图符号创建、网表生成到 PCB 布局布线,全程自动化完成,最终输出可直接发给工厂打样的 Gerber 文件。

yueyeguzhuo的专栏 442

SAR成像专栏目录

为方便大家阅读,我做了一个专栏目录,蓝色字有超链接,可以直接打开。 本专栏默认读者已具备雷达系统的基本知识或者已阅读过雷达导论专栏中的文章。 1. 概述 SAR成像概述 星载SAR的各项指标解读(史上最全) SAR成像算法的实现途径与算力分析 2. SAR成像原理与SAR系统简介 雷达与分辨率 SAR成像原理与方法 SAR图像的形成和处理 SAR系统设计 3. 点目标仿真 点目标仿真(一)—— 数学模型 点目标仿真(二)—— Matlab仿真 4. 成像算法 更新中 雷达导论专

7471

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

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

weixin_33953249的博客 184

2026数学建模国赛D题:时频冲突检测与消解 论文解析

最终无需撤销任何计划,共调整110个计划,其中频移43个、时移48个、间隔调整19个,总调整幅度528。附件模板只要求填写新增计划的频段区间和首次时间区间,没有要求填写宽度、间隔和次数,因此本文按附件中C类装备的统一需求特征处理:每个新增计划占用3个连续频段,持续2个时间单位,间隔8,使用12次。本文针对有限频带内大量周期性用频计划的时频冲突检测、单参数消解、无冲突条件下新增C类计划装载,以及允许调整间隔时长后的再次消解问题,建立了由占用展开、冲突图、组合动作集、精确约束满足和二维资源装箱组成的统一模型。

YOLO 190

【转】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

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

waveOutReset 停止播放并重置管理器

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

Lisa的专栏 2020

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

关于waveInReset/waveOutReset锁死问题

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

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

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、付费专栏及课程。

余额充值