libgroove  5.0.0
playlist.c

play several files in a row and then exit

/* play several files in a row and then exit */
#include <groove/player.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
__attribute__ ((cold))
__attribute__ ((noreturn))
__attribute__ ((format (printf, 1, 2)))
static void panic(const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
abort();
}
static int usage(const char *exe) {
fprintf(stderr, "Usage: %s [options] file1 file2 ...\n"
"Options:\n"
" [--volume 1.0]\n"
" [--exact]\n"
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
" [--device id]\n"
" [--raw]\n", exe);
return 1;
}
int main(int argc, char * argv[]) {
// parse arguments
const char *exe = argv[0];
if (argc < 2) return usage(exe);
atexit(groove_finish);
struct GroovePlaylist *playlist = groove_playlist_create();
if (!playlist)
panic("create playlist: out of memory");
struct GroovePlayer *player = groove_player_create();
if (!player)
panic("out of memory");
enum SoundIoBackend backend = SoundIoBackendNone;
bool is_raw = false;
char *device_id = NULL;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
arg += 2;
if (strcmp(arg, "exact") == 0) {
} else if (strcmp(arg, "raw") == 0) {
is_raw = true;
} else if (i + 1 >= argc) {
return usage(exe);
} else if (strcmp(arg, "backend") == 0) {
char *backend_name = argv[++i];
if (strcmp(backend_name, "dummy") == 0) {
backend = SoundIoBackendDummy;
} else if (strcmp(backend_name, "alsa") == 0) {
backend = SoundIoBackendAlsa;
} else if (strcmp(backend_name, "pulseaudio") == 0) {
backend = SoundIoBackendPulseAudio;
} else if (strcmp(backend_name, "jack") == 0) {
backend = SoundIoBackendJack;
} else if (strcmp(backend_name, "coreaudio") == 0) {
backend = SoundIoBackendCoreAudio;
} else if (strcmp(backend_name, "wasapi") == 0) {
backend = SoundIoBackendWasapi;
} else {
fprintf(stderr, "Invalid backend name: %s\n", backend_name);
return 1;
}
} else if (strcmp(arg, "volume") == 0) {
double volume = atof(argv[++i]);
groove_playlist_set_gain(playlist, volume);
} else if (strcmp(arg, "device") == 0) {
device_id = argv[++i];
} else {
return usage(exe);
}
} else {
struct GrooveFile * file = groove_file_open(arg);
if (!file)
panic("unable to queue %s", arg);
groove_playlist_insert(playlist, file, 1.0, 1.0, NULL);
}
}
struct SoundIo *soundio = soundio_create();
if (!soundio)
panic("out of memory");
int err = (backend == SoundIoBackendNone) ?
soundio_connect(soundio) : soundio_connect_backend(soundio, backend);
if (err)
panic("error connecting %s", soundio_strerror(err));
soundio_flush_events(soundio);
int selected_device_index = -1;
if (device_id) {
int device_count = soundio_output_device_count(soundio);
for (int i = 0; i < device_count; i += 1) {
struct SoundIoDevice *device = soundio_get_output_device(soundio, i);
if (strcmp(device->id, device_id) == 0 && device->is_raw == is_raw) {
selected_device_index = i;
break;
}
}
} else {
selected_device_index = soundio_default_output_device_index(soundio);
}
if (selected_device_index < 0)
panic("Output device not found");
struct SoundIoDevice *device = soundio_get_output_device(soundio, selected_device_index);
if (!device) {
fprintf(stderr, "out of memory\n");
return 1;
}
fprintf(stderr, "Output device: %s\n", device->name);
if (device->probe_error)
panic("Cannot probe device: %s", soundio_strerror(device->probe_error));
player->device = device;
if ((err = groove_player_attach(player, playlist)))
panic("error attaching player");
union GroovePlayerEvent event;
struct GroovePlaylistItem *item;
while (groove_player_event_get(player, &event, 1) >= 0) {
switch (event.type) {
fprintf(stderr, "buffer underrun\n");
break;
fprintf(stderr, "device re-opened\n");
break;
panic("error re-opening device");
break;
groove_player_position(player, &item, NULL);
if (!item) {
printf("done\n");
item = playlist->head;
while (item) {
struct GrooveFile *file = item->file;
struct GroovePlaylistItem *next = item->next;
groove_playlist_remove(playlist, item);
item = next;
}
soundio_destroy(soundio);
return 0;
}
struct GrooveTag *artist_tag = groove_file_metadata_get(item->file, "artist", NULL, 0);
struct GrooveTag *title_tag = groove_file_metadata_get(item->file, "title", NULL, 0);
if (artist_tag && title_tag) {
printf("Now playing: %s - %s\n", groove_tag_value(artist_tag),
groove_tag_value(title_tag));
} else {
printf("Now playing: %s\n", item->file->filename);
}
break;
}
}
return 1;
}