关于重写QIODevice类readData函数来向声卡传递音频数据播放音乐的问题

大树学长 2019-11-19 06:35:00
我是按照这个博客上面来做的
https://blog.csdn.net/jklinux/article/details/72620102
功能需要我一边获取数据一边播放,现在播放什么的都正常,但是遇到一个非常偶尔才会出现的BUG

BUG:
有时候播放过很多首音乐后会变成噪音输出,有时候刚播放第一首一部分后也会变成噪音输出,等这首音乐播放完,播放下一首又会变正常了,反正很偶尔出现这个BUG,正常情况下无法重现这个BUG。
不过在debug模式下在MyDevice::readData(char *data, qint64 maxlen)中打断点,然后去掉断点继续播放,多来几次也会变成噪音,data_pcm中肯定是有数据的,如果再继续打断点去掉断点操作几次又变成正常音乐播放了,不知道是什么原因?有没有大神帮忙看看这个问题

重写QIODevice类中readData函数,data_pcm为音频数据,memcpy到声卡缓存中

qint64 MyDevice::readData(char *data, qint64 maxlen) // data为声卡的数据缓冲区地址, maxlen为声卡缓冲区最大能存放的字节数
{
if (len_written >= data_pcm.size())
return 0;
int len;

//计算未播放的数据的长度
len = (len_written+maxlen) > data_pcm.size() ? (data_pcm.size() - len_written) : maxlen;

memcpy(data, data_pcm.data()+len_written, len); //把要播放的pcm数据存入声卡缓冲区里
len_written += len; //更新已播放的数据长度
return len;
}
...全文
950 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
MrYangLu 2021-08-13
  • 打赏
  • 举报
回复
audioOutput->setBufferSize(data.size());
QIODevice* io = audioOutput->start();
io->write(data);

不重写就OK了

道亦无名 2019-11-26
  • 打赏
  • 举报
回复
同步一下撒 这种东西
donwmufromdying 2019-11-25
  • 打赏
  • 举报
回复
我个人觉得还是你的数据读写上的问题。应该是播放器在偶尔的状态下读取到的数据是脏数据,而此时可能你写入buffer的数据才写了一半。所以,你可以用加锁解锁来试试看
大树学长 2019-11-25
  • 打赏
  • 举报
回复
引用 13 楼 这是一个正经昵称 的回复:
[quote=引用 12 楼 大树学长 的回复:] [quote=引用 11 楼 donwmufromdying 的回复:] 我个人觉得还是你的数据读写上的问题。应该是播放器在偶尔的状态下读取到的数据是脏数据,而此时可能你写入buffer的数据才写了一半。所以,你可以用加锁解锁来试试看
各种情况下的数据都生成音频文件挺过了,没有问题,现在没有用这个QT接口了,准备用windows的播放数据[/quote] 很神奇的情况,我这边没试出来过。移植Qt到嵌入式的时候我也发现Qt有一些‘bug’,不能好好用的时候还是用别的替换最好了[/quote] 不经常出现的,我跑2个小时都没有问题,一天出现不了几次,但是一定会出现
  • 打赏
  • 举报
回复
引用 12 楼 大树学长 的回复:
[quote=引用 11 楼 donwmufromdying 的回复:] 我个人觉得还是你的数据读写上的问题。应该是播放器在偶尔的状态下读取到的数据是脏数据,而此时可能你写入buffer的数据才写了一半。所以,你可以用加锁解锁来试试看
各种情况下的数据都生成音频文件挺过了,没有问题,现在没有用这个QT接口了,准备用windows的播放数据[/quote] 很神奇的情况,我这边没试出来过。移植Qt到嵌入式的时候我也发现Qt有一些‘bug’,不能好好用的时候还是用别的替换最好了
大树学长 2019-11-25
  • 打赏
  • 举报
回复
引用 11 楼 donwmufromdying 的回复:
我个人觉得还是你的数据读写上的问题。应该是播放器在偶尔的状态下读取到的数据是脏数据,而此时可能你写入buffer的数据才写了一半。所以,你可以用加锁解锁来试试看
各种情况下的数据都生成音频文件挺过了,没有问题,现在没有用这个QT接口了,准备用windows的播放数据
大树学长 2019-11-23
  • 打赏
  • 举报
回复
1、 试过将接收的数据保存成音频文件, 将传递给声卡的数据保存成音频文件, 将声卡缓冲区数据保存成音频文件, 所有出现白噪音的地方文件数据都没有问题,也就是说所有传递的数据都是没有问题的,但是就是有偶尔白噪音 2、 直接播放音频文件,但是还是这种白噪音的问题, 3、 最后将QIODevice使用readData函数播放这个模块单独拿出来播放还是有白噪音,感觉本身就有BUG
大树学长 2019-11-21
  • 打赏
  • 举报
回复
引用 8 楼 这是一个正经昵称 的回复:
那你把送进去的数据同时写到文件里看看吧,操作出噪音的情况然后再分析下数据。我这边播pcm,wav都没有过那种问题。只有一种噪音的时候,就是wav的结尾有一段xml描述,播完还把xml数据送进去播的时候就是噪音。
我这个本来就有导出的功能,如果导出的音乐文件有问题那么在听某个音乐时应该每次都会出现白噪音的,但是实际上有噪音的音乐听第二遍就变正常了
  • 打赏
  • 举报
