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

发布者:清新自然最新更新时间:2024-07-16 来源: elecfans关键字:jz2440  编写 手机看文章 扫描二维码
随时随地手机看文章

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、实验

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

在板子上执行出现段错误


关键字:jz2440  编写 引用地址:ALSA声卡16_编写ALSA声卡应用程序_学习笔记

上一篇:ALSA声卡12_从零编写之添加音量控制_学习笔记
下一篇:使用wifi网卡笔记1----网卡选型、开发环境搭建、内核配置

推荐阅读最新更新时间:2024-11-09 22:32

触摸屏驱动-JZ2440
测试方法: 1、make menuconfig 去掉原来的触摸程序 - Device Drivers - Input device support - generic input layer - Touchscreens s3c2410/s3c2440 ts make uImage 使用新内核启动 2、在虚拟机中编译tslib 2.1、解压缩 tar xzf tslib-1.4.tar.gz 2.2、自动生成 ./autogen.sh 2.3、添加一个目录,用于保存编译结果 mkdir tmp 2.4、响应一下 echo ac_cv_func_malloc_0_nonnull=yes arm-linux.cach
[单片机]
Linux驱动之一个简单的输入子系统程序编写
在Linux驱动之输入子系统简析已经分析过了输入子系统的构成,它是由设备层、核心层、事件层共同组成的。其中核心层提供一些设备层与事件层公用的函数,比如说注册函数、反注册函数、事件到来的处理函数等等;事件层其实在Linux内核里面已经帮我们写好了很多有关的事件;而设备层就跟我们新添加到输入系统的具体设备相关了。这里以JZ2440开发板上的4个按键作为输入子系统的按键:它定义的功能分别为:KEY_L、KEY_S、KEY_ENTER、KEY_LEFTSHIFT。这几个值是在includelinuxinput.h中被定义的。接下来就是编写程序: 直接贴出源程序: #include linux/module.h #include
[单片机]
Linux驱动之一个简单的输入子系统程序<font color='red'>编写</font>
OpenCV2.0.0移植到ARM9(五)(JZ2440----S3c2440)
Linux系统:Ubuntu9.10 交叉编译器:arm-linux-gcc-4.3.2(已安装) Qt:qt-x11-opensource-src-4.5.3.tar.gz qt-embedded-linux-opensource-src-4.5.3.tar.gz 1、安装Qt Qt下载地址:https://www.qt.io/download-open-source/ 这里下载的安装包为:qt-embedded-linux-opensource-src-4.5.3.tar.gz(大小123MB) 2、安装Qt-x11 将qt-x11-opensource-src-4.5.3.tar.gz包放到U
[单片机]
OpenCV2.0.0移植到ARM9(五)(JZ2440----S3c2440)
s3c9228汇编写的I2C及一字节除法
; /*EEPROM的读写*/ ;本文件提供四个函数,对MEM(24C02)进行读写 ;ReadMemByte ;ReadMemBlock ;WriteMemByte ;WriteMemBlock ;--------------------------------------------------------- ;从EEPROM中读一个字节,函数返回值R15 ;unsigned char ReadMemByte(unsigned char Addr) ;入口:R15 ;出口:R15 ;资源: R14,R15 ;引用:供外部用作从MEM读1BYTE的函数 ReadMemByte: PUSH R15 ;保存Addr堆栈
[单片机]
MSP430单片机中断函数的编写方法
以USCI0为例,说明该两种不同方法。 1.switch-case方法 #pragmavector=USCI_A0_VECTOR __interruptvoidUSCI_A0_ISR(void) { switch(__even_in_range(UCA0IV,4)) { case0: break; case2://接收中断 //dosomethinghere break; case4://发送中断 //dosomethinghere break; default: break; } } 2.查询标志为方法 #pragmavector=USCI_A0_VECTOR __interruptvoidUSCI_A0_ISR(vo
[单片机]
MSP430单片机中断函数的<font color='red'>编写</font>方法
如何编写有利于编译器优化的代码
在嵌入式开发中,代码的体积和运行效率非常重要,代码体积往往和芯片的FLASH、RAM容量对应,程序的运行效率也要求在相应能力的处理器上运行。在大多数情况下,成熟的开发人员都希望降低代码体积、提高代码运行效率,然而具体该怎么做呢?本篇文章将以国际知名编译器厂商IAR Systems的编译器为例,来解答开发人员在实际工作中常常遇到的问题,工程师朋友们可以在IAR编译器上进行实践验证。 对于嵌入式系统,最终代码的体积和效率取决于由编译器生成的可执行代码,而非开发人员编写的源代码;但是源代码的优化,可以帮助编译器生成更加优质的可执行代码。因此,开发人员不仅要从整体效率等因素上去构思源代码体系,也要高度关注编译器的性能和编译优化的便捷性
[嵌入式]
51定时器中断程序编写
上篇笔记记录到51单片机的中断允许寄存器、定时器/计数器工作方式寄存器(TMOD)、定时器/计数器控制寄存器(TCON)各位的作用。这些寄存器都是用来为编写定时器中断程序编写的初始化部分而服务的。然后今天再这里补填中断函数的编写格式,以后就可以编写定时器中断程序了。 1.中断服务程序的写法 C51的中断函数格式如下: void 函数名() 中断号 using 工作组 { 中断服务程序内容 } 与一般的C语言程序相比,中断服务程序有一下特点 中断函数不能返回任何值,所以函数名前用void; 函数名随便起,但不能与C51语言中的关键字同名(同C语言函数要求) 中断函数不能带任何参数,故函数名后的括号
[单片机]
51定时器中断程序<font color='red'>编写</font>
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved