热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux音频采集和在国产化平台中遇到的坑(一)

原标题:Linux音频采集和在国产化平台中遇到的坑(一)Linux音频采集和在国产化平台中遇到的坑(一)

原标题:Linux音频采集和在国产化平台中遇到的坑(一)

Linux音频采集和在国产化平台中遇到的坑(一)

最近在做一个国产化平台的软件项目的开发,是基于国产芯片的银河麒麟系统。其中有一个重要模块,是采集和播放音频数据,播放不用多说了,采集的话,包括采集麦克风和采集桌面系统声音。很多人都觉得银河麒麟不就是linux么,那不直接用ALSA就好了,我原本也是这么想的,但是实际开发下来才发现,还是有各种坑需要自己去趟的。这里我简单记录一下。

虽然都是linux,芯片也是基于同样的架构,同样的指令集,但是考虑到芯片的实现毕竟是不同的,于是所有涉及到硬件交互的软件部分,也会有所差异,最终会导致了有些应用层面的接口,不能按照普通linux的通常用法去使用。

linux ALSA音频采集

首先,银河麒麟既然是linux系统,那首先考虑到的是通过ALSA(Advanced Linux Sound Architecture)来进行采集,ALSA是linux的默认声卡驱动,同时在用户层还有一个ALSA Lib来供应用程序调用,它的整体上的结构图是这个样子的:

image

应用程序通常都是通过alsa-lib来使用,如果系统没有的话,可以通过命令安装开发库,就可以使用了。例如

sudo apt-get install libasound2-dev

另外需要注意一点的是,如果是android系统,那么系统里通常是不存在alsa的,而是它的简化版tiny-alsa,接口名称也不一样,但是大致调用流程是相同的。

alsa音频采集,有几个关键函数

#include
/***
创建alsa pcm handle去连接设备
@param handle: 返回创建的PCM handle
@param name: 设备名称,ASCII编码
@param stream: 标明采集或者播放(SND_PCM_STREAM_CAPTURE, SND_PCM_STREAM_PLAYBACK)
@param mode: 打开模式(see SND_PCM_NONBLOCK, SND_PCM_ASYNC)
@return: 0表示成功,小于0表示错误
*/
int snd_pcm_open( snd_pcm_t **handle, const char* name, int stream, int mode );
/***
读取音频帧
@param h文章来源站点https://www.yii666.com/andle: PCM handle
@param buffer: frames containing buffer
@param size: frames to be read
@return: 实际读取的音频帧个数,小于0表示错误
*/
ssize_t snd_pcm_readi( snd_pcm_t *handle, void *buffer, size_t size );
/***
关闭
@param handle: PCM handle
@return: 实际读取的音频帧个数,小于0表示错误
*/
int snd_pcm_close( snd_pcm_t *handle );
/***
准备使用PCM
@param handle: PCM handle
@return: 实际读取的音频帧个数,小于0表示错误
*/
int snd_pcm_prepare( snd_pcm_t *handle );

接口简单,参数也少,所以使用起来很方便,基本上是linux下采集和播放的第一选择,下面写个简单的例子演示下如何调用


  1. 打开音频设备并设置参数

