Qt - 如何同时录制和播放声音
我在Qt论坛上发布了这个问题,但没有得到答案。这就是我将其发布在这里的原因。
我想知道有没有办法在Qt中同时录制和播放声音。我想从麦克风录制声音,同时我想在扬声器/耳机中播放它。
Qt 有什么办法可以做到这一点吗?或者我需要使用其他库吗?
如果解决方案是跨平台的,那就太好了(我需要覆盖windows、linux和mac)。如果不可能,那么 Linux 解决方案就可以了。
顺便说一句,我正在使用 Qt 4.7。
编辑
此处给出了我的最新实现。我创建了 QIODevice 的子类并重新实现了其 < a href="https://doc.qt.io/qt-5/qiodevice.html#writeData" rel="nofollow noreferrer">writeData 和 readData 方法,以便可以使用循环缓冲区进行读写。我已按照此建议执行此操作。此代码也不起作用,因为 QAudioOutput 实例面临 Underrun错误
,根据此文档表示-
音频数据没有以足够快的速率传送到音频设备
我已经应用了一个 hack 来暂时解决这个问题。在 outputStateChanged
方法中,我检查输出状态是否已更改为 IDLE
,如果已更改,我将再次调用 start()< /code> 方法,指定公共缓冲区。我不想使用它作为永久解决方案,因为它感觉真的很糟糕,而且因为我在没有正确调查其原因的情况下吞下了一个错误。
我应该怎么做才能解决这个问题?
我还尝试使用 Phonon 解决这个问题,但失败了,因为我不对这个模块有足够的了解。
I posted this question on the Qt forum, but got no answers. That's why I am posting it here.
I wanted to know is there any way to record and play sound at the same time in Qt. I want to record sound from a microphone and at the same time I want to play it in the speaker/headphone.
Is there any way to do this in Qt? Or do I need to use any other library?
It would be great if the solution is cross-platform (I need to cover windows, linux and mac). If it isn't possible, then a linux solution will do.
I am using Qt 4.7 by the way.
Edit
My latest implementation is given here. I have created a sub-class of the QIODevice and re-implemented its writeData and readData method so that reading and writing can be done with a circular buffer. I have done this as per this suggestion. This code also doesn't work because the QAudioOutput instance faces Underrun Error
, which according to this documentation means -
Audio data is not being fed to the audio device at a fast enough rate
I have applied a hack to solve this problem temporarily. In the outputStateChanged
method, I am checking to see if the state of the output has changed to IDLE
and if it has, I am again calling start()
method, specifying the common buffer. I don't want to use this as a permanent solution because it feels really hacky and because I am swallowing an error without properly investigating its reasons.
What should I do to solve this problem?
I also tried to solve this using Phonon but failed because I do not have sufficient knowledge of this module.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我对 Qt 不太有经验,但我在处理媒体方面很有经验,所以如果我的答案不是很具体而是从更一般的角度解决您的问题,请原谅我。
我看了你的代码,我认为一般来说你的想法应该可行。不过,我看到了一些问题:
writeData
方法似乎没有准备好处理缓冲区已满的情况。当循环缓冲区填满时,它只会覆盖旧数据,并错误地继续增加currentBufferLength
变量。我认为这里正确的做法是更新readPosition
以跳过丢失的数据,并防止currentBufferLength
增长超过缓冲区大小。 p>您几乎同时启动了作者和读者。相反,您应该启动写入器并准备循环缓冲区,然后启动读取器。请记住,您永远无法以零延迟进行录制和播放。至少您的延迟将是单个缓冲区写入的大小,但实际上您可能需要写入器领先几个缓冲区以避免出现问题。
您应该分别调试读取器和写入器。仅设置写入器并验证循环缓冲区是否定期写入(首先按照我上面的建议修复溢出情况)。要进行调试,您可以将缓冲区转储到文件中,然后在音频播放器(例如 Audacity)中检查该文件,或者您可以使用 printf 调试来确保不断获取数据。然后仅对读取器执行类似的操作。
最后的想法。调用
readData
和writeData
方法的代码可能正在其他线程上运行,可能是两个不同的线程,一个用于读取器,另一个用于写入器。如果我的猜测是正确的,那么你的圆形结构就有很大的问题了。您必须保护对确定读写位置和大小的变量的访问,否则就会出现竞争条件。祝你好运。
I'm not very experienced with Qt, but I am with handling media, so forgive me if my answer isn't very specific but instead addresses your problem from a more general point of view.
I looked at your code, and I think in general your idea should work. I see some problems though:
the
writeData
method doesn't seem to be prepared to handle a buffer full condition. When the circular buffer fills it'll just overwrite old data, and incorrectly continue to increment thecurrentBufferLength
variable. I think the correct thing to do here is to update thereadPosition
to skip over the data that was lost, and to preventcurrentBufferLength
from ever growing past the buffer size.You are starting both the writer and the reader at pretty much the same time. Instead, you should start the writer and prime the circular buffer, then start the reader. Keep in mind that you will never be able to record and play with zero latency. At the very least your latency will be the size of an individual buffer write, but in practice you'll probably need the writer to be ahead by a few buffers to avoid hiccups.
You should debug the reader and the writer separately. Set up only the writer and verify that the circular buffer is getting written to at regular intervals (first fix the overflow condition as I suggested above). To debug, you can dump the buffers to a file and then check the file in an audio player (Audacity, for example), or you can use printf debugging to ensure you are constantly getting data. Then do something similar with only a reader.
Final thought. The code that calls your
readData
andwriteData
methods is probably running on other threads, likely two different threads, one for the reader and another one for the writer. If my guess is correct, then you have a big problem with your circular structure. You have to protect access to the variables that determine the read and write positions and sizes, if not you will have race conditions.Good luck.
我不明白为什么使用您在评论中提到的类会出现问题。两者都不限于仅使用文件。
获取从
QAudioInput
的start()
方法返回的QIODevice
并将其传递给QAudioOutput
:I don't see why there would be a problem using the classes you mention in your comment. Neither are restricted to just using files.
Take the
QIODevice
returned from thestart()
method ofQAudioInput
and give it to thestart()
method ofQAudioOutput
:像这样启动输入和输出设备
,并将输入示例写入 readMore() 中的输出,
请参阅本文了解更多信息。
此示例应用程序是在 Qt 中创建的,将从麦克风录制并同时播放音频
http://www.codeproject.com/Articles/421287 /跨平台麦克风音频处理实用程序
Start the input and output device like this
and write the input sample to output in readMore()
Please look at this article for more.
This sample application is created in Qt will record from microphone and play audio simultaneously
http://www.codeproject.com/Articles/421287/Cross-Platform-Microphone-Audio-Processing-Utility
下面是用 QT5 编写的代码,用于读取音频输入、麦克风,并将其放入 64K 循环缓冲区中。一旦缓冲区有数据,它就会将其写入音频输出,即 PC 上的扬声器。这是基本代码,应该是熟悉声音设备的良好起点。请注意,此处声音输入和输出位于一个对象中,这可能会导致缓冲区问题。为了克服这个问题,为输入和输出创建一个单独的对象。
该程序有两个文件,第一个是 qt 配置文件(.pro),第二个是 main.cpp 文件。
Below is the code written in QT5 to read the audio input, the microphone, and places it into a 64K circular buffer. Once the buffer has data it writes it to audio output, the speaker on the PC. This is the bare bones code that should be a good starting point for getting familiar with the sound device. Note, that here the sound input and output are in one object this may cause buffer problems. To over come this create a separate objects for the input and output.
The program is in two file, the first being qt profile (.pro) and the second being the main.cpp file.
您获取从启动 QAudioInput 中获得的 QIOStream 并使用它来创建 Phonon::MediaSource。然后,您在 Phonon::MediaSource 和 Phonon::AudioOutput 对象之间创建一条路径。有关更多详细信息,请查看 Phonon::AudioOutput 和 Phonon::MediaSource。
You take the QIOStream that you get from starting the QAudioInput and use it to create a Phonon::MediaSource. Then you create a path between that Phonon::MediaSource and a Phonon::AudioOutput object. For more details checkout documentation for Phonon::AudioOutput and Phonon::MediaSource.