Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304955
  • 博文数量: 68
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 706
  • 用 户 组: 普通用户
  • 注册时间: 2015-08-13 14:58
文章分类

全部博文(68)

文章存档

2021年(4)

2020年(6)

2018年(5)

2017年(13)

2016年(8)

2015年(32)

我的朋友

分类: LINUX

2016-12-24 12:39:56

portaudio是一个跨平台音频库,类似于SDL作为跨平台图像库一样,只是在系统原生音频库(alsa、oss)上封装了一层

portaudio自带的录音示例代码只有同步IO模式,没有异步IO模式,而异步IO能释放主线程,是更好的方式

为了实现异步,需要定义回调函数,在回调函数里将音频数据不断写入文件

为了实现任意长度,需要引入无限循环,但该无限循环要能根据用户的输入及时退出。

为此可选择挂接signal处理器,监听ctrl-c组合键发送的SIGINT信号,在信号里置标志位;

回调函数检查标志位,发现置位就关闭音频流,从而使无限循环退出

不说了,上代码


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include "portaudio.h"  
  6.   
  7. /* #define SAMPLE_RATE  (17932) // Test failure to open with this value. */  
  8. #define SAMPLE_RATE  (16000)  
  9. #define FRAMES_PER_BUFFER (SAMPLE_RATE/1000*200)  
  10. #define NUM_SECONDS     (5)  
  11. #define NUM_CHANNELS    (1)  
  12. /* #define DITHER_FLAG     (paDitherOff)  */  
  13. #define DITHER_FLAG     (0) /**/  
  14.   
  15. /* Select sample format. */  
  16. #if 0  
  17. #define PA_SAMPLE_TYPE  paFloat32  
  18. typedef float SAMPLE;  
  19. #define SAMPLE_SILENCE  (0.0f)  
  20. #define PRINTF_S_FORMAT "%.8f"  
  21. #elif 1  
  22. #define PA_SAMPLE_TYPE  paInt16  
  23. typedef short SAMPLE;  
  24. #define SAMPLE_SILENCE  (0)  
  25. #define PRINTF_S_FORMAT "%d"  
  26. #elif 0  
  27. #define PA_SAMPLE_TYPE  paInt8  
  28. typedef char SAMPLE;  
  29. #define SAMPLE_SILENCE  (0)  
  30. #define PRINTF_S_FORMAT "%d"  
  31. #else  
  32. #define PA_SAMPLE_TYPE  paUInt8  
  33. typedef unsigned char SAMPLE;  
  34. #define SAMPLE_SILENCE  (128)  
  35. #define PRINTF_S_FORMAT "%d"  
  36. #endif  
  37.   
  38. int exiting = 0;  
  39. FILE  *fid;  
  40.   
  41. void sigroutine(int dunno) { /* 信号处理例程,其中dunno将会得到信号的值 */  
  42.     switch (dunno) {   
  43.     case SIGINT:  
  44.         exiting = 1;  
  45.         break;  
  46.     }  
  47. }  
  48.   
  49. int cb(  
  50.     const void *input, void *output,  
  51.     unsigned long frameCount,  
  52.     const PaStreamCallbackTimeInfo* timeInfo,  
  53.     PaStreamCallbackFlags statusFlags,  
  54.     void *userData )  
  55. {  
  56.     printf("recv %lu frames\n", frameCount);  
  57.   
  58.     /* Write recorded data to a file. */  
  59.     fwrite( input, NUM_CHANNELS * sizeof(SAMPLE), frameCount, fid );  
  60.   
  61.   
  62.   
  63.     if (exiting)  
  64.     {  
  65.         printf("exiting loop\n");  
  66.         return paComplete;  
  67.     }  
  68.     else  
  69.         return paContinue;  
  70. }  
  71.   
  72. /*******************************************************************/  
  73. int main(void);  
  74. int main(void)  
  75. {  
  76.     PaStreamParameters inputParameters, outputParameters;  
  77.     PaStream *stream;  
  78.     PaError err;  
  79.     int i;  
  80.       
  81.     printf("patest_read_record.c\n"); fflush(stdout);  
  82.   
  83. signal(SIGINT, sigroutine);  
  84.   
  85. fid = fopen("recorded.raw", "wb");  
  86. if( fid == NULL )  
  87. {  
  88.     printf("Could not open file.");  
  89.     exit(10);  
  90. }  
  91.   
  92.     err = Pa_Initialize();  
  93.     if( err != paNoError ) goto error;  
  94.   
  95.     inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */  
  96.     if (inputParameters.device == paNoDevice) {  
  97.       fprintf(stderr,"Error: No default input device.\n");  
  98.       goto error;  
  99.     }  
  100.     inputParameters.channelCount = NUM_CHANNELS;  
  101.     inputParameters.sampleFormat = PA_SAMPLE_TYPE;  
  102.     inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;  
  103.     inputParameters.hostApiSpecificStreamInfo = NULL;  
  104.   
  105.     /* Record some audio. -------------------------------------------- */  
  106.     err = Pa_OpenStream(  
  107.               &stream,  
  108.               &inputParameters,  
  109.               NULL,                  /* &outputParameters, */  
  110.               SAMPLE_RATE,  
  111.               FRAMES_PER_BUFFER,  
  112.               paClipOff,      /* we won't output out of range samples so don't bother clipping them */  
  113.               cb, /* no callback, use blocking API */  
  114.               NULL ); /* no callback, so no callback userData */  
  115.     if( err != paNoError ) goto error;  
  116.   
  117.     err = Pa_StartStream( stream );  
  118.     if( err != paNoError ) goto error;  
  119.     printf("Now recording!!\n"); fflush(stdout);  
  120.   
  121.   
  122. while(Pa_IsStreamActive(stream))  
  123. {  
  124.     usleep(100*1000);  
  125. }  
  126.   
  127.     err = Pa_CloseStream( stream );  
  128.     if( err != paNoError ) goto error;  
  129.   
  130. fclose( fid );  
  131.   
  132.     Pa_Terminate();  
  133.     return 0;  
  134.   
  135. error:  
  136.     Pa_Terminate();  
  137.     fprintf( stderr, "An error occured while using the portaudio stream\n" );  
  138.     fprintf( stderr, "Error number: %d\n", err );  
  139.     fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );  
  140.     return -1;  
  141. }  
