Alsa 调试下篇:应用篇

1.前言

  在笔者的上篇,中篇中给你介绍了alsa库的交叉编译和alsa官网提供的几个工具的应用,在下篇中,笔者将会介绍在实际项目中的应用。所有的alsa-lib提供的api可以在官网:http://www.alsa-project.org/alsa-doc/alsa-lib/index.html 中详细介绍各种api的用法和参数说明,在http://alsa-lib.sourcearchive.com/documentation/1.0.15/files.html介绍了alsa-lib各种api之间的调用关系,思维导图画的很不错,让人一看就明白。笔者这里不详细介绍这些函数,而是介绍笔者的一个项目。

2.软件架构设计

         在这套设计中,笔者将会用到aloop这个驱动,这个驱动从linux-2.6之后就引入内核,是alsa的虚拟声卡驱动。在ubuntu系统上面运行aplay -l 命令如下:

ccion@ubuntu:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC3202 Analog [ALC3202 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 1: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7

可以看到,card1就是aloop生成的虚拟声卡,总共提供了8个虚拟声卡。如果你的ubuntu系统中没有,请运行命令:

ccion@ubuntu:~$ sudo modprobe snd_aloop

在开发板中,在内核的编译选项中打开:CONFIG_SND_ALOOP=m 将其以模块的形式编进内核,然后通过modprobe来注册进内核。整个软件的音频路劲如下图:

解释:1.其中hw:1,0,0和hw:1,0,1是aloop提供的虚拟声卡,它们是一起的,你可以将其看做管道类似的东西,从这端扔数据进去,从另外一端出来。当然hw:1,0,0和hw:1,0,1既可以做capture也能做playback,但不能二者同时做一样的功能,当hw:1,0,0做playback模式,hw:1,0,1就作为capture功能了。

   2.从hw:1,0,1到真实的物理声卡会经过capture(开一个线程),然后在放入ringfifo中,最后通过playback(开一个线程)来将声音送入真实的物理声卡。关于声音怎么从上层流入到底层,请参考我的博客《Linux ALSA音频系统:声卡》一文。

  整体设计大概就是这样,这跟之前的有些aplay应用不一样,二个线程capture和playback是会一直工作,即playback在这里当音频播放完后,这里不会调用snd_pcm_close()函数,将声卡关闭,然后当音频数据来的时候,在次通过snd_pcm_open()来打开声卡。在aplay线程的部分应用中,你可以做EQ等等的处理。接下来就是放源码了,不多解释。

3.源码

首先是主程序部分alsa.c

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>

#include "alsa.h"

pcm_dev_t  tp_read_node;
pcm_dev_t  tp_write_node;

static int snd_pcm_dev_capture_init(pcm_dev_t *pcm_dev)
{
	
	int dir;
	int err;
	int write_dir;
	unsigned int val;
	snd_pcm_uframes_t frames;
	snd_pcm_uframes_t  periodSize = PERIOD_SIZE;
	snd_pcm_uframes_t  bufferSize = BUFFER_SIZE;
	snd_pcm_uframes_t write_final_buffer;
	snd_pcm_uframes_t write_final_period;
	if(pcm_dev == NULL){
		printf("pcm_dev null\n");
		goto error_pcm;
	}
	/* open PCM device for recording (capture) */
	err = snd_pcm_open(&pcm_dev->handle, pcm_dev->dev, pcm_dev->mode, 0);
	if(err){
		printf("Unable to open capture PCM device!\n");
		goto error_pcm;
	}

	/* Allocate a hardware parameters object*/
	snd_pcm_hw_params_alloca(&pcm_dev->params);
	snd_pcm_hw_params_any(pcm_dev->handle,pcm_dev->params);

	err = snd_pcm_hw_params_set_access(pcm_dev->handle, pcm_dev->params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if(err){
		printf("Error setting interleaved mode\n");
		goto error_pcm;
	}
	//set format
	err = snd_pcm_hw_params_set_format(pcm_dev->handle, pcm_dev->params, pcm_dev->formats);
	if(err){
		printf("Error setting format:%s\n",snd_strerror(err));
		goto error_pcm;
	}
	//set channels
	err = snd_pcm_hw_params_set_channels(pcm_dev->handle, pcm_dev->params , pcm_dev->channels);
	if(err){
		printf("Error setting channels:%s\n",snd_strerror(err));
		goto error_pcm;
	}
	//set rate
	err = snd_pcm_hw_params_set_rate_near(pcm_dev->handle,pcm_dev->params, &pcm_dev->rate, &dir);
	if(err){
		printf("Error setting sampling rate (%d):%s\n",pcm_dev->rate, snd_strerror(err));
		goto error_pcm;
	}
	//set buffer
	err = snd_pcm_hw_params_set_buffer_size_near(pcm_dev->handle,pcm_dev->params, &bufferSize);
	if(err){
		printf("Error setting buffer size (%d) :%s\n",bufferSize,snd_strerror(err));
		goto error_pcm;
	}
	//set period
	err = snd_pcm_hw_params_set_period_size_near(pcm_dev->handle,pcm_dev->params, &periodSize, 0);
	if(err){
		printf("Error setting period time (%d) :%s\n",periodSize, snd_strerror(err));
		goto error_pcm;
	}

	/*write the parameters to the driver */
	err = snd_pcm_hw_params(pcm_dev->handle,pcm_dev->params);
	if(err < 0){
		printf("Unable to set HW parameters:%s\n",snd_strerror(err));
		goto error_pcm;
	}
	return 1;
error_pcm:
	if(pcm_dev->handle) snd_pcm_close(pcm_dev->handle);
	return 0;
}


static int snd_pcm_dev_playback_init(pcm_dev_t *pcm_dev)
{
    int dir;
    int err;
    int write_dir;
    unsigned int  val;
    snd_pcm_uframes_t  frames;
    snd_pcm_uframes_t  periodSize = PERIOD_SIZE;
    snd_pcm_uframes_t  bufferSize = BUFFER_SIZE;
    snd_pcm_uframes_t  write_final_buffer;
    snd_pcm_uframes_t  write_final_period;
    if(pcm_dev == NULL){
        printf("pcm_dev null\n");
        goto  error_pcm;
    }
   /*open  playback dev */
    err = snd_pcm_open(&pcm_dev->handle, pcm_dev->dev, pcm_dev->mode, 0);
    if(err){
        printf("Unable to open capture PCM device!\n");
        goto error_pcm;
    }
    snd_pcm_hw_params_alloca(&pcm_dev->params);
    snd_pcm_hw_params_any(pcm_dev->handle , pcm_dev->params);

    err = snd_pcm_hw_params_set_access(pcm_dev->handle, pcm_dev->params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if(err){
        printf("Error setting interleaved mode\n");
        goto error_pcm;
    }
	//set format
	err = snd_pcm_hw_params_set_format(pcm_dev->handle, pcm_dev->params, pcm_dev->formats);
	if(err){
		printf("Error setting format:%s\n",snd_strerror(err));
		goto error_pcm;
	}
	//set channels
	err = snd_pcm_hw_params_set_channels(pcm_dev->handle, pcm_dev->params , pcm_dev->channels);
	if(err){
		printf("Error setting channels:%s\n",snd_strerror(err));
		goto error_pcm;
	}
	//set rate
	err = snd_pcm_hw_params_set_rate_near(pcm_dev->handle,pcm_dev->params, &pcm_dev->rate, &dir);
	if(err){
		printf("Error setting sampling rate (%d):%s\n",pcm_dev->rate, snd_strerror(err));
		goto error_pcm;
	}
	//set buffer
	err = snd_pcm_hw_params_set_buffer_size_near(pcm_dev->handle,pcm_dev->params, &bufferSize);
	if(err){
		printf("Error setting buffer size (%d) :%s\n",bufferSize,snd_strerror(err));
		goto error_pcm;
	}
	//set period
	err = snd_pcm_hw_params_set_period_size_near(pcm_dev->handle,pcm_dev->params, &periodSize, 0);
	if(err){
		printf("Error setting period time (%d) :%s\n",periodSize, snd_strerror(err));
		goto error_pcm;
	}
	//get final buffer
	err = snd_pcm_hw_params_get_buffer_size(pcm_dev->params, &write_final_buffer);
    printf("final buffer size :%ld \n",write_final_buffer);
	//get final period
	err = snd_pcm_hw_params_get_period_size(pcm_dev->params, &write_final_period,&write_dir);
	printf("final period size :%ld \n",write_final_period);
    /*attach sound for control */
    snd_mixer_selem_id_alloca(&pcm_dev->sid);
    if((err = snd_mixer_open(&pcm_dev->mixer_handle,0)) < 0){
         printf("mixer open err\n");
    }
    if((err = snd_mixer_attach(pcm_dev->mixer_handle,pcm_dev->card) <0)){
         printf("snd_attach error\n");
    }
    if((err = snd_mixer_selem_register(pcm_dev->mixer_handle, NULL, NULL)) < 0 ){
        printf("mixer register error\n");
    }
    err = snd_mixer_load(pcm_dev->mixer_handle);
    if(err == 0 ){
        printf("mixer load error\n");
		goto error_pcm;
    }
	/*write the parameters to the driver */
	err = snd_pcm_hw_params(pcm_dev->handle,pcm_dev->params);
	if(err < 0){
		printf("Unable to set HW parameters:%s\n",snd_strerror(err));
		goto error_pcm;
	}
    return 1;
    
error_pcm:
    if(pcm_dev->handle) snd_pcm_close(pcm_dev->handle);
    if(pcm_dev->mixer_handle) snd_mixer_close(pcm_dev->mixer_handle);
    return 0;

    
}
static int xrun_recovery(snd_pcm_t *handle, int err){
    if(err == -EPIPE){/*under-run*/
        err = snd_pcm_prepare(handle);
        if(err<0)
            printf("can't recovery from underrun ,prepare failed:%s\n",snd_strerror(err));
        return 0;
    }else if (err == -ESTRPIPE){
        while((err = snd_pcm_resume(handle)) == -EAGAIN)
            sleep(1);
        if(err < 0){
            err = snd_pcm_prepare(handle);
            if(err <0)
                printf("can't recovery from suspend,prepare failed:%s\n",snd_strerror(err));
        }
        return 0;
    }
    return err;
}
int pcm_dev_check_status(pcm_dev_t *pcm_dev){
    int  in;
    char line[255];
    int count = pcm_dev->count, cnt=pcm_dev->cnt;
    int last_running = pcm_dev->last_running;
    if (count++%cnt != 0){
        pcm_dev->count = count;
        pcm_dev->cnt = cnt;
        return pcm_dev->is_running;
    }
    in = open(pcm_dev->cdev, O_RDONLY);
    if(in){
        int size=0;
        size =read(in,line,sizeof(line));
        if(size >0){
            if(!strncmp(line,"state: RUNNING",14)){
                pcm_dev->is_running = 1;
            }else {
                pcm_dev->is_running = 0;
            }
        }
    }
    if(pcm_dev->is_running){
        cnt = 20;
    }else{
        cnt = 1;
    }
    if(last_running != pcm_dev->is_running && last_running == 0){
        count = 1;
        cnt = 40;
    }
    last_running = pcm_dev->is_running;
    pcm_dev->last_running = last_running;
    close(in);
    pcm_dev->count = count;
    pcm_dev->cnt = cnt;
    return pcm_dev->is_running;
}

void* pcm_data_queue(void* arg){
	int16_t size;
	int16_t buffer[READ_FRAME*4];
    int count = 0;
    int running =0;
	pcm_dev_t *p =(pcm_dev_t*)arg;
	while(1){
        // check each dev status  if  status = running ,readi data into ringfifo.
        // others   break  this loop ,jump other one loop.
        // usleep  = 20ms (there someting wrong  when the time = 10 ms)
        running = pcm_dev_check_status(p);
        if(!running){
             usleep(5000);
             continue;
        }
		//memset(&buffer,0,READ_FRAME*2);
		size = snd_pcm_readi(p->handle,buffer, READ_FRAME*2);
        if (size == -EAGAIN){
            continue;
        }
        if(size <0){
            if((size =snd_pcm_recover(p->handle,size,0))<0)
                   continue;
        }
        // ringfifo  full   must  clear READ_FRAME*2 size
        if(ringfifo_is_full(&p->fifo)){
            ringfifo_get_none(&p->fifo, READ_FRAME*4);     
		    if(count % 500 == 0){
                 printf("warning: ringfifo is full !!!,--->%s\n",p->dev);
            }
        }
		ringfifo_put(&p->fifo,buffer,size*2);
        memset(buffer,0,sizeof(buffer));
	}
}

void* audio_write_hw(void *arg)
{
    int streams_len;
    short *buffer_out;
    int size =0;
    int err;
	pthread_detach(pthread_self());
    buffer_out =(short *)malloc(READ_FRAME * 4);
    while(1){
        streams_len = ringfifo_get_entries(&tp_write_node.fifo);
        if(streams_len){
            size = ringfifo_get(&tp_write_node.fifo,buffer_out,READ_FRAME*2 );
            err = snd_pcm_writei(tp_write_node.handle,buffer_out,READ_FRAME);
            if(err == -EAGAIN)
                continue;
            if(err < 0){
                if(xrun_recovery(tp_write_node.handle,err) <0){
                    err = snd_pcm_recover(tp_write_node.handle,err,0);
                    if(err <0){
                        printf("Error occured while writing:%s\n",snd_strerror(err));
                    }
                    continue;
                }
            }
        }else{
            usleep(100*1000L);
            continue;
        }
    }
	pthread_exit(NULL);  
      
    
}

void main()
{
	int ret;
	//init capture
	memset(&tp_read_node,0,sizeof(pcm_dev_t));
	ringfifo_init(&tp_read_node.fifo);//ringfifo init
	tp_read_node.mode = SND_PCM_STREAM_CAPTURE;//mode
	tp_read_node.rate = SAMPLE_RATE_48000;//rate
	tp_read_node.channels = SAMPLE_CHANNELS_2;
	tp_read_node.formats = SND_PCM_FORMAT_S16_LE;
	tp_read_node.dev = "hw:1,0,1";
	tp_read_node.cdev = "/proc/asound/card1/pcm0p/sub0/status";
	snd_pcm_dev_capture_init(&tp_read_node);
	//init playback
	memset(&tp_write_node,0,sizeof(pcm_dev_t));
	tp_write_node.mode = SND_PCM_STREAM_PLAYBACK;
	tp_write_node.rate = SAMPLE_RATE_48000;
	tp_write_node.channels = SAMPLE_CHANNELS_2;
	tp_write_node.dev = "softvol";
	tp_write_node.formats = SND_PCM_FORMAT_S16_LE;
	tp_write_node.card = "default";
	snd_pcm_dev_playback_init(&tp_write_node);
	ret = pthread_create(&tp_read_node.au_pthreads, NULL,&pcm_data_queue,&tp_read_node);
	if(ret !=0){
		printf("Note: create pthread error\n");
		return;
	}
	ret = pthread_create(&tp_write_node.au_pthreads, NULL,&audio_write_hw,&tp_write_node);
	if(ret != 0){
		printf("Note: create pthread error\n");
		return;
	}
	while(1){
		sleep(1);
	}
}

其中:snd_pcm_dev_capture_init()是初始化capture部分,snd_pcm_dev_playback_init()是初始化playback部分。在主程序中你可以看到tp_write_node.dev = "softvol", tp_write_node.card="default",这个跟asound.conf(/etc/)有关,在之后的篇幅中,我将单独讲解一篇asound.conf,它很重要,alsa的很多接口,插件通过这个文件来配置。

然后再是alsa.h

扫描二维码关注公众号,回复: 5865192 查看本文章
#ifndef  __ALSA_H__
#define  __ALSA_H__
#ifdef  __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <unistd.h>
#include <pthread.h>
#include "ring.h"

#define SAMPLE_RATE_48000      48000
#define SAMPLE_RATE            48000
#define SAMPLE_CHANNELS_2      2
#define READ_FRAME             512
#define BUFFER_SIZE            (READ_FRAME * 8)
#define PERIOD_SIZE            (READ_FRAME * 2)

typedef struct{
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    snd_mixer_t  *mixer_handle;
    snd_mixer_elem_t *elem;
    snd_mixer_selem_id_t *sid;
    snd_pcm_stream_t  mode;
    snd_pcm_format_t formats;
    const char   *dev;
    const char   *cdev;
    const char   *card;
    unsigned  int  rate;
    unsigned int channels;
    ring_fifo_t fifo;
    pthread_t au_pthreads;
    int count;
    int cnt;
    int is_running;
    int last_running;

}pcm_dev_t;



#ifdef __cplusplus
}
#endif
#endif

再就是ring.c你直接调用就行,不需要把整个ring看懂。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>

#include "ring.h"

int ringfifo_init(ring_fifo_t * fifo)
{
	fifo->head = 0;
	fifo->tail = 0;
	fifo->cur_entries = 0;
	fifo->max_entries = FIFO_MAX_ENTRIES;
	fifo->len_input = 0;
	fifo->len_output = 0;
	memset(fifo->buf, 0, fifo->max_entries * 2);

	pthread_mutex_init(&fifo->mutex, NULL);

	return 0;
}
int ringfifo_close(ring_fifo_t * fifo)
{
	pthread_mutex_destroy(&fifo->mutex);
//	free(fifo->buf);
	return 0;
}
inline long get_fifo_pos(int pos)
{
	return 0;
}
int ringfifo_get_none(ring_fifo_t *fifo, int len)
{
	int i;
	if(fifo->cur_entries < len)
		len = fifo->cur_entries;

	if(len == 0) return 0;
	pthread_mutex_lock(&fifo->mutex);
	for(i=0; i<len; i++){
		fifo->head++;
		if(fifo->head == fifo->max_entries)
			fifo->head = 0;
	}
	fifo->cur_entries -= len;
	fifo->len_output += len;
	pthread_mutex_unlock(&fifo->mutex);

	return len;
}
int ringfifo_get(ring_fifo_t *fifo, int16_t *buf, int len)
{
	int i;
	if(fifo->cur_entries < len)
		len = fifo->cur_entries;

	if(len == 0) return 0;

	pthread_mutex_lock(&fifo->mutex);
	for(i=0; i<len; i++){
		buf[i] = fifo->buf[fifo->head++];
		if(fifo->head == fifo->max_entries)
			fifo->head = 0;
	}
	fifo->cur_entries -= len;
	fifo->len_output += len;
	pthread_mutex_unlock(&fifo->mutex);

	return len;
}
int ringfifo_put(ring_fifo_t *fifo, int16_t *buf, int len)
{
	int i, residue = fifo->max_entries - fifo->cur_entries;
	if(len > residue) len = residue;

	pthread_mutex_lock(&fifo->mutex);
	if(len == 1){
		fifo->buf[fifo->tail++] = buf[0];
		if(fifo->tail == fifo->max_entries)
			fifo->tail = 0;
	}else{
		for(i=0; i<len; i++){
			fifo->buf[fifo->tail++] = buf[i];
			if(fifo->tail == fifo->max_entries)
				fifo->tail = 0; 
		}
	}
	fifo->cur_entries += len;
	fifo->len_input += len;
	pthread_mutex_unlock(&fifo->mutex);

	return len;
}
int ringfifo_put_mix(ring_fifo_t *fifo, int16_t *buf, int len)
{
	int i, residue = fifo->max_entries - fifo->cur_entries;
	if(len > residue) len = residue;

	pthread_mutex_lock(&fifo->mutex);
	if(fifo->cur_entries != 0){
		int flag = 0;
		int pos = fifo->head;
		for(i=0; i<len; i++){
			if(pos == fifo->tail) flag = 1;
			if(!flag)
				fifo->buf[pos++] += buf[i];
			else
				fifo->buf[pos++] = buf[i];

			if(pos == fifo->max_entries)
				pos = 0; 
		}

		fifo->tail = (len > fifo->cur_entries) ? (fifo->head + len): fifo->tail;
		if(fifo->tail >= fifo->max_entries) fifo->tail -= fifo->max_entries;

		fifo->cur_entries = (len > fifo->cur_entries) ? len : fifo->cur_entries;
	}else{
		if(len == 1){
			fifo->buf[fifo->tail++] = buf[0];
			if(fifo->tail == fifo->max_entries)
				fifo->tail = 0;
		}else{
			for(i=0; i<len; i++){
				fifo->buf[fifo->tail++] = buf[i];
				if(fifo->tail == fifo->max_entries)
					fifo->tail = 0; 
			}
		}
		fifo->cur_entries += len;
	}
	pthread_mutex_unlock(&fifo->mutex);

	return len;
}

int ringfifo_is_full(ring_fifo_t *fifo){
	int full = 0;
	pthread_mutex_lock(&fifo->mutex);
    if(fifo->cur_entries == fifo->max_entries){
        full = 1;
    }
	pthread_mutex_unlock(&fifo->mutex);
	return full;
}
int ringfifo_get_entries(ring_fifo_t *fifo){
	int entries;
	pthread_mutex_lock(&fifo->mutex);
	entries = fifo->cur_entries;
	pthread_mutex_unlock(&fifo->mutex);
	return entries;
}


int ringfifo_test(void)
{
#define DATA_LEN 1024
	int i, j, len, index = 0, put, get;
	int16_t buf[DATA_LEN], data[48];
	ring_fifo_t fifo;

	ringfifo_init(&fifo);

	for(i=0; i< DATA_LEN; i++)
		buf[i] = i;

	put = 8;
	get = 4;
	for(i=0; i<100; i++){
		printf("\ncount:%d => ", i);
		if(fifo.cur_entries < fifo.max_entries){
			if((index + put) < DATA_LEN){
				len = ringfifo_put(&fifo, &buf[index], put);
				index += len;
				printf("put[%d] ", len);
			}
		}

		len = ringfifo_get(&fifo, data, get);
		printf("get: ");
		for(j=0; j<len ; j++)
			printf("%d ", data[j]); 
	}
	ringfifo_close(&fifo);

	printf("\n\nRing FiFo Test End!!!\n");
	exit(1);

	return 0;	
}
#ifndef __RING_H__
#define __RING_H__
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <pthread.h>

//#define FIFO_MAX_ENTRIES (1024*1024)
#define FIFO_MAX_ENTRIES (200*1024)
//#define FIFO_MAX_ENTRIES (64)
/* Ring FiFo */
typedef struct ring_fifo {
int head;
int tail;
int cur_entries;
int max_entries;
int len_input;
int len_output;
int data_ready;
int data_type;
int data_size;
int data_index;
int data_offset;
int data_pos;
pthread_mutex_t mutex;
int16_t buf[FIFO_MAX_ENTRIES];
} ring_fifo_t;

int ringfifo_init(ring_fifo_t * fifo);
int ringfifo_close(ring_fifo_t * fifo);
int ringfifo_get(ring_fifo_t *fifo, int16_t *buf, int len);
int ringfifo_put(ring_fifo_t *fifo, int16_t *buf, int len);
int ringfifo_put_mix(ring_fifo_t *fifo, int16_t *buf, int len);
int ringfifo_get_entries(ring_fifo_t *fifo);
int ringfifo_is_full(ring_fifo_t *fifo);
int ringfifo_get_none(ring_fifo_t *fifo, int len);
#ifdef __cplusplus
}
#endif
#endif

最后,基于笔者的开发平台的makefile.

TOPDIR=~/work/muno/
CUR_DIR=$(dirname $0)

ifdef mips
CROSS_COMPILE=mipsel-linux-
CFLAGS = -DCONFIG_MIPS
endif

ifdef arm
CROSS_COMPILE=arm-linux-androideabi-
CFLAGS = -DCONFIG_ARM
endif

ifdef armhf
CROSS_COMPILE=arm-linux-gnueabihf-
CFLAGS = -DCONFIG_ARM
endif

ifdef aarch64
CROSS_COMPILE=aarch64-linux-gnu-
CFLAGS = -DCONFIG_ARM 
endif

CC = ${CROSS_COMPILE}gcc
CXX = ${CROSS_COMPILE}g++
LIBS =

CFLAGS += -O2
CPPFLAGS += $(CFLAGS) -std=c++11
LDFLAGS += -lasound -lpthread 

INC=

OBJECTS = $(SOURCES:.cpp=.o)
PRJOBJS = alsa.o ring.o 
OBJECTS_INC = ring.h alsa.h

PRJNAME = alsa_test

all: $(PRJNAME) 


$(PRJNAME):$(OBJECTS) $(PRJOBJS) $(OBJECTS_INC)
	$(CXX) -o $@ $(LDFLAGS) $(OBJECTS) $(PRJOBJS) $(LIBS)
.c.o:
	$(CC)  $(INC) $(CFLAGS) -c -o $@ $<

.cpp.o:
	$(CXX)  $(INC) $(CPPFLAGS) -c -o $@ $<

clean:
	rm -rf $(OBJECTS) $(PRJOBJS) $(PRJNAME) *.so *.o

通过运行make armhf=1.笔者的电脑上面得到,alsa_test的可执行程序。

ccion@ubuntu:~/ccion/alsa/test$ make armhf=1
arm-linux-gnueabihf-gcc   -DCONFIG_ARM -O2 -c -o alsa.o alsa.c
arm-linux-gnueabihf-gcc   -DCONFIG_ARM -O2 -c -o ring.o ring.c
arm-linux-gnueabihf-g++ -o alsa_test -lasound -lpthread   alsa.o ring.o  
ccion@ubuntu:~/ccion/alsa/test$ ls
alsa.c  alsa.h  alsa.o  alsa_test  Makefile  ring.c  ring.h  ring.o

猜你喜欢

转载自blog.csdn.net/weixin_41965270/article/details/81270015