alsabat: refactoring alsa capture thread

Refactoring ALSA capture thread:
  1. Move file open/seek operations to sub function, so all file
  processes are now on a single function (read_from_pcm_loop()), so
  the structure is more reasonable, the function API is simplified
  and no need file cleanup in thread loop.
  2. Replace the wav header processing lines with a general function
  (update_wav_header()), which can be reused in other sections.
  3. Add pthread_exit() for thread to exit safely in single line mode,
  and correct comment.

Signed-off-by: Lu, Han <han.lu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Lu, Han 2016-03-23 15:52:42 +08:00 committed by Takashi Iwai
parent c5b022e621
commit 241d7fc1bb
3 changed files with 48 additions and 38 deletions

View file

@ -465,12 +465,29 @@ static int read_from_pcm(struct pcm_container *sndpcm,
return 0; return 0;
} }
static int read_from_pcm_loop(FILE *fp, int count, static int read_from_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)
struct pcm_container *sndpcm, struct bat *bat)
{ {
int err = 0; int err = 0;
FILE *fp = NULL;
int size, frames; int size, frames;
int remain = count; int bytes_read = 0;
int bytes_count = bat->frames * bat->frame_size;
int remain = bytes_count;
remove(bat->capture.file);
fp = fopen(bat->capture.file, "wb");
err = -errno;
if (fp == NULL) {
fprintf(bat->err, _("Cannot open file: %s %d\n"),
bat->capture.file, err);
return err;
}
/* leave space for file header */
if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) {
err = -errno;
fclose(fp);
return err;
}
while (remain > 0) { while (remain > 0) {
size = (remain <= sndpcm->period_bytes) ? size = (remain <= sndpcm->period_bytes) ?
@ -489,6 +506,8 @@ static int read_from_pcm_loop(FILE *fp, int count,
snd_strerror(err), err); snd_strerror(err), err);
return -EIO; return -EIO;
} }
bytes_read += size;
remain -= size; remain -= size;
bat->periods_played++; bat->periods_played++;
@ -497,6 +516,9 @@ static int read_from_pcm_loop(FILE *fp, int count,
break; break;
} }
update_wav_header(bat, fp, bytes_read);
fclose(fp);
return 0; return 0;
} }
@ -505,21 +527,13 @@ static void pcm_cleanup(void *p)
snd_pcm_close(p); snd_pcm_close(p);
} }
static void file_cleanup(void *p)
{
fclose(p);
}
/** /**
* Record * Record
*/ */
void *record_alsa(struct bat *bat) void *record_alsa(struct bat *bat)
{ {
int err = 0; int err = 0;
FILE *fp = NULL;
struct pcm_container sndpcm; struct pcm_container sndpcm;
struct wav_container wav;
int count;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
@ -543,48 +557,27 @@ void *record_alsa(struct bat *bat)
goto exit2; goto exit2;
} }
remove(bat->capture.file);
fp = fopen(bat->capture.file, "wb");
err = -errno;
if (fp == NULL) {
fprintf(bat->err, _("Cannot open file: %s %d\n"),
bat->capture.file, err);
retval_record = err;
goto exit3;
}
prepare_wav_info(&wav, bat);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
pthread_cleanup_push(pcm_cleanup, sndpcm.handle); pthread_cleanup_push(pcm_cleanup, sndpcm.handle);
pthread_cleanup_push(free, sndpcm.buffer); pthread_cleanup_push(free, sndpcm.buffer);
pthread_cleanup_push(file_cleanup, fp);
err = write_wav_header(fp, &wav, bat);
if (err != 0) {
retval_record = err;
goto exit4;
}
count = wav.chunk.length;
fprintf(bat->log, _("Recording ...\n")); fprintf(bat->log, _("Recording ...\n"));
err = read_from_pcm_loop(fp, count, &sndpcm, bat); err = read_from_pcm_loop(&sndpcm, bat);
if (err != 0) { if (err != 0) {
retval_record = err; retval_record = err;
goto exit4; goto exit3;
} }
/* Normally we will never reach this part of code (before fail_exit) as /* Normally we will never reach this part of code (unless error in
this thread will be cancelled by end of play thread. */ * previous call) (before exit3) as this thread will be cancelled
pthread_cleanup_pop(0); * by end of play thread. Except in single line mode. */
pthread_cleanup_pop(0); pthread_cleanup_pop(0);
pthread_cleanup_pop(0); pthread_cleanup_pop(0);
snd_pcm_drain(sndpcm.handle); snd_pcm_drain(sndpcm.handle);
pthread_exit(&retval_record);
exit4:
fclose(fp);
exit3: exit3:
free(sndpcm.buffer); free(sndpcm.buffer);
exit2: exit2:

View file

@ -195,3 +195,19 @@ int write_wav_header(FILE *fp, struct wav_container *wav, struct bat *bat)
return 0; return 0;
} }
/* update wav header when data size changed */
int update_wav_header(struct bat *bat, FILE *fp, int bytes)
{
int err = 0;
struct wav_container wav;
prepare_wav_info(&wav, bat);
wav.chunk.length = bytes;
wav.header.length = (wav.chunk.length) + sizeof(wav.chunk)
+ sizeof(wav.format) + sizeof(wav.header) - 8;
rewind(fp);
err = write_wav_header(fp, &wav, bat);
return err;
}

View file

@ -183,3 +183,4 @@ struct analyze {
void prepare_wav_info(struct wav_container *, struct bat *); void prepare_wav_info(struct wav_container *, struct bat *);
int read_wav_header(struct bat *, char *, FILE *, bool); int read_wav_header(struct bat *, char *, FILE *, bool);
int write_wav_header(FILE *, struct wav_container *, struct bat *); int write_wav_header(FILE *, struct wav_container *, struct bat *);
int update_wav_header(struct bat *, FILE *, int);