您尚未登录。

楼主 #1 2021-04-22 11:48:06

sck852414902
会员
注册时间: 2020-12-23
已发帖子: 12
积分: 18.5

V3S CODEC的使用及驱动测试(声音播放功能)

由于做项目要用音频播放,然后就自己研究了没用tinyalsa


一.下载alsa-lib和alsa-utils

https://www.alsa-project.org/main/index.php/Download
这里可以下载最新版本的alsa-lib和alsa-utils,
我这边使用的是1.1.4.1版本的alsa-lib,和1.1.4版本的alsa-utils

链接:https://pan.baidu.com/s/1dSB9ZGjThztQ2xucConoCA
提取码:vzg9

1.编译alsa-lib

tar xvf alsa-lib-1.1.4.1.tar.bz2  
cd alsa-lib-1.1.4.1/

//设置安装路径,在系统目录/usr/local/alsa下安装
MyDIR="/usr/local/alsa"
//host 编译器名称,不同编译器自己改
//prefix 保存路径,后面会用到
//CC 链接到自己LINUX的编译器路径
./configure --host=arm-linux-gnueabihf --prefix=$MyDIR/build --enable-shared --disable-python --with-configdir=$MyDIR/build/alsa_lib/share --with-plugindir=$MyDIR/build/alsa_lib/lib CC=/opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
sudo make
sudo make install

2.编译alsa-utils

tar xvf alsa-utils-1.1.4.tar.bz2
cd alsa-utils-1.1.4/
//设置安装路径,在系统目录/usr/local/alsa下安装
MyDIR="/usr/local/alsa/build"
//host 编译器名称,不同编译器自己改
//prefix 保存路径,后面会用到
//CC 链接到自己LINUX的编译器路径
./configure --host=arm-linux-gnueabihf --prefix=$PWD/build CC=/opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc CFLAGS="-I$MyDIR/include" LDFLAGS="-L$MyDIR/lib -lasound" --disable-alsamixer --disable-xmlto
sudo make
sudo make install

3.把文件拷贝到开发板

1.把/usr/local/alsa/build/lib 中的libasound.la  libasound.so  libasound.so.2  libasound.so.2.0.0 拷贝到开发板上的/lib目录(系统目录下的lib,不是/usr里面的lib)

2.将/usr/local/alsa/build/alsa_lib/share文件复制到开发板的同样的文件位置(为了方便可以直接把整个local文件拷到/usr文件夹下)
3.把/alsa-utils-1.1.4/build/bin中的可执行文件拷贝到开发板的/bin目录(在alsa-utils-1.1.4目录下面,系统的bin文件下,不是/usr/bin)
4.alsa-utils-1.1.4/build/share/sounds/alsa  里面有测试用的音频文件,可以拷到开发板测试用,也可以自己下,要WAV格式。

在开发板上ls -l /dev/snd看看系统是否已经有了设备节点,如果没有,需要手动创建。
这个我没试过,荔枝派内核是已经开启snd了,所以我直接跳过这一步了

mkdir /dev/snd 
mknod /dev/snd/controlC0 c 116 0 
mknod /dev/snd/pcmC0D0p c 116 16 
mknod /dev/snd/pcmC0D0c c 116 24 
mknod /dev/snd/seq c 116 1 
mknod /dev/snd/hwC0D0 c 116 4 
mknod /dev/snd/timer c 116 33

//可以打下面看下有没有SND

ls -l /dev/snd/

//输出:

controlC0  pcmC0D0c   pcmC0D0p   timer

音频播放测试

//开机后默认状态是静音状态,需要取消掉静音状态

amixer -c 0 sset 'Headphone',0 100% unmute
cd 有音频目录下
aplay xxx.wav

驱动测试代码
main.c

#define ALSA_PCM_NEW_HW_PARAMS_API
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
 
#define u32 unsigned int
#define u8   unsigned char
#define u16 unsigned short
 
 
#pragma pack(push) 
#pragma pack(1)     //1字节对齐
 
typedef  struct	{
	u32 	dwSize;
	u16		wFormatTag;
	u16		wChannels;
	u32 	dwSamplesPerSec;
	u32 	dwAvgBytesPerSec;
	u16		wBlockAlign;
	u16		wBitsPerSample;
} WAVEFORMAT;
 