回复
那你把送进去的数据同时写到文件里看看吧,操作出噪音的情况然后再分析下数据。我这边播pcm,wav都没有过那种问题。只有一种噪音的时候,就是wav的结尾有一段xml描述,播完还把xml数据送进去播的时候就是噪音。
大树学长 2019-11-20
  • 打赏
  • 举报
回复
测试 memcpy(data, data_pcm.data()+len_written, len); 改为 memcpy(data, data_pcm.data()+len_written + 1, len); 开始播放的时候就会变为白噪音,但是通过几次断点会变为正常音乐播放 那么原来没有+1的肯定就会变为白噪音, 猜测是这个地方导致的正常播放时非常偶尔出现白噪音的原因, 但是不知道怎么判断这个地方正确应该给多少
大树学长 2019-11-20
  • 打赏
  • 举报
回复
引用 2 楼 这是一个正经昵称 的回复:
你应该看一下音频的数据格式。 你是一边获取一边播放的对吧? 音频数据流的地址偏移保持为偶数试试吧,可能是你每次送进来的音频数据都是不确定的引起的吧 QAudioOutput按上述代码播本地pcm文件是没有问题的,但如果memcpy的时候+1,就会只有很小声的一段然后就是噪音了。所以我想,比如数据是0101010101这样的,送进去的时候每次起始都应该是0,如果错开成1 就会噪音,而获取到的数据送进来的时候可能刚好就这样的吧。
测试len_written的值都是偶数,而且为偶数的情况下还是能变为白噪音
大树学长 2019-11-20
  • 打赏
  • 举报
回复
引用 4 楼 这是一个正经昵称 的回复:
我用QAudioOutput做的播放器,Seek就是初始化len_written= n秒*位数*1024;然后memcpy(data, data_pcm.data()+len_written, len); 所以你看是不是检查下输入的数据是不是有问题
我现在刚测的能一直播放音乐一个多小时音乐都没有出现白噪音,我还发现如果在播放的时候,电脑锁屏或者解锁win+L快捷键,本来播放好好的也会导致出现白噪音
大树学长 2019-11-20
  • 打赏
  • 举报
回复
引用 2 楼 这是一个正经昵称 的回复:
你应该看一下音频的数据格式。 你是一边获取一边播放的对吧? 音频数据流的地址偏移保持为偶数试试吧,可能是你每次送进来的音频数据都是不确定的引起的吧 QAudioOutput按上述代码播本地pcm文件是没有问题的,但如果memcpy的时候+1,就会只有很小声的一段然后就是噪音了。所以我想,比如数据是0101010101这样的,送进去的时候每次起始都应该是0,如果错开成1 就会噪音,而获取到的数据送进来的时候可能刚好就这样的吧。
1、我这个是播放过程中才出现白噪音的,开头和结尾没有出现过噪音, 2、我获取音频数据的速度要比播放要快很多,所以每次声卡获取的数据都是按照最大缓冲大小发的,len_written初始为0

qint64 MyDevice::readData(char *data, qint64 maxlen) // data为声卡的数据缓冲区地址, maxlen为声卡缓冲区最大能存放的字节数
{
    if (len_written >= Data_sum)
    {
        return 0;
    }


    //计算未播放的数据的长度
    int len = 0;
    if((len_written + maxlen) > Data_sum)
        len = Data_sum - len_written;
    else
        len = maxlen;

    if(len < 0)
    {
        len = 0;
    }

    memcpy(data, (char*)(Data3 + len_written), len); //把要播放的pcm数据存入声卡缓冲区里,Data3 为全局变量uint8_t格式,
    len_written = len_written + len; //更新已播放的数据长度


    return len;
}
  • 打赏
  • 举报
回复
我用QAudioOutput做的播放器,Seek就是初始化len_written= n秒*位数*1024;然后memcpy(data, data_pcm.data()+len_written, len); 所以你看是不是检查下输入的数据是不是有问题
  • 打赏
  • 举报
回复
对了,音频一般是一个buffer一个buffer播的,你每次播的buffer不足的为需要你自己去填静音数据过去,比如你最后一个buffer里只放了1646的数据,那剩下的maxlen-1646需要你去补全,不同的音频格式要补的数据不一样,有的是0,有的是0xD5还是什么来着,不然就会有一下噪音。
  • 打赏
  • 举报
回复
你应该看一下音频的数据格式。 你是一边获取一边播放的对吧? 音频数据流的地址偏移保持为偶数试试吧,可能是你每次送进来的音频数据都是不确定的引起的吧 QAudioOutput按上述代码播本地pcm文件是没有问题的,但如果memcpy的时候+1,就会只有很小声的一段然后就是噪音了。所以我想,比如数据是0101010101这样的,送进去的时候每次起始都应该是0,如果错开成1 就会噪音,而获取到的数据送进来的时候可能刚好就这样的吧。

16,814

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