diff --git a/src/utils-lgpl/fcplay.c b/src/utils-lgpl/fcplay.c index eac0712..57a86e3 100644 --- a/src/utils-lgpl/fcplay.c +++ b/src/utils-lgpl/fcplay.c @@ -24,6 +24,12 @@ static int verbose; +enum continuous_playback_mode { + PLAYBACK_MODE_NOP = 0, /* sequential: files are streamed continuously */ + PLAYBACK_MODE_GAPLESS = 1, /* gapless: uses kernel gapless API */ + PLAYBACK_MODE_RESTART = 2, /* restart: compress device is drained, closed and reopened between tracks */ +}; + static const struct { const char *name; unsigned int id; @@ -52,21 +58,24 @@ static void usage(void) { int i; - fprintf(stderr, "usage: cplay [OPTIONS] filename\n" + fprintf(stderr, "usage: fcplay [OPTIONS] file1 [file2 ...]\n" "-c\tcard number\n" "-d\tdevice node\n" "-I\tspecify codec ID (default is mp3)\n" "-b\tbuffer size\n" "-f\tfragments\n" - "-g\tgapless play\n\n" + "-p\tcontinuous playback mode:\n" + "\t 0 = NOP (default): files streamed continuously\n" + "\t 1 = gapless: kernel gapless API, no audible gap\n" + "\t 2 = restart: compress device drained and reopened between tracks\n" + "-g\t(deprecated) equivalent to -p 0/1\n" "-v\tverbose mode\n" "-h\tPrints this help list\n\n" "Example:\n" "\tfcplay -c 1 -d 2 test.mp3\n" - "\tfcplay -f 5 test.mp3\n" "\tfcplay -c 1 -d 2 test1.mp3 test2.mp3\n" "\tGapless:\n" - "\t\tfcplay -c 1 -d 2 -g 1 test1.mp3 test2.mp3\n\n" + "\t\tfcplay -c 1 -d 2 -p 1 test1.mp3 test2.mp3\n\n" "Valid codec IDs:\n"); for (i = 0; i < CPLAY_NUM_CODEC_IDS; ++i) @@ -80,7 +89,8 @@ static void usage(void) void play_samples(char **files, unsigned int card, unsigned int device, unsigned long buffer_size, unsigned int frag, - unsigned long codec_id, unsigned int file_count, unsigned int gapless); + unsigned long codec_id, unsigned int file_count, + enum continuous_playback_mode pb_mode); static int print_time(struct compress *compress) { @@ -103,13 +113,14 @@ int main(int argc, char **argv) int c, i; unsigned int card = 0, device = 0, frag = 0; unsigned int codec_id = SND_AUDIOCODEC_MP3; - unsigned int file_count = 0, gapless = 0; + unsigned int file_count = 0; + enum continuous_playback_mode pb_mode = PLAYBACK_MODE_NOP; if (argc < 2) usage(); verbose = 0; - while ((c = getopt(argc, argv, "hvb:f:c:d:I:g:")) != -1) { + while ((c = getopt(argc, argv, "hvb:f:c:d:I:g:p:")) != -1) { switch (c) { case 'h': usage(); @@ -127,7 +138,10 @@ int main(int argc, char **argv) device = strtol(optarg, NULL, 10); break; case 'g': - gapless = strtol(optarg, NULL, 10); + fprintf(stderr, "Warning: -g is deprecated, use -p instead\n"); + /* fall through */ + case 'p': + pb_mode = strtol(optarg, NULL, 10); break; case 'I': if (optarg[0] == '0') { @@ -164,7 +178,7 @@ int main(int argc, char **argv) file_count = argc - optind; play_samples(file, card, device, buffer_size, frag, codec_id, - file_count, gapless); + file_count, pb_mode); fprintf(stderr, "Finish Playing.... Close Normally\n"); exit(EXIT_SUCCESS); @@ -199,7 +213,7 @@ static int get_codec_id(int codec_id) } } -static int parse_file(char *file, struct snd_codec *codec) +static int parse_file(const char *file, struct snd_codec *codec) { AVFormatContext *ctx = NULL; AVStream *stream; @@ -301,36 +315,21 @@ static int parse_file(char *file, struct snd_codec *codec) } -void play_samples(char **files, unsigned int card, unsigned int device, - unsigned long buffer_size, unsigned int frag, - unsigned long codec_id, unsigned int file_count, unsigned int gapless) +static struct compress * +compress_open_and_prepare(unsigned int card, unsigned int device, + unsigned long buffer_size, const char *name, FILE *file, + char **buffer_out, int *size_out) { struct compr_config config; - struct snd_codec codec; struct compress *compress; - struct compr_gapless_mdata mdata; - FILE *file; - char *buffer; - char *name; int size, num_read, wrote; - unsigned int file_idx = 0, rc = 0; - - if (verbose) - printf("%s: entry\n", __func__); - - name = files[file_idx]; - file = fopen(name, "rb"); - if (!file) { - fprintf(stderr, "Unable to open file '%s'\n", name); - exit(EXIT_FAILURE); - } + struct snd_codec codec; + char *buffer; memset(&codec, 0, sizeof(codec)); memset(&config, 0, sizeof(config)); - memset(&mdata, 0, sizeof(mdata)); parse_file(name, &codec); - config.codec = &codec; compress = compress_open(card, device, COMPRESS_IN, &config); @@ -338,21 +337,21 @@ void play_samples(char **files, unsigned int card, unsigned int device, fprintf(stderr, "Unable to open Compress device %d:%d\n", card, device); fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); - goto FILE_EXIT; - }; + return NULL; + } if (verbose) printf("%s: Opened compress device\n", __func__); + size = config.fragment_size; buffer = malloc(size * config.fragments); if (!buffer) { - fprintf(stderr, "Unable to allocate %d bytes\n", size); - goto COMP_EXIT; + fprintf(stderr, "Unable to allocate %d bytes\n", + size * config.fragments); + compress_close(compress); + return NULL; } - if (gapless) - compress_set_gapless_metadata(compress, &mdata); - - /* we will write frag fragment_size and then start */ + /* write full buffer data initially */ num_read = fread(buffer, 1, size * config.fragments, file); if (num_read > 0) { if (verbose) @@ -361,13 +360,51 @@ void play_samples(char **files, unsigned int card, unsigned int device, if (wrote < 0) { fprintf(stderr, "Error %d playing sample\n", wrote); fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); - goto BUF_EXIT; + free(buffer); + compress_close(compress); + return NULL; } if (wrote != num_read) { /* TODO: Buufer pointer needs to be set here */ fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote); } } + + *buffer_out = buffer; + *size_out = size; + return compress; +} + +void play_samples(char **files, unsigned int card, unsigned int device, + unsigned long buffer_size, unsigned int frag, + unsigned long codec_id, unsigned int file_count, + enum continuous_playback_mode pb_mode) +{ + struct compr_gapless_mdata mdata; + struct compress *compress; + int size, num_read, wrote; + unsigned int file_idx = 0; + struct snd_codec codec; + char *buffer, *name; + FILE *file; + + name = files[file_idx]; + file = fopen(name, "rb"); + if (!file) { + fprintf(stderr, "Unable to open file '%s'\n", name); + exit(EXIT_FAILURE); + } + + compress = compress_open_and_prepare(card, device, buffer_size, name, + file, &buffer, &size); + if (!compress) + goto FILE_EXIT; + + if (pb_mode == PLAYBACK_MODE_GAPLESS) { + memset(&mdata, 0, sizeof(mdata)); + compress_set_gapless_metadata(compress, &mdata); + } + printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n", name, card, device, buffer_size); printf("Format %u Channels %u, %u Hz, Bit Rate %d\n", @@ -388,17 +425,19 @@ void play_samples(char **files, unsigned int card, unsigned int device, printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n", name, card, device, buffer_size); - if (gapless) { - parse_file(name, &codec); + if (pb_mode == PLAYBACK_MODE_GAPLESS) { + int rc; - rc = compress_next_track(compress); - if (rc) - fprintf(stderr, "ERR: compress next track set\n"); + parse_file(name, &codec); rc = compress_set_gapless_metadata(compress, &mdata); if (rc) fprintf(stderr, "ERR: set gapless metadata\n"); + rc = compress_next_track(compress); + if (rc) + fprintf(stderr, "ERR: compress next track set\n"); + rc = compress_set_codec_params(compress, &codec); if (rc) fprintf(stderr, "ERR: set next track codec params\n"); @@ -407,6 +446,25 @@ void play_samples(char **files, unsigned int card, unsigned int device, rc = compress_partial_drain(compress); if (rc) fprintf(stderr, "ERR: partial drain\n"); + } else if (pb_mode == PLAYBACK_MODE_RESTART) { + /* restart: drain, close, and reopen for the new file */ + compress_drain(compress); + compress_close(compress); + free(buffer); + + compress = compress_open_and_prepare(card, device, buffer_size, + name, file, &buffer, &size); + if (!compress) + goto FILE_EXIT; + + printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n", + name, card, device, buffer_size); + printf("Format %u Channels %u, %u Hz, Bit Rate %d\n", + codec.id, codec.ch_in, codec.sample_rate, codec.bit_rate); + + compress_start(compress); + if (verbose) + printf("%s: You should hear audio NOW!!!\n", __func__); } } @@ -450,7 +508,6 @@ void play_samples(char **files, unsigned int card, unsigned int device, printf("%s: exit track\n", __func__); BUF_EXIT: free(buffer); -COMP_EXIT: compress_close(compress); FILE_EXIT: fclose(file);