typedef  struct	{
	u8    	RiffID [4];
	u32     RiffSize;
	u8    	WaveID[4];
	u8    	FmtID[4];
	u32     FmtSize;
	u16   	wFormatTag;
	u16   	nChannels;
	u32 	nSamplesPerSec;  /*采样频率*/
	u32 	nAvgBytesPerSec; /*每秒所需字节数*/
	u16		nBlockAlign; /*数据块对齐单位,每个采样需要的字节数*/
	u16		wBitsPerSample;/*每个采样需要的bit数*/
	u8		DataID[4];
	u32 	nDataBytes;
} WAVE_HEADER;
 
#pragma pack(pop) /* 恢复先前的pack设置 */
 
WAVE_HEADER g_wave_header;
snd_pcm_t *gp_handle;  //调用snd_pcm_open打开PCM设备返回的文件句柄,后续的操作都使用是、这个句柄操作这个PCM设备
snd_pcm_hw_params_t *gp_params;  //设置流的硬件参数
snd_pcm_uframes_t g_frames;    //snd_pcm_uframes_t其实是unsigned long类型
char *gp_buffer;
u32 g_bufsize;
 
FILE * open_and_print_file_params(char *file_name)
{
	FILE * fp = fopen(file_name, "r");
	if (fp == NULL)
	{
		printf("can't open wav file\n");
		return NULL;
	}
	
 
	memset(&g_wave_header, 0, sizeof(g_wave_header));
	fread(&g_wave_header, 1, sizeof(g_wave_header), fp);
	
	printf("RiffID:%c%c%c%c\n", g_wave_header.RiffID[0], g_wave_header.RiffID[1], g_wave_header.RiffID[2], g_wave_header.RiffID[3]);
	printf("RiffSize:%d\n", g_wave_header.RiffSize);
	printf("WaveID:%c%c%c%c\n", g_wave_header.WaveID[0], g_wave_header.WaveID[1], g_wave_header.WaveID[2], g_wave_header.WaveID[3]);
	printf("FmtID:%c%c%c%c\n", g_wave_header.FmtID[0], g_wave_header.FmtID[1], g_wave_header.FmtID[2], g_wave_header.FmtID[3]);
	printf("FmtSize:%d\n", g_wave_header.FmtSize);
	printf("wFormatTag:%d\n", g_wave_header.wFormatTag);
	printf("nChannels:%d\n", g_wave_header.nChannels);
	printf("nSamplesPerSec:%d\n", g_wave_header.nSamplesPerSec);
	printf("nAvgBytesPerSec:%d\n", g_wave_header.nAvgBytesPerSec);
	printf("nBlockAlign:%d\n", g_wave_header.nBlockAlign);
	printf("wBitsPerSample:%d\n", g_wave_header.wBitsPerSample);
	printf("DataID:%c%c%c%c\n", g_wave_header.DataID[0], g_wave_header.DataID[1], g_wave_header.DataID[2], g_wave_header.DataID[3]);
	printf("nDataBytes:%d\n", g_wave_header.nDataBytes);
	
	return fp;
}
 
