ALSA声卡16_编写ALSA声卡应用程序_学习笔记

发布时间:2024-07-16  

1、体验

(1)ALSA声卡使用体验:使用arecord录音,使用aplay播放,在Alsa-utils里面)

准备:

cd linux-3.4.2
patch -p1 < ../linux-3.4.2_alsa_wm8976_uda1341_jz2440_mini2440_tq2440.patch  //打补丁
cp config_wm8976_jz2440 .config 或 cp config_uda1341_tq2440_mini2440 .config    //设置配置文件
make uImage   //编译内核

(2)使用新内核启动并测试

启动后创建设备节点


直接输入arecord命令查看帮助信息(arecord 选项 文件)


执行命令后,出现错误(没有匹配的通道)


搜索内核目录查看错误原因(在soc_pcm.c文件的222行)


通道最小大于通道最大值,也就是codec这一边的dai不匹配CPU这边的dai接口,他们的声道不匹配,在codec部分,对应wm8976的capture通道支持的声道数是1(最大和最小都是 ,因而应该修改为2);

而在platform(cpu部分)的IIS,capture通道支持的声道数是2,因而不匹配。



(3)修改程序后编译新内核并重新启动调试

jz2440:
i. 声音差
    arecord test.wav  //录音,把录到的声音放到文件test.wav里去
    aplay   test.wav   //播放test.wav文件





对着麦克风说话,然后播放声音


(4)声音有很多噪声,解决办法是添加一些参数(改变采样率,声道数,格式)

-f cd表示每一个采样点是16位,采样率是44100(更高的采样频率),双声道


ii. 声音好
arecord -f cd test.wav
aplay test.wav



(5)对于mini2440,重新配置内核,然后编译拷贝到网络文件系统,并使用新内核启动


按上面的录音和播放声音操作,没有播放出任何声音,看原理图,录音麦克风通道是第2个通道(VINL),没有被打开


查看控制项


获取控制项Input Mux的状态,当前值是0,表示没有使用。


把第二个通道打开(用于录音)


 然后录音播放







2. 编写一个应用程序

(1)分析

一边录音一边播放(仿造arecord ,aplay(都在aplay.c里面(在Alsa-utils里面),aplay.c用到alsa-lib库))

aplay.c使用alsa-lib这个库编写程序的
A Tutorial on Using the ALSA Audio API:
alsa-lib使用方法
open_the_device();//打开设备
set_the_parameters_of_the_device(); //设置参数
while (!done) {
           /* one or both of these */
           receive_audio_data_from_the_device(); //如果是录音就接收data
    deliver_audio_data_to_the_device(); //如果播放把数据发送到设备上去
      }
close the device  //关闭设备

(2)main函数

int main (int argc, char *argv[])
{
int err;
char buf[512];
snd_pcm_t *playback_handle;
snd_pcm_t *capture_handle;
    playback_handle = open_playback();// 打开播放设备
    if (!playback_handle)
    {
fprintf (stderr, "cannot open for playbackn");
        return -1;
    }
    capture_handle = open_capture();//打开录音设备
    if (!capture_handle)
    {
fprintf (stderr, "cannot open for capturen");
        return -1;
    }
if ((err = snd_pcm_prepare (playback_handle)) < 0) { //准备播放操作
fprintf (stderr, "cannot prepare audio interface for use (%s)n",
snd_strerror (err));
return -1;
}
if ((err = snd_pcm_prepare (capture_handle)) < 0) { //准备录音操作
fprintf (stderr, "cannot prepare audio interface for use (%s)n",
snd_strerror (err));
return -1;
}
while (1) {
if ((err = snd_pcm_readi (capture_handle, buf, 128)) != 128) { //读操作(把数据读到buffer)
fprintf (stderr, "read from audio interface failed (%s)n",
snd_strerror (err));
return -1;
}
if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) { //写操作(把数据写到buffer)
fprintf (stderr, "write to audio interface failed (%s)n",
snd_strerror (err));
return -1;
}
}
snd_pcm_close (playback_handle);//关闭播放设备
snd_pcm_close (capture_handle);//关闭录音设备
    return 0;
}


(3)打开设备

snd_pcm_t *open_sound_dev(snd_pcm_stream_t type)
{
int err;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
unsigned int rate = 44100;


if ((err = snd_pcm_open (&handle, "default", type, 0)) < 0) {   //打开设备,第2个参数是指使用默认的 设备名称
return NULL;
}
  
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {  //分配参数
fprintf (stderr, "cannot allocate hardware parameter structure (%s)n",
snd_strerror (err));
return NULL;
}
 
if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {  //初始化参数
fprintf (stderr, "cannot initialize hardware parameter structure (%s)n",
snd_strerror (err));
return NULL;
}


if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { //设置参数,数据存放方式是交叉存放SND_PCM_ACCESS_RW_INTERLEAVED(先放左声道再放右声道)
fprintf (stderr, "cannot set access type (%s)n",   
snd_strerror (err));
return NULL;
}


if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
fprintf (stderr, "cannot set sample format (%s)n", //设置格式SND_PCM_FORMAT_S16_LE是16位的
snd_strerror (err));
return NULL;
}


if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &rate, 0)) < 0) { //设置采样率
fprintf (stderr, "cannot set sample rate (%s)n",
snd_strerror (err));
return NULL;
}


if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, 2)) < 0) { //设置通道数
fprintf (stderr, "cannot set channel count (%s)n",
snd_strerror (err));
return NULL;
}


if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { //把构造的结构体的数据写到硬件上去
fprintf (stderr, "cannot set parameters (%s)n",
snd_strerror (err));
return NULL;
}


snd_pcm_hw_params_free (hw_params); //释放含参数的结构体


return handle;  //成功时返回句柄
}

(4)关闭声卡设备和打开播放/录音设备

void close_sound_dev(snd_pcm_t *handle) //关闭声音设备
{
snd_pcm_close (handle);
}


snd_pcm_t *open_playback(void) //打开播放设备
{
    return open_sound_dev(SND_PCM_STREAM_PLAYBACK);
}


snd_pcm_t *open_capture(void) //打开录音设备
{
    return open_sound_dev(SND_PCM_STREAM_CAPTURE);
}


3、Makefile

这里-lasound表示使用asound库



4、实验

编译好,拷贝到网络文件系统上

在板子上执行出现段错误


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>