注意!portaudio回调函数第三个参数frameCount是帧数,不是缓冲区字节数,对于我的例子,帧格式是signed short,所以每帧2字节,切记


编译运行效果


[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. gq@gq-All-Series:~/projects/test$ gcc record_cb.c -lportaudio  
  2. gq@gq-All-Series:~/projects/test$ ./a.out   
  3. patest_read_record.c  
  4. ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear  
  5. ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe  
  6. ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side  
  7. ALSA lib pcm_route.c:947:(find_matching_chmap) Found no matching channel map  
  8. ALSA lib pcm_route.c:947:(find_matching_chmap) Found no matching channel map  
  9. bt_audio_service_open: connect() failed: Connection refused (111)  
  10. bt_audio_service_open: connect() failed: Connection refused (111)  
  11. bt_audio_service_open: connect() failed: Connection refused (111)  
  12. bt_audio_service_open: connect() failed: Connection refused (111)  
  13. Cannot connect to server socket err = No such file or directory  
  14. Cannot connect to server request channel  
  15. jack server is not running or cannot be started  
  16. Now recording!!  
  17. recv 3200 frames  
  18. recv 3200 frames  
  19. recv 3200 frames  
  20. recv 3200 frames  
  21. recv 3200 frames  
  22. recv 3200 frames  
  23. recv 3200 frames  
  24. recv 3200 frames  
  25. recv 3200 frames  
  26. recv 3200 frames  
  27. recv 3200 frames  
  28. recv 3200 frames  
  29. recv 3200 frames  
  30. recv 3200 frames  
  31. recv 3200 frames  
  32. recv 3200 frames  
  33. recv 3200 frames  
  34. recv 3200 frames  
  35. recv 3200 frames  
  36. recv 3200 frames  
  37. recv 3200 frames  
  38. recv 3200 frames  
  39. recv 3200 frames  
  40. recv 3200 frames  
  41. recv 3200 frames  
  42. recv 3200 frames  
  43. recv 3200 frames  
  44. recv 3200 frames  
  45. recv 3200 frames  
  46. recv 3200 frames  
  47. recv 3200 frames  
  48. recv 3200 frames  
  49. recv 3200 frames  
  50. recv 3200 frames  
  51. ^Crecv 3200 frames  
  52. exiting loop  
  53. gq@gq-All-Series:~/projects/test$ aplay -t raw -c 1 -r 16000 -f S16_LE recorded.raw   
  54. 正在播放 原始資料 'recorded.raw' : Signed 16 bit Little Endian, 频率16000Hz, Mono  




阅读(2889) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~