Linux声卡录音程序之——mp3(通过ALSA操作声卡)

本文转载自博客:http://blog.sina.com.cn/s/blog_936739790101b4og.html

————————————————--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

此程序通过ALSA打开声卡设备,和从声卡读取数据,避免直接操作声卡。由于不同主机,不同声卡的名字可能不一样,直接通过设备名操作声卡有局限性,故改进成通过ALSA操作。



#include "lame.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
//#include <signal.h>
//#include <sys/ioctl.h>
#include <memory.h>
//#include <linux/soundcard.h>
#include <alsa/asoundlib.h>
#include <sys/time.h>

#define TIMES 

    10    //录音时间,秒
#define RATE      41000 //采样频率
#define BITS      16    //量化位数
#define CHANNELS 2    //声道数目
#define INBUFF_SIZE 4096
#define MP3BUFF_SIZE (int) (1.25 * INBUFF_SIZE) + 7200

// handle the case of underrun or overrun
int xrun(snd_pcm_t* handle);
// handle the case that device busy
int suspend(snd_pcm_t* handle);
// set alsa params
int SetFormat(snd_pcm_t* handle, unsigned int channels, unsignedint rate)
{
      int ret =0;
     
      ret =snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 1, 500000);
      if (ret !=0) {
            printf("Unable to set params,error(%s)\n",snd_strerror(ret));
      }

      returnret;
}

int main(int argc, char **argv)
{
      intfd_dsp;
      FILE*fd_tmp;
      FILE*fd_mp3;
      lame_global_flags* gfp;
      short*input_buff;
      unsignedchar *mp3_buff;

      intsamples;
      intmp3_bytes;
      intwrite_bytes;
      int num =0;
      intch;
      int i =0;
      int ret =0;
      snd_pcm_t*handle;

      if (argc !=2) {
              fprintf(stderr, "Useage: ./mp3_record test.mp3\n");
              return -1;
      }

      if(snd_pcm_open(&handle, "default",SND_PCM_STREAM_CAPTURE, 0) != 0) {
              printf("Failed to open device\n");
              return -1;
      }
      if(SetFormat(handle, CHANNELS, RATE) != 0) {
              printf("Cannot set sound device in bit 16, channel 2, speed44100.\n");
              return -1;
      }

      if ((fd_mp3= fopen(argv[1], "w")) == NULL) {
              fprintf(stderr, "Open file error: %s\n", strerror(errno));
              ret = -1;
              goto CLOSE_DSP;
      }
      gfp =lame_init();
      if (gfp ==NULL) {
              printf("lame_init failed\n");
              ret = -1;
              goto CLOSE_MP3;
      }

      lame_set_in_samplerate(gfp, RATE);
      //lame_set_out_samplerate(gfp, RATE);
      lame_set_num_channels(gfp, CHANNELS);
      //lame_set_brate(gfp, 24);
      //lame_set_VBR_min_bitrate_kbps(gfp, lame_get_brate(gfp));
      //lame_set_quality(gfp,7);
      ret =lame_init_params(gfp);
      if (ret< 0) {
              printf("lame_init_params returned %d\n", ret);
              ret = -1;
              goto CLOSE_LAME;
      }
      ch =lame_get_num_channels(gfp);
      printf("default rate is %d, out rate is %d.\n",lame_get_in_samplerate(gfp), lame_get_out_samplerate(gfp));
      printf("default brate is %d.\n", lame_get_brate(gfp));
      printf("default samples is %lu.\n",lame_get_num_samples(gfp));
      printf("default channel is %d.\n", ch);
      printf("default vbr_mode is %d.\n", lame_get_VBR(gfp));
      printf("default force_ms is %d.\n", lame_get_force_ms(gfp));
      printf("default mode is %d.\n", lame_get_mode(gfp));
      printf("default compression_ratio is %f.\n",lame_get_compression_ratio(gfp));
      printf("default VBR_mean_bitrate is %d.\n",lame_get_VBR_mean_bitrate_kbps(gfp));
      printf("default quality is %d.\n", lame_get_quality(gfp));
     

      input_buff =(short *) malloc(INBUFF_SIZE * CHANNELS);
      mp3_buff =(unsigned char *) malloc(MP3BUFF_SIZE);
      if(input_buff == NULL || mp3_buff == NULL) {
              printf("Failed to malloc.\n");
              goto FREE_BUF;
      }

      if((TIMES*RATE*BITS*CHANNELS/8)%(INBUFF_SIZE * CHANNELS) != 0)
              num = (TIMES*RATE*BITS*CHANNELS/8)/(INBUFF_SIZE * CHANNELS) +1;
      else
              num = (TIMES*RATE*BITS*CHANNELS/8)/(INBUFF_SIZE * CHANNELS);
      for(i = 0; i< num; i++) {
              memset(input_buff, 0, INBUFF_SIZE * CHANNELS);
              memset(mp3_buff, 0, MP3BUFF_SIZE);
#if 0
              samples = read(fd_dsp, input_buff, INBUFF_SIZE * 2);
              if (samples < 0) {
                      perror("Read sound device failed");
                      ret = -1;
                      goto FREE_BUF;
              }
                      printf("samples is %d.\n", samples);
#endif


      samples =ret = snd_pcm_readi(handle, input_buff, INBUFF_SIZE/2);
      if (ret ==-EAGAIN || (ret >= 0&& (size_t)ret <INBUFF_SIZE/2)) {
            snd_pcm_wait(handle, 1000);
              goto FREE_BUF;
      } else if(ret == -EBADFD){      // PCM isnot in the right state
            printf("PCMis not in the right state!\n "); // EPIPE means underrun
              goto FREE_BUF;
      }
      else if(ret== -EPIPE){              // an overrun occurred
            printf("anoverrun occurred. samples = %d\n", samples);
            if(xrun(handle) < 0) {
                      goto FREE_BUF;
            }

      } elseif(ret == -ESTRPIPE) {    // asuspend event occurred
            printf("asuspend event occurred\n");
            if(suspend(handle) < 0) {
                      goto FREE_BUF;
              }
      }

        //printf("samples is %d.\n", samples);

                     
      mp3_bytes =lame_encode_buffer_interleaved(gfp, input_buff, samples, mp3_buff,MP3BUFF_SIZE);
      //mp3_bytes= lame_encode_buffer(gfp, input_buff, NULL, samples, mp3_buff,MP3BUFF_SIZE);
      //printf("mp3_bytes is %d.\n", mp3_bytes);
      if(mp3_bytes < 0) {
              printf("lame_encode_buffer_interleaved returned %d\n",mp3_bytes);
              ret = -1;
              goto FREE_BUF;
      }
      write_bytes= fwrite(mp3_buff, 1, mp3_bytes, fd_mp3);
      if(write_bytes < 0) {
              perror("Write sound data file failed\n");
              ret = -1;
              goto FREE_BUF;
      } elsefflush(fd_mp3);
      }
      mp3_bytes =lame_encode_flush(gfp, mp3_buff, sizeof(mp3_buff));
      if(mp3_bytes > 0) {
              printf("Writing %d mp3 bytes.\n", mp3_bytes);
              if (fwrite(mp3_buff, 1, mp3_bytes, fd_mp3) != (unsignedint)mp3_bytes)
                      printf("'Writing mp3 bytes error.\n");
              else
                      fflush(fd_mp3);
      } else
              printf("Writing mp3 bytes 0.\n");
                     
      FREE_BUF:
      if (mp3_buff!= NULL) { free(mp3_buff);
      mp3_buff =NULL; }
      if(input_buff != NULL) { free(input_buff);
      input_buff =NULL; }
     
      CLOSE_LAME:lame_close(gfp);
      CLOSE_MP3:fclose(fd_mp3);
      CLOSE_DSP:
      snd_pcm_drain(handle);
      snd_pcm_close(handle);

      EXIT: returnret;
}

int xrun(snd_pcm_t* handle)
{
      snd_pcm_status_t *status = NULL;
      intret;
      int verbose= 0;

      snd_pcm_status_alloca(&status);
      if ((ret =snd_pcm_status(handle, status)) < 0) {
            printf("status error: %d \n", ret);
            return-1;
      }

      if(snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
            structtimeval now, diff, tstamp;
            gettimeofday(&now, 0);
            snd_pcm_status_get_trigger_tstamp(status,&tstamp);
            timersub(&now, &tstamp,&diff);
            fprintf(stderr, "overrun!!! (at least %.3f ms long)\n", diff.tv_sec* 1000 + diff.tv_usec / 1000.0);
            if (verbose){
                  printf("Status:\n");
                  //snd_pcm_status_dump(status, _log);
            }

            if ((ret =snd_pcm_prepare(handle)) < 0) {
                  printf("xrun: prepare error:%d\n", ret);
                  return-1;
            }
            return1;        // ok, data should be accepted again
      }

      if(snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING){
            if (verbose){
                  printf("Status(DRAINING):\n");
                  //snd_pcm_status_dump(status, _log);
            }

            printf("capture stream format change? attemptingrecover...\n");
            if ((ret =snd_pcm_prepare(handle)) < 0) {
                  printf("xrun(DRAINING): prepare error: %d\n", ret);
                  return-1;
            }
            return1;
      }
      if (verbose){
            printf("Status(R/W):\n");
            //snd_pcm_status_dump(status, _log);
      }
      printf("read/write error, state = %s\n",snd_pcm_state_name(snd_pcm_status_get_state(status)));
      return-1;
}

// handle the case that device busy
int suspend(snd_pcm_t* handle)
{
      intret;

      while ((ret= snd_pcm_resume(handle)) ==-EAGAIN)      //Resume from suspend.
            sleep(1);        // resume can't be proceed immediately, waituntil suspend flag is released

      if (ret< 0) {    //-ENOSYS hardware doesn't support this feature
            if ((ret =snd_pcm_prepare(handle)) < 0) {
                  printf("suspend: prepare error: %d", ret);
                  return-1;
            }
      }
      return1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值