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

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

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

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

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

linux ALSA音频采集

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

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

sudo apt-get install libasound2-dev

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

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

#include <sys/asoundlib.h>
/***
 创建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 handle: 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 (&params);
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:
  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));
                return false;
            }
        }
        read_size += ret * sample_size_;
        need_frames -= ret;
    }
    return true;
}

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

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

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

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

查看声卡:

cat /proc/asound/cards

查看采集设备:

sudo arecord -l

查看播放设备:

cat aplay -l

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

sudo apt-get install alsa-utils

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

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

目录
相关文章
|
9天前
|
编解码 Linux 开发工具
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
|
2月前
|
安全 Linux 图形学
Linux平台Unity下RTMP|RTSP低延迟播放器技术实现
本文介绍了在国产操作系统及Linux平台上,利用Unity实现RTMP/RTSP直播播放的方法。通过设置原生播放模块的回调函数,可将解码后的YUV数据传递给Unity进行渲染,实现低延迟播放。此外,还提供了播放器启动、参数配置及停止的相关代码示例,并概述了如何在Unity中更新纹理以显示视频帧。随着国产操作系统的发展,此类跨平台直播解决方案的需求日益增长,为开发者提供了灵活高效的开发方式。
|
2月前
|
编解码 算法 Linux
Linux平台下RTSP|RTMP播放器如何跟python交互投递RGB数据供视觉算法分析
在对接Linux平台的RTSP播放模块时,需将播放数据同时提供给Python进行视觉算法分析。技术实现上,可在播放时通过回调函数获取视频帧数据,并以RGB32格式输出。利用`SetVideoFrameCallBackV2`接口设定缩放后的视频帧回调,以满足算法所需的分辨率。回调函数中,每收到一帧数据即保存为bitmap文件。Python端只需读取指定文件夹中的bitmap文件,即可进行视频数据的分析处理。此方案简单有效,但应注意控制输出的bitmap文件数量以避免内存占用过高。
|
2月前
|
编解码 Linux 数据安全/隐私保护
Linux平台x86_64|aarch64架构如何实现轻量级RTSP服务
为满足在Linux平台(x86_64与aarch64架构)上实现轻量级RTSP服务的需求,我们开发了一套解决方案。该方案通过调用`start_rtsp_server()`函数启动RTSP服务,并设置端口号及认证信息。支持AAC音频和H.264视频编码,可推送纯音频、纯视频或音视频流。此外,还支持X11屏幕采集、部分V4L2摄像头采集、帧率/GOP/码率调整、摄像头设备选择与预览等功能。对于音频采集,支持alsa-lib和libpulse接口。整体设计旨在提供150-400ms的低延迟体验,适用于多种应用场景。
|
2月前
|
编解码 Linux 开发工具
Linux平台x86_64(麒麟|统信UOS)|aarch64(飞腾)如何实现摄像头|屏幕和麦克风|扬声器采集推送RTMP服务或轻量级RTSP服务
国产化操作系统的发展,减少了外部依赖,更符合国家安全标准,并可提升自主研发能力,促进产业链发展,满足定制开发能力,减少了外部技术封锁的风险,提高了国际竞争力,推动了产业升级。目前大牛直播SDK针对Linux平台x86_64架构和aarch64架构的RTMP推送模块和轻量级RTSP服务模块
|
2月前
|
Linux
Avalonia应用在基于Linux的国产操作deepin上运行
Avalonia应用在基于Linux的国产操作deepin上运行
44 0
|
4月前
|
Linux 开发工具
Linux技术资源分享:探索Linux软件包的宝藏:沙皇下载平台体验
Linux技术资源分享:探索Linux软件包的宝藏:沙皇下载平台体验
29 3
|
3月前
|
弹性计算 运维 自然语言处理
属于Basis运维的、在Linux平台上运行的大模型测评 OS Copilot智能助手测评
OS Copilot是阿里云为Linux打造的智能操作系统助手,基于大模型,助用户进行自然语言问答、命令执行和系统运维。它简化了Linux操作,适合新手和运维人员。测评者作为IT架构师,发现OS Copilot使非技术背景人员也能操作Linux,接入命令可在官方文档找到。测试显示,通过"co"命令可与OS Copilot交互,实现生产任务融合。该工具提高了工作效率,尤其是对于遗忘具体命令时,非常有帮助。文档清晰,适合生产环境使用,值得进一步探索。
69 0
|
4月前
|
Linux API C语言
C语言读写BMP文件-EasyBmp【 linux 平台】
**EasyBmp** 是一个49KB的轻量级C++图像处理库,专注于BMP格式,提供简单易用的API。它的特点是小巧、开源、易于理解和高度定制。通过示例代码展示了如何轻松读取、缩放和保存BMP图像。适合需要高效处理BMP图像的开发者。
|
5月前
|
消息中间件 Linux 数据库
第五十三章 使用 ^SystemPerformance 监视性能 - InterSystems IRIS Linux 平台性能数据报告
第五十三章 使用 ^SystemPerformance 监视性能 - InterSystems IRIS Linux 平台性能数据报告
38 0
下一篇
无影云桌面