有谁对音频设备的读写相对了解的,进来看看。(紧急,非常感谢)
看看下面这个写pcm数据的函数。
为什么要是出现WARNING: AUDIOWRITE: Underrun occurred. Preparing pcm..,网上查了下,说是送的数据不够就会出现,设备播空了。好像跟period(硬件中中断间的间隔时间)有关系,新手不太懂,请高手帮忙分析下原因。
int DRV_audioWrite(DRV_AudioHndl *hndl, void *pInBuf, int writeSamples)
{
int rc;
DRV_AudioObj *pObj;
if(hndl==NULL)
return OSA_EFAIL;
if(hndl->hndl==NULL)
return OSA_EFAIL;
pObj = (DRV_AudioObj *)hndl->hndl;
while (writeSamples > 0)
{
rc = snd_pcm_writei(pObj->sound_handle, pInBuf, writeSamples);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
OSA_printf("WARNING: AUDIOWRITE: Underrun occurred. Preparing pcm..\n");
if (snd_pcm_prepare(pObj->sound_handle) < 0) {
OSA_ERROR("Failed to recover from underrun\n");
}
//return 0;
}
else{
if( rc < 0 )
{
OSA_ERROR("error from write : %s\n",snd_strerror(rc));
if (snd_pcm_prepare(pObj->sound_handle) < 0) {
OSA_ERROR("Failed to recover from snd_strerror\n");
}
}
return rc;
}
if (rc == -EPIPE) {
//memset(pInBuf, 0x7F, writeSamples*2*2);
//printf("rc != writeSamples\n");
}
else {
printf("write success\n");
writeSamples -= rc;
}
}
}
下面是打开音频设备的代码。
Audioplayconfig.samplingRate = rbuf.sampleRate; //8000
Audioplayconfig.deviceId = 0;
Audioplayconfig.numChannels = 1;
Audioplayconfig.buff_Of_Samples = 640;
Audioplayconfig.bufferSize = 1280;
rc = DRV_audioplayOpen(&gAUDIOPLAY_ctrl.audioHndl, &Audioplayconfig);
if(rc != OSA_SOK)
{snd_msg(snd_msg_qid);
return rc;
}
int DRV_audioOpen(DRV_AudioHndl *hndl, DRV_AudioConfig *config)
{
int rc = 0;
unsigned int val = 0;
int dir = 0;
unsigned int buffer_time = 0;
snd_pcm_uframes_t frames;
snd_pcm_uframes_t buffer_frames;
snd_pcm_hw_params_t *sound_params = NULL;
DRV_AudioObj *pObj;
hndl->hndl = OSA_memAlloc(sizeof(DRV_AudioObj));
if( hndl->hndl == NULL )
{
OSA_ERROR("OSA_memAlloc fail \n");
goto error_exit;
}
pObj = (DRV_AudioObj*)hndl->hndl;
memset(pObj,0,sizeof(DRV_AudioObj));
/* Open PCM device for record. */
rc = snd_pcm_open(&(pObj->sound_handle), "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0)
{
OSA_ERROR("unable to open pcm device: %s\n", snd_strerror(rc));
goto error_exit;
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&sound_params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(pObj->sound_handle, sound_params);
/* Set the desired hardware parameters. */
/* Sampling rate*/
val = config->samplingRate;
snd_pcm_hw_params_set_rate_near(pObj->sound_handle, sound_params, &val, &dir);
if (val != config->samplingRate)
{
OSA_ERROR("Rate doesn't match (requested %iHz, get %iHz)\n", config->samplingRate, val);
goto error_exit;
}
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(pObj->sound_handle, sound_params, SND_PCM_FORMAT_S16_LE);
/* Interleaved mode */
snd_pcm_hw_params_set_access(pObj->sound_handle, sound_params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Num channels */
snd_pcm_hw_params_set_channels(pObj->sound_handle, sound_params, config->numChannels);
/* Set period size of frames. */
frames = config->buff_Of_Samples;
snd_pcm_hw_params_set_period_size_near(pObj->sound_handle, sound_params, &frames, &dir);
/* set the buffer time */
if( buffer_time )
{
rc = snd_pcm_hw_params_set_buffer_time_near(pObj->sound_handle, sound_params, &buffer_time, &dir);
if (rc < 0) {
OSA_ERROR("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(rc));
goto error_exit;
}
}
else{
buffer_frames = frames*4;
snd_pcm_hw_params_set_buffer_size_near(pObj->sound_handle, sound_params, &buffer_frames);
}
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(pObj->sound_handle, sound_params);
if (rc < 0)
{
OSA_ERROR("unable to set hw parameters: %s\n",
snd_strerror(rc));
goto error_exit;
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(sound_params, &frames, &dir);
snd_pcm_hw_params_get_period_time(sound_params, &val, &dir);
.....
}
请问是为什么?我怀疑是打开采集设备的某个参数设置得不对。现在用的默认值。TI dm365的codec代码。