Linux下使用alsa-lib库实现放音和录音

参考代码:从声卡获取PCM数据,实现录音功能

下面代码在命令行通过gcc编译运行:  读取声卡数据,保存为文件,结束录音可以按下Ctrl+C即可结束。

/*
 进行音频采集,采集pcm数据并直接保存pcm数据
 音频参数: 
     声道数:       1
     采样位数:  16bit、LE格式
     采样频率:  44100Hz
运行示例:
$ gcc linux_pcm_save.c -lasound
$ ./a.out hw:0 123.pcm

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <signal.h>
 
#define AudioFormat SND_PCM_FORMAT_S16_LE  //指定音频的格式,其他常用格式:SND_PCM_FORMAT_U24_LE、SND_PCM_FORMAT_U32_LE
#define AUDIO_CHANNEL_SET   1                //1单声道   2立体声
#define AUDIO_RATE_SET 44100   //音频采样率,常用的采样频率: 44100Hz 、16000HZ、8000HZ、48000HZ、22050HZ
 
FILE *pcm_data_file=NULL;
int run_flag=0;
void exit_sighandler(int sig)
{
    run_flag=1;
}
 
int main(int argc, char *argv[])
{
    int i;
    int err;
    char *buffer;
    int buffer_frames = 1024;
    unsigned int rate = AUDIO_RATE_SET;
    snd_pcm_t *capture_handle;// 一个指向PCM设备的句柄
    snd_pcm_hw_params_t *hw_params; //此结构包含有关硬件的信息,可用于指定PCM流的配置
    
    /*注册信号捕获退出接口*/
    signal(2,exit_sighandler);
 
    /*PCM的采样格式在pcm.h文件里有定义*/
    snd_pcm_format_t format=AudioFormat; // 采样位数:16bit、LE格式
 
    /*打开音频采集卡硬件,并判断硬件是否打开成功,若打开失败则打印出错误提示*/
    // SND_PCM_STREAM_PLAYBACK 输出流
    // SND_PCM_STREAM_CAPTURE  输入流
    if ((err = snd_pcm_open (&capture_handle, argv[1],SND_PCM_STREAM_CAPTURE,0))<0) 
    {
        printf("无法打开音频设备: %s (%s)\n",  argv[1],snd_strerror (err));
        exit(1);
    }
    printf("音频接口打开成功.\n");
 
    /*创建一个保存PCM数据的文件*/
    if((pcm_data_file = fopen(argv[2], "wb")) == NULL)
    {
        printf("无法创建%s音频文件.\n",argv[2]);
        exit(1);
    } 
    printf("用于录制的音频文件已打开.\n");
 
    /*分配硬件参数结构对象,并判断是否分配成功*/
    if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) 
    {
        printf("无法分配硬件参数结构 (%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("硬件参数结构已分配成功.\n");
    
    /*按照默认设置对硬件对象进行设置,并判断是否设置成功*/
    if((err=snd_pcm_hw_params_any(capture_handle,hw_params)) < 0) 
    {
        printf("无法初始化硬件参数结构 (%s)\n", snd_strerror(err));
        exit(1);
    }
    printf("硬件参数结构初始化成功.\n");
 
    /*
        设置数据为交叉模式,并判断是否设置成功
        interleaved/non interleaved:交叉/非交叉模式。
        表示在多声道数据传输的过程中是采样交叉的模式还是非交叉的模式。
        对多声道数据,如果采样交叉模式,使用一块buffer即可,其中各声道的数据交叉传输;
        如果使用非交叉模式,需要为各声道分别分配一个buffer,各声道数据分别传输。
    */
    if((err = snd_pcm_hw_params_set_access (capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 
    {
        printf("无法设置访问类型(%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("访问类型设置成功.\n");
 
    /*设置数据编码格式,并判断是否设置成功*/
    if ((err=snd_pcm_hw_params_set_format(capture_handle, hw_params,format)) < 0) 
    {
        printf("无法设置格式 (%s)\n",snd_strerror(err));
        exit(1);
    }
    fprintf(stdout, "PCM数据格式设置成功.\n");
 
    /*设置采样频率,并判断是否设置成功*/
    if((err=snd_pcm_hw_params_set_rate_near(capture_handle,hw_params,&rate,0))<0) 
    {
        printf("无法设置采样率(%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("采样率设置成功\n");
 
    /*设置声道,并判断是否设置成功*/
    if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,AUDIO_CHANNEL_SET)) < 0) 
    {
        printf("无法设置声道数(%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("声道数设置成功.\n");
 
    /*将配置写入驱动程序中,并判断是否配置成功*/
    if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0) 
    {
        printf("无法向驱动程序设置参数(%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("参数设置成功.\n");
 
    /*使采集卡处于空闲状态*/
    snd_pcm_hw_params_free(hw_params);
 
    /*准备音频接口,并判断是否准备好*/
    if((err=snd_pcm_prepare(capture_handle))<0) 
    {
        printf("无法使用音频接口 (%s)\n",snd_strerror(err));
        exit(1);
    }
    printf("音频接口准备好.\n");
 
    /*配置一个数据缓冲区用来缓冲数据*/
    //snd_pcm_format_width(format) 获取样本格式对应的大小(单位是:bit)
    int frame_byte=snd_pcm_format_width(format)/8;
    buffer=malloc(buffer_frames*frame_byte*AUDIO_CHANNEL_SET); //2048
    printf("缓冲区分配成功.\n");
    
    /*开始采集音频pcm数据*/
    printf("开始采集数据...\n");
    while(1) 
    {
        /*从声卡设备读取一帧音频数据:2048字节*/
        if((err=snd_pcm_readi(capture_handle,buffer,buffer_frames))!=buffer_frames) 
        {
              printf("从音频接口读取失败(%s)\n",snd_strerror(err));
              exit(1);
        }
        /*写数据到文件: 音频的每帧数据样本大小是16位=2个字节*/
        fwrite(buffer,(buffer_frames*AUDIO_CHANNEL_SET),frame_byte,pcm_data_file);    
        if(run_flag)
        {
            printf("停止采集.\n");
            break;
        }
    }
 
    /*释放数据缓冲区*/
    free(buffer);
 
    /*关闭音频采集卡硬件*/
    snd_pcm_close(capture_handle);
 
    /*关闭文件流*/
    fclose(pcm_data_file);
    return 0;
}
 

四、参考代码:从文件读取PCM数据,再写入到声卡设备,实现声音播放功能

下面代码在命令行通过gcc编译运行:  读取文件PCM音频数据,写入到声卡进行播放,结束播放可以按下Ctrl+C即可结束。

  1 /*
  2  进行音频采集,读取存放pcm数据的文件通过声卡进行播放
  3  音频参数: 
  4      声道数:        1
  5      采样位数:    16bit、LE格式
  6      采样频率:    44100Hz
  7      
  8 运行示例:
  9 $ gcc linux_pcm_save.c -lasound
 10 $ ./a.out hw:0 123.pcm
 11 */
 12  
 13 #include <stdio.h>
 14 #include <stdlib.h>
 15 #include <alsa/asoundlib.h>
 16 #include <signal.h>
 17  
 18 #define AudioFormat SND_PCM_FORMAT_S16_LE  //指定音频的格式,其他常用格式:SND_PCM_FORMAT_U24_LE、SND_PCM_FORMAT_U32_LE
 19 #define AUDIO_CHANNEL_SET   1                //1单声道   2立体声
 20 #define AUDIO_RATE_SET 44100   //音频采样率,常用的采样频率: 44100Hz 、16000HZ、8000HZ、48000HZ、22050HZ
 21  
 22 FILE *pcm_data_file=NULL;
 23 int run_flag=0;
 24 void exit_sighandler(int sig)
 25 {
 26     run_flag=1;
 27 }
 28  
 29  
 30 //
 31 int main(int argc, char *argv[])
 32 {
 33     int i;
 34     int err;
 35     char *buffer;
 36     int buffer_frames = 1024;
 37     unsigned int rate = AUDIO_RATE_SET;
 38     snd_pcm_t *capture_handle;// 一个指向PCM设备的句柄
 39     snd_pcm_hw_params_t *hw_params; //此结构包含有关硬件的信息,可用于指定PCM流的配置
 40     
 41     /*注册信号捕获退出接口*/
 42     signal(2,exit_sighandler);
 43  
 44     /*PCM的采样格式在pcm.h文件里有定义*/
 45     snd_pcm_format_t format=AudioFormat; // 采样位数:16bit、LE格式
 46  
 47     /*打开音频采集卡硬件,并判断硬件是否打开成功,若打开失败则打印出错误提示*/
 48     // SND_PCM_STREAM_PLAYBACK 输出流
 49     // SND_PCM_STREAM_CAPTURE  输入流
 50     if ((err = snd_pcm_open (&capture_handle, argv[1],SND_PCM_STREAM_PLAYBACK,0))<0) 
 51     {
 52         printf("无法打开音频设备: %s (%s)\n",  argv[1],snd_strerror (err));
 53         exit(1);
 54     }
 55     printf("音频接口打开成功.\n");
 56  
 57     /*打开存放PCM数据的文件*/
 58     if((pcm_data_file = fopen(argv[2], "rb")) == NULL)
 59     {
 60         printf("无法打开%s音频文件.\n",argv[2]);
 61         exit(1);
 62     } 
 63     printf("用于播放的音频文件已打开.\n");
 64  
 65     /*分配硬件参数结构对象,并判断是否分配成功*/
 66     if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) 
 67     {
 68         printf("无法分配硬件参数结构 (%s)\n",snd_strerror(err));
 69         exit(1);
 70     }
 71     printf("硬件参数结构已分配成功.\n");
 72     
 73     /*按照默认设置对硬件对象进行设置,并判断是否设置成功*/
 74     if((err=snd_pcm_hw_params_any(capture_handle,hw_params)) < 0) 
 75     {
 76         printf("无法初始化硬件参数结构 (%s)\n", snd_strerror(err));
 77         exit(1);
 78     }
 79     printf("硬件参数结构初始化成功.\n");
 80  
 81     /*
 82         设置数据为交叉模式,并判断是否设置成功
 83         interleaved/non interleaved:交叉/非交叉模式。
 84         表示在多声道数据传输的过程中是采样交叉的模式还是非交叉的模式。
 85         对多声道数据,如果采样交叉模式,使用一块buffer即可,其中各声道的数据交叉传输;
 86         如果使用非交叉模式,需要为各声道分别分配一个buffer,各声道数据分别传输。
 87     */
 88     if((err = snd_pcm_hw_params_set_access (capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 
 89     {
 90         printf("无法设置访问类型(%s)\n",snd_strerror(err));
 91         exit(1);
 92     }
 93     printf("访问类型设置成功.\n");
 94  
 95     /*设置数据编码格式,并判断是否设置成功*/
 96     if ((err=snd_pcm_hw_params_set_format(capture_handle, hw_params,format)) < 0) 
 97     {
 98         printf("无法设置格式 (%s)\n",snd_strerror(err));
 99         exit(1);
100     }
101     fprintf(stdout, "PCM数据格式设置成功.\n");
102  
103     /*设置采样频率,并判断是否设置成功*/
104     if((err=snd_pcm_hw_params_set_rate_near(capture_handle,hw_params,&rate,0))<0) 
105     {
106         printf("无法设置采样率(%s)\n",snd_strerror(err));
107         exit(1);
108     }
109     printf("采样率设置成功\n");
110  
111     /*设置声道,并判断是否设置成功*/
112     if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,AUDIO_CHANNEL_SET)) < 0) 
113     {
114         printf("无法设置声道数(%s)\n",snd_strerror(err));
115         exit(1);
116     }
117     printf("声道数设置成功.\n");
118  
119     /*将配置写入驱动程序中,并判断是否配置成功*/
120     if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0) 
121     {
122         printf("无法向驱动程序设置参数(%s)\n",snd_strerror(err));
123         exit(1);
124     }
125     printf("参数设置成功.\n");
126  
127     /*使采集卡处于空闲状态*/
128     snd_pcm_hw_params_free(hw_params);
129  
130     /*准备音频接口,并判断是否准备好*/
131     if((err=snd_pcm_prepare(capture_handle))<0) 
132     {
133         printf("无法使用音频接口 (%s)\n",snd_strerror(err));
134         exit(1);
135     }
136     printf("音频接口准备好.\n");
137  
138     /*配置一个数据缓冲区用来缓冲数据*/
139     //snd_pcm_format_width(format) 获取样本格式对应的大小(单位是:bit)
140     int frame_byte=snd_pcm_format_width(format)/8;
141     buffer=malloc(buffer_frames*frame_byte*AUDIO_CHANNEL_SET);
142     printf("缓冲区分配成功.\n");
143     
144     /*开始采集音频pcm数据*/
145     printf("开始播放音频数据...\n");
146     
147     int read_cnt;
148     while(1) 
149     {
150         /*从文件读取数据: 音频的每帧数据样本大小是16位-2个字节*/
151         read_cnt=fread(buffer,1,frame_byte*(buffer_frames*AUDIO_CHANNEL_SET),pcm_data_file);
152         if(read_cnt<=0)break;
153         
154         /*向声卡设备写一帧音频数据:2048字节*/
155         if((err=snd_pcm_writei(capture_handle,buffer,buffer_frames))!=buffer_frames) 
156         {
157               printf("向音频接口写数据失败(%s)\n",snd_strerror(err));
158               exit(1);
159         }
160             
161         if(run_flag)
162         {
163             printf("停止播放.\n");
164             break;
165         }
166     }
167     printf("播放完成.\n");
168     /*释放数据缓冲区*/
169     free(buffer);
170  
171     /*关闭音频采集卡硬件*/
172     snd_pcm_close(capture_handle);
173  
174     /*关闭文件流*/
175     fclose(pcm_data_file);
176     return 0;
177 }
178  

 

posted @ 2025-11-10 10:41  张大帅哥  阅读(51)  评论(0)    收藏  举报