SIMPLE_LOG("try open %s\n", device_name_.c_str());
int ret = snd_pcm_open(&alsa_pcm_, device_name_.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if (!alsa_pcm_ || ret <0)
{
SIMPLE_LOG("open %s failed, ret: %d\n", device_name_.c_str(), ret);
return false;
}
snd_pcm_hw_params_t* params;
snd_pcm_hw_params_alloca (¶ms);文章来源地址68338.html
snd_pcm_hw_params_any (alsa_pcm_, params);
snd_pcm_hw_params_set_access (alsa_pcm_, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_format_t format;
switch (bits_per_sam_) {
case 8:
format = SND_PCM_FORMAT_S8;
break;
case 16:
format = SND_PCM_FORMAT_S16_LE;
break;
case 24:文章来源地址68338.html
format = SND_PCM_FORMAT_S24_LE;
break;
case 32:
format = SND_PCM_FORMAT_S32_LE;
break;
default:
format = SND_PCM_FORMAT_S16_LE;
break;
}
snd_pcm_hw_params_set_format (alsa_pcm_, params, format);
snd_pcm_hw_params_set_channels (alsa_pcm_, params, channel_count_);
unsigned int rate = sample_rate_;
snd_pcm_hw_params_set_rate_near (alsa_pcm_, params, &rate, NULL);
sample_size_ = channel_count_ * (bits_per_sam_/8);
/* Activate the parameters */
ret = snd_pcm_hw_params (alsa_pcm_, params);
if (ret <0)
{
SIMPLE_LOG("set param failed, ret: %d\n", ret);
snd_pcm_close (alsa_pcm_);
alsa_pcm_ = NULL;
return false;
}


  1. 读取音频数据

bool AlsaCapture::ReadData()
{
int read_size = 0;
snd_pcm_uframes_t need_frames = real_sample_count_;
for (;;)
{
if (read_size >= pcm_buf_.size())
{
break;
}
int ret = 0;
while (true)
{
char* read_buf = &pcm_buf_[0] + read_size;
ret = snd_pcm_readi(alsa_pcm_, read_buf, need_frames);
if (ret >= 0)
{
break;
}
if (ret == -EAGAIN)
{
SIMPLE_LOG("snd_pcm_readi EAGAIN\n");
return false;
}
if (AlsaXRunRecover(alsa_pcm_, ret) <0)
{
SIMPLE_LOG("ALSA read error: %s\n", snd_strerror(ret));
www.yii666.com return false;
}
}
read_size += ret * sample_size_;
need_frames -= ret;
}
return true;
}

这样就可以完成音频数据的采集,需要注意的是,在第二步读取数据之前,需要先调用snd_pcm_prepare,否则是无法驱动数据采集正常进行的。

在国产化芯片平台上出现的问题

在普通Linux下,这样写下来,就可以实现想要的音频采集功能了,后面对数据做进一步的规整和编码就可以发送了。但是在某个国产芯片平台的银河麒麟系统下,我却遇到了一个问题,那就是打开设备的函数调用以及所有的参数设置都是成功的,但是数据采集却总是异常,要么返回无意义噪声数据,要么read接口干脆就报EAGAIN错误。

刚开始我以为是ALSA默认设备的问题,因为出问题的国产化芯片平台,有两个声卡,其中一个是可以正常使用的,另一个是无效声卡。这些信息可以通过使www.yii666.com用命令行来查看,例如:

查看声卡:

cat /proc/asound/cards

查看采集设备:

sudo arecord -l

查看播放设备:

cat aplay -l

于是我尝试通过系统配置的方式,来设置默认声卡,这里推荐一个工具“alsamixer”,是一个字符化界面的ALSA配置工具,可以通过如下命令安装:

sudo apt-get install alsa-utils

启动后就是一个这样的界面

image

然而,修改以后,发现默认设备的修改,并不能影响到alsa采集的结果。于是通过罗列所有录音设备,并且指定设备名称,但是仍然出现同样的结果。在多次尝试无果以后,最终只能放弃使用ALSA来进行音频设备的数据采集,而采用复杂一些的PulseAudio框架。最后的结果也证明,更加上层的PulseAudio还是正确的处理了有效的音频设备和无效音频设备,并正确返回了麦克风/桌面系统声音。具体过程我下一篇再写。

image

合作请加QQ或微信hbstream。(转载请注明作者和出处)


来源于:Linux音频采集和在国产化平台中遇到的坑(一)


推荐阅读
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 抽空写了一个ICON图标的转换程序
    抽空写了一个ICON图标的转换程序,支持png\jpe\bmp格式到ico的转换。具体的程序就在下面,如果看的人多,过两天再把思路写一下。 ... [详细]
  • java io换行符_Java IO:为什么从stdin读取时,换行符的数字表示出现在控制台上?...
    只是为了更好地理解我在讲座中听到的内容(关于Java输入和输出流),我自己做了这个小程序:publicstaticvoidmain(String[]args)thro ... [详细]
  • docker安装到基本使用
    记录docker概念,安装及入门日常使用Docker安装查看官方文档,在&quot;Debian上安装Docker&quot;,其他平台在&quot;这里查 ... [详细]
  • Ubuntu18.04 安装ROS Melodic && Ros2 Dashing
    https:blog.csdn.netqq_44717317articledetails104547474一、Ubuntu18.04的安装ubuntu2go的制作关于Ubuntu2 ... [详细]
author-avatar
品格优良2003_645
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有