Mac下使用miniaudio播放WAV文件遇AddInstanceForFactory错误及无音频输出的问题咨询
Mac下使用miniaudio播放WAV文件遇AddInstanceForFactory错误及无音频输出的问题咨询
嘿,我来帮你梳理和解决这个问题~
首先说你碰到的那个AddInstanceForFactory错误日志,这个其实是Mac系统音频插件层面的提示,和你的代码、miniaudio库本身都没有关系,它只是系统在加载音频组件时的一个非关键性日志,而且你也发现非debug模式下看不到它,完全不用把精力放在这个上面。
接下来是核心的无音频问题:你加了sleep(10)就能听到声音,本质原因是miniaudio的播放逻辑是异步的——调用ma_device_start()只是启动了后台播放线程,它不会阻塞主线程等待播放完成。你的程序紧接着就执行了ma_device_uninit()和ma_decoder_uninit(),直接把播放设备和解码器资源销毁了,自然听不到声音。
下面给你几个靠谱的等待播放完成的方案,替代不灵活的sleep:
方案1:通过解码器进度等待播放结束
在启动设备后,循环检查解码器已读取的帧数,直到它等于总帧数:
if (ma_device_start(&device) != MA_SUCCESS) { ma_device_uninit(&device); ma_decoder_uninit(&decoder); return; } // 等待播放完成 ma_uint64 totalFrames = ma_decoder_get_length_in_pcm_frames(&decoder); ma_uint64 framesRead = 0; while (framesRead < totalFrames) { ma_decoder_get_cursor_in_pcm_frames(&decoder, &framesRead); // 加10ms延迟避免CPU空转 ma_sleep(10); } ma_device_uninit(&device); ma_decoder_uninit(&decoder);
方案2:用回调标记播放完成
在数据回调函数里判断是否已读完所有音频帧,标记播放状态,主线程等待这个标记:
// 自定义结构体传递播放状态 typedef struct { ma_decoder* pDecoder; bool isPlaybackFinished; } PlaybackData; void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount){ PlaybackData* pData = (PlaybackData*)pDevice->pUserData; if (pData == NULL || pData->pDecoder == NULL) { return; } ma_uint32 actualFramesRead; ma_decoder_read_pcm_frames(pData->pDecoder, pOutput, frameCount, &actualFramesRead); // 读到的帧数小于请求数,说明播放完毕 if (actualFramesRead < frameCount) { pData->isPlaybackFinished = true; ma_device_stop(pDevice); // 主动停止设备 } (void)pInput; } void process() { ma_result result; ma_decoder decoder; ma_device_config deviceConfig; ma_device device; PlaybackData playbackData; result = ma_decoder_init_file("<path to wav file>", NULL, &decoder); if (result != MA_SUCCESS) { return; } playbackData.pDecoder = &decoder; playbackData.isPlaybackFinished = false; deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.format = decoder.outputFormat; deviceConfig.playback.channels = decoder.outputChannels; deviceConfig.sampleRate = decoder.outputSampleRate; deviceConfig.dataCallback = data_callback; deviceConfig.pUserData = &playbackData; if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { ma_decoder_uninit(&decoder); return; } if (ma_device_start(&device) != MA_SUCCESS) { ma_device_uninit(&device); ma_decoder_uninit(&decoder); return; } // 等待播放完成标记 while (!playbackData.isPlaybackFinished) { ma_sleep(10); } ma_device_uninit(&device); ma_decoder_uninit(&decoder); }
方案3:等待用户输入(适合测试场景)
如果只是简单测试,可以让主线程等待用户输入(比如按回车)再退出,手动控制播放时长:
if (ma_device_start(&device) != MA_SUCCESS) { ma_device_uninit(&device); ma_decoder_uninit(&decoder); return; } printf("按回车键停止播放...\n"); getchar(); // 阻塞等待用户输入 ma_device_uninit(&device); ma_decoder_uninit(&decoder);
另外结合你的更新信息:所有初始化和启动调用都成功,说明你的WAV文件路径正确、设备配置没问题,核心矛盾就是程序没有等待播放完成就提前销毁了资源,用上上面的任意一种方案就能解决啦。
备注:内容来源于stack exchange,提问作者bourne
相关产品推荐
相关产品推荐

