Alsa,无法连续播放同一曲目两次
Alsa, unable to play the same track twice in sequence
我开发了一些代码来播放音频(波形文件)。当我尝试播放同一个文件两次时,第一次播放正常,但第二次播放时总是失败。
下面是一次性音频初始化函数
/* PCM interface objects */
static snd_pcm_t *pcm_handle;
static snd_pcm_uframes_t frames;
static int rate = 44100, channels = 2;
void audio_init(void)
{
snd_pcm_hw_params_t *params;
unsigned int pcm = 0;
/* Open the PCM device in playback mode */
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
printf("ERROR: Can't open \"%s\" PCM device. %s\n",PCM_DEVICE, snd_strerror(pcm));
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(pcm_handle, params);
/* Interleaved mode */
if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
/* Signed 16 bit little-endian format */
if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params,
SND_PCM_FORMAT_S16_LE)) < 0)
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
/* Two channels, stereo */
if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0)
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
/* 44100 bits/second sampling rate (CD quality) */
if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0)
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
/* Write parameters to the driver */
if ((pcm = snd_pcm_hw_params(pcm_handle, params) < 0))
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
/* Resume information */
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
int tmp = 0;
snd_pcm_hw_params_get_channels(params, &tmp);
printf("channels: %i ", tmp);
if (tmp == 1)
printf("(mono)\n");
else if (tmp == 2)
printf("(stereo)\n");
snd_pcm_hw_params_get_rate(params, &tmp, 0);
printf("rate: %d bps\n", tmp);
/* Allocate large enough buffer to hold single period (No. of samples) */
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("period size = %d frames\n", (int)frames);
/* Get the period time */
snd_pcm_hw_params_get_period_time(params, &tmp, NULL);
printf("period time = %d us\n", tmp);
audio_playTrack(AUDIO_HOMING_TRACK);
sleep(1);
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
audio_playTrack(AUDIO_ARRIVE_TRACK);
sleep(1);
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
}
下面是我在 audio_init( ) 末尾调用两次的函数。
void audio_playTrack(char *audioFile)
{
short int* buf = NULL;
int readcount = 0;
int pcmrc;
SNDFILE *infile = NULL;
SF_INFO sfinfo;
infile = sf_open(audioFile, SFM_READ, &sfinfo);
printf("\r\n");
printf("[FILE]Channels : %d\n", sfinfo.channels);
printf("[FILE]Sample rate : %d\n", sfinfo.samplerate);
printf("[FILE]Sections : %d\n", sfinfo.sections);
printf("[FILE]Format : %d\n", sfinfo.format);
printf("\r\n");
printf("+------------------\n");
printf("### AUDIO BEGIN ###\n");
printf("+------------------\n\n");
buf = malloc(frames * sfinfo.channels * sizeof(int));
while ((readcount = sf_readf_short(infile, buf, frames))>0)
{
pcmrc = snd_pcm_writei(pcm_handle, buf, readcount);
if (pcmrc == -EPIPE)
{
printf("Underrun!\n");
snd_pcm_prepare(pcm_handle);
}
else if (pcmrc < 0)
{
printf("Error writing to PCM device: %s\n", snd_strerror(pcmrc));
}
else if (pcmrc != readcount)
{
printf("PCM write differs from PCM read.\n");
}
}
printf("+------------------\n");
printf("### AUDIO END ###\n");
printf("+------------------\n\n");
free(buf);
sf_close (infile);
}
对第一个 audio_playTrack() 的调用有效。第二个不作为 sf_readf_short returns 0 帧,甚至不进入 while 循环。
我希望能够在代码中随时停止和重新启动音频。谁能帮我理解为什么 sf_readf_short returns 0 和 audio_playTrack() 在第二次调用时失败?
下面是控制台打印。
PCM name: 'default'
PCM state: PREPARED
channels: 2 (stereo)
rate: 44100 bps
period size = 940 frames
period time = 21333 us
[FILE]Channels : 2
[FILE]Sample rate : 44100
[FILE]Sections : 1
[FILE]Format : 65538
+------------------
### AUDIO BEGIN ###
+------------------
+------------------
### AUDIO END ###
+------------------
PCM state: RUNNING
[FILE]Channels : 2
[FILE]Sample rate : 44100
[FILE]Sections : 1
[FILE]Format : 65538
+------------------
### AUDIO BEGIN ###
+------------------
Underrun!
+------------------
### AUDIO END ###
+------------------
编辑:从 audio_playTrack( ) 中删除了 snd_pcm_drain( ) 并将 snd_pcm_hw_params_t 参数设为 audio_init( )
的本地参数
两次调用的文件对象 infile
相同。所以你第一次已经到了文件的末尾,那么你第二次尝试播放时,你仍然在文件的末尾。您需要关闭并重新打开文件,或者在尝试再次播放之前倒回到开头。
我开发了一些代码来播放音频(波形文件)。当我尝试播放同一个文件两次时,第一次播放正常,但第二次播放时总是失败。
下面是一次性音频初始化函数
/* PCM interface objects */
static snd_pcm_t *pcm_handle;
static snd_pcm_uframes_t frames;
static int rate = 44100, channels = 2;
void audio_init(void)
{
snd_pcm_hw_params_t *params;
unsigned int pcm = 0;
/* Open the PCM device in playback mode */
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
printf("ERROR: Can't open \"%s\" PCM device. %s\n",PCM_DEVICE, snd_strerror(pcm));
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(pcm_handle, params);
/* Interleaved mode */
if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
/* Signed 16 bit little-endian format */
if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params,
SND_PCM_FORMAT_S16_LE)) < 0)
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
/* Two channels, stereo */
if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0)
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
/* 44100 bits/second sampling rate (CD quality) */
if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0)
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
/* Write parameters to the driver */
if ((pcm = snd_pcm_hw_params(pcm_handle, params) < 0))
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
/* Resume information */
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
int tmp = 0;
snd_pcm_hw_params_get_channels(params, &tmp);
printf("channels: %i ", tmp);
if (tmp == 1)
printf("(mono)\n");
else if (tmp == 2)
printf("(stereo)\n");
snd_pcm_hw_params_get_rate(params, &tmp, 0);
printf("rate: %d bps\n", tmp);
/* Allocate large enough buffer to hold single period (No. of samples) */
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("period size = %d frames\n", (int)frames);
/* Get the period time */
snd_pcm_hw_params_get_period_time(params, &tmp, NULL);
printf("period time = %d us\n", tmp);
audio_playTrack(AUDIO_HOMING_TRACK);
sleep(1);
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
audio_playTrack(AUDIO_ARRIVE_TRACK);
sleep(1);
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
}
下面是我在 audio_init( ) 末尾调用两次的函数。
void audio_playTrack(char *audioFile)
{
short int* buf = NULL;
int readcount = 0;
int pcmrc;
SNDFILE *infile = NULL;
SF_INFO sfinfo;
infile = sf_open(audioFile, SFM_READ, &sfinfo);
printf("\r\n");
printf("[FILE]Channels : %d\n", sfinfo.channels);
printf("[FILE]Sample rate : %d\n", sfinfo.samplerate);
printf("[FILE]Sections : %d\n", sfinfo.sections);
printf("[FILE]Format : %d\n", sfinfo.format);
printf("\r\n");
printf("+------------------\n");
printf("### AUDIO BEGIN ###\n");
printf("+------------------\n\n");
buf = malloc(frames * sfinfo.channels * sizeof(int));
while ((readcount = sf_readf_short(infile, buf, frames))>0)
{
pcmrc = snd_pcm_writei(pcm_handle, buf, readcount);
if (pcmrc == -EPIPE)
{
printf("Underrun!\n");
snd_pcm_prepare(pcm_handle);
}
else if (pcmrc < 0)
{
printf("Error writing to PCM device: %s\n", snd_strerror(pcmrc));
}
else if (pcmrc != readcount)
{
printf("PCM write differs from PCM read.\n");
}
}
printf("+------------------\n");
printf("### AUDIO END ###\n");
printf("+------------------\n\n");
free(buf);
sf_close (infile);
}
对第一个 audio_playTrack() 的调用有效。第二个不作为 sf_readf_short returns 0 帧,甚至不进入 while 循环。
我希望能够在代码中随时停止和重新启动音频。谁能帮我理解为什么 sf_readf_short returns 0 和 audio_playTrack() 在第二次调用时失败?
下面是控制台打印。
PCM name: 'default'
PCM state: PREPARED
channels: 2 (stereo)
rate: 44100 bps
period size = 940 frames
period time = 21333 us
[FILE]Channels : 2
[FILE]Sample rate : 44100
[FILE]Sections : 1
[FILE]Format : 65538
+------------------
### AUDIO BEGIN ###
+------------------
+------------------
### AUDIO END ###
+------------------
PCM state: RUNNING
[FILE]Channels : 2
[FILE]Sample rate : 44100
[FILE]Sections : 1
[FILE]Format : 65538
+------------------
### AUDIO BEGIN ###
+------------------
Underrun!
+------------------
### AUDIO END ###
+------------------
编辑:从 audio_playTrack( ) 中删除了 snd_pcm_drain( ) 并将 snd_pcm_hw_params_t 参数设为 audio_init( )
的本地参数两次调用的文件对象 infile
相同。所以你第一次已经到了文件的末尾,那么你第二次尝试播放时,你仍然在文件的末尾。您需要关闭并重新打开文件,或者在尝试再次播放之前倒回到开头。