Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 103 additions & 46 deletions src/utils-lgpl/fcplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
{
Expand All @@ -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();
Expand All @@ -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') {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -301,58 +315,43 @@ 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);
if (!compress || !is_compress_ready(compress)) {
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)
Expand All @@ -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",
Expand All @@ -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");
Expand All @@ -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__);
}
}

Expand Down Expand Up @@ -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);
Expand Down