首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux下无法得到音频流,望有人讲解清楚录音原理,分不够再加解决方案

2012-04-26 
linux下无法得到音频流,望有人讲解清楚录音原理,分不够再加参考了网上大部分文章, 基本都是 你抄我来我抄

linux下无法得到音频流,望有人讲解清楚录音原理,分不够再加
参考了网上大部分文章, 基本都是 你抄我来我抄他。在录音着一块,基本思路都是从声卡读数据。我调试到现在也没调通。只能从声卡读到一个统一的乱码字符“?”。特来请教,代码如下

C/C++ code
 
int Audio_Record(char *pathname,int nSampleRate,int nChannels,int fmt)
{
    int dsp_fd,mix_fd,status,arg;
    dsp_fd = open("/dev/dsp" , O_RDWR);  /*open dsp*/
   
    if(dsp_fd < 0)
    {
        return  OPEN_DSP_FAILED;
    }
   
    // arg = nSampleRate;
    //status = ioctl(dsp_fd,SOUND_PCM_READ_RATE,&arg); /*set samplerate*/
   
/**
    if(status < 0)
    {
        close(dsp_fd);
        return SAMPLERATE_STATUS;
    }

    if(arg != nSampleRate)
    {
        close(dsp_fd);
        return SET_SAMPLERATE_FAILED;
    }
**/   
  // arg = nChannels;  /*set channels*/
  // status = ioctl(dsp_fd, SOUND_PCM_READ_CHANNELS, &arg);
/**   
    if(status < 0)
    {
        close(dsp_fd);
        return CHANNELS_STATUS;
    }
   
    if( arg != nChannels)
    {
        close(dsp_fd);
        return SET_CHANNELS_FAILED;
    }
**/
    // arg = fmt; /*set bit fmt*/
   
    //status = ioctl(dsp_fd, SOUND_PCM_READ_BITS, &arg);
/**   
    if(status < 0)
    {
        close(dsp_fd);
        return FMT_STATUS;
    }
   
    if(arg != fmt)
    {
        close(dsp_fd);
        return SET_FMT_FAILED;
    }
**/

    arg = 0;
    ioctl( dsp_fd, SNDCTL_DSP_RESET, (char *)&arg );
    ioctl( dsp_fd, SNDCTL_DSP_SYNC, (char *)&arg );

    arg = 1;
    ioctl( dsp_fd, SNDCTL_DSP_NONBLOCK, (char*)&arg );

    arg = nSampleRate;
    ioctl( dsp_fd, SNDCTL_DSP_SPEED, (char *)&arg );
   
    arg = nChannels;
    ioctl( dsp_fd, SNDCTL_DSP_STEREO, 0 );
    ioctl( dsp_fd, SNDCTL_DSP_CHANNELS, (char *)&arg );

    arg = fmt;
    ioctl( dsp_fd, SNDCTL_DSP_SETFMT, (char*)&arg );

    arg = 3;
    ioctl( dsp_fd, SNDCTL_DSP_SETTRIGGER, (char*)&arg );

    arg = 3;
    ioctl( dsp_fd, SNDCTL_DSP_SETFRAGMENT, (char*)&arg );

    arg = 1;
    ioctl( dsp_fd, SNDCTL_DSP_PROFILE, (char*)&arg );

    FILE *file_fd = fopen(pathname,"w+");
    if(file_fd == NULL)
    {
        close(dsp_fd);
        return OPEN_FILE_FAILED;
    }

    int num = 2 * nChannels*nSampleRate*fmt/8;
    int get_num;
    unsigned char buf[num];

    // Record
    int j = 0;
    while( 1 )
    {
        get_num = read( dsp_fd, buf, num );
        printf( "buf = %s\n", buf );


        printf( "buf = %d\n", buf[0] );
        fwrite( buf, 1, get_num, file_fd );
        j++;
    }
   
    close(dsp_fd);
    fclose(file_fd);
    return 0;
}



代码中的注释部分是 另一种设置方法,都试过了,不行。

[解决办法]
up
[解决办法]
为什么不使用ALSA呢?
我现在使用ALSA可以轻松的得到声音。
但现在我只能使用固定的取样长度chunk_size(就是一次取几帧数据),不然如果每次取不如128就报-EMLINK,即连接数太多的错误。最后我找到规律就是每次取
chunk_size个样本数据就没问题。chunk_size通过 snd_pcm_hw_params_get_period_size(params, &chunk_size, 0)取得。

我录音的程序根据ALSA 例子放音程序改的:
#include "../include/asoundlib.h"

static char *device = "default";/* playback device */

snd_output_t *output = NULL;
unsigned char buffer[2352]; /* 根据打印period_size*snd_pcm_format_t*channels*/

int main(void)
{
int err;
unsigned int i;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;

if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_set_params(handle,
SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
48000,
1,
500000)) < 0) {/* 0.5sec */
printf("capture open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}

for (int i=0; i<100; ++i)
{
frames = snd_pcm_readi(handle, buffer, 2352); //2352是自己根据snd_pcm_hw_params_get_period_size得到,正好一帧就一个字节
//如果此时不是2352而是160等就会报-EMLINK错误。
}

snd_pcm_close(handle);
return 0;
}

通过读snd_pcm_set_params这个函数,发现只要snd_pcm_readi第三个参数等于period_size就没问题。ALSA自带的录音程序也是这样做的。现在是我要改变period_size
我要怎么做?就是简单的设置snd_pcm_hw_params_set_period_size吗?我看代码还要设置什么BUFFER_TIME,BUFFER_SIZE,但不懂他们之间的关系。
有没有人懂ALSA解释下 BUFFER_TIME ,BUFFER_SIZE, PERIOD_SIZE之间的关系。下面是代码里的解释看不懂。谢谢了。

SNDRV_PCM_HW_PARAM_PERIOD_TIME,/* Approx distance between interrupts
in us */
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,/* Approx frames between interrupts */
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, /* Approx bytes between interrupts */
SNDRV_PCM_HW_PARAM_PERIODS,/* Approx interrupts per buffer */
SNDRV_PCM_HW_PARAM_BUFFER_TIME,/* Approx duration of buffer in us */
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,/* Size of buffer in frames */
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, /* Size of buffer in bytes */
SNDRV_PCM_HW_PARAM_TICK_TIME,/* Approx tick duration in us */





[解决办法]
学习下。。。

热点排行