int set_hardware_params()
{
	int rc;
	/* Open PCM device for playback */    
	rc = snd_pcm_open(&gp_handle, "hw:0,0", SND_PCM_STREAM_PLAYBACK, 0);    
	if (rc < 0) 
	{    
		printf("unable to open pcm device\n"); 
		return -1;   
	} 

 
	
	/* Allocate a hardware parameters object */    
	snd_pcm_hw_params_alloca(&gp_params);
	
	/* Fill it in with default values. */     
	rc = snd_pcm_hw_params_any(gp_handle, gp_params);
	if (rc < 0) 
	{    
		printf("unable to Fill it in with default values.\n");    
		goto err1;  
	}
	
 
	/* Interleaved mode */    
	rc = snd_pcm_hw_params_set_access(gp_handle, gp_params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (rc < 0) 
	{    
		printf("unable to Interleaved mode.\n");    
		goto err1;  
	}
		
	snd_pcm_format_t format;
	
	if (8 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U8;
	}
	else if (16 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_S16_LE;
	}
	else if (24 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U24_LE;
	}
	else if (32 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U32_LE;
	}
	else
	{
		printf("SND_PCM_FORMAT_UNKNOWN.\n");    
		format = SND_PCM_FORMAT_UNKNOWN;
		goto err1; 
	}
	
		
	/* set format */    
	rc = snd_pcm_hw_params_set_format(gp_handle, gp_params, format);
	if (rc < 0) 
	{    
		printf("unable to set format.\n");    
		goto err1;  
	}
	
	/* set channels (stero) */    
	snd_pcm_hw_params_set_channels(gp_handle, gp_params, g_wave_header.nChannels);
	if (rc < 0) 
	{    
		printf("unable to set channels (stero).\n");    
		goto err1;  
	}
	
	/* set sampling rate */       
    u32 dir, rate = g_wave_header.nSamplesPerSec;  
	rc = snd_pcm_hw_params_set_rate_near(gp_handle, gp_params, &rate, &dir); 
	if (rc < 0) 
	{    
		printf("unable to set sampling rate.\n");    
		goto err1;  
	} 
	
	/* Write the parameters to the dirver */    
	rc = snd_pcm_hw_params(gp_handle, gp_params);    
	if (rc < 0) {    
		printf("unable to set hw parameters: %s\n", snd_strerror(rc));    
		goto err1;  
	} 
	
	snd_pcm_hw_params_get_period_size(gp_params, &g_frames, &dir);
	g_bufsize = g_frames * 2;	//g_frames * 4 //播放速度
	gp_buffer = (u8 *)malloc(g_bufsize);
	if (gp_buffer == NULL)
	{
		printf("malloc failed\n");
		goto err1;  
	}
 
	return 0;
	
err1:
	snd_pcm_close(gp_handle);
	return -1;	
}
 
 
int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("usage: %s filename.wav\n", argv[0]);
		return -1;
	}
	
	FILE * fp = open_and_print_file_params("Rear_Right.wav");
	//int fd = open(argv[1], O_RDONLY);
	if (fp == NULL)
	{	
		printf("open_and_print_file_params error\n");
		return -1;
    }
	
	int ret = set_hardware_params();
	if (ret < 0)
	{
		printf("set_hardware_params error\n");
		return -1;
	}
	
	size_t rc;
	while (1)
	{
		rc = fread(gp_buffer, g_bufsize, 1, fp);
		if (rc <1)
		{
			break;
		}
		
		ret = snd_pcm_writei(gp_handle, gp_buffer, g_frames);    
		if (ret == -EPIPE) {    
			printf("underrun occured\n");  
			break;  
		}    
		else if (ret < 0) {    
			printf("error from writei: %s\n", snd_strerror(ret));    
			break;
		} 
	}
	
	
	snd_pcm_drain(gp_handle);    
	snd_pcm_close(gp_handle);    
	free(gp_buffer); 
	fclose(fp);
	return 0;
}

makefile

SOURCE = $(wildcard *.c)
TARGETS = $(patsubst %.c, %, $(SOURCE))

CC = arm-linux-gnueabihf-gcc
PREFIX=/usr/local/alsa/build
#CFLAGS = -Wall


all:$(TARGETS)

$(TARGETS):%:%.c
	$(CC) $<  -o $@ -I $(PREFIX)/include -L $(PREFIX)/lib -lasound

.PHONY:clean all
clean:
	-rm -rf $(TARGETS)
//别忘了取消静音
amixer -c 0 sset 'Headphone',0 100% unmute
./main xxx.wav

总结
1.由于我做项目没有用到录音功能,所以就没测试了,有需要的话看 https://blog.csdn.net/weixin_30301183/article/details/98466667 后面有讲到arecord 没有编译出来的原因和解决的问题。
2.有试过按照 https://blog.csdn.net/Jun626/article/details/100036595 用buildroot自动生成alsa,并成功测试过播放和录音,但是编程上困住了,有研究过的可以讨论下(教教我)
3.最后是自己的CSDN https://blog.csdn.net/Topshenck/article/details/116002269

最近编辑记录 sck852414902 (2021-04-22 13:27:12)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn