static bool ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) { GError *error = NULL; assert(ao != NULL); assert(ao->filter != NULL); if (chunk->tag != NULL) { g_mutex_unlock(ao->mutex); ao_plugin_send_tag(ao->plugin, ao->data, chunk->tag); g_mutex_lock(ao->mutex); } size_t size; const char *data = ao_filter_chunk(ao, chunk, &size); if (data == NULL) { ao_close(ao, false); /* don't automatically reopen this device for 10 seconds */ ao->fail_timer = g_timer_new(); return false; } while (size > 0 && ao->command == AO_COMMAND_NONE) { size_t nbytes; if (!ao_wait(ao)) break; g_mutex_unlock(ao->mutex); nbytes = ao_plugin_play(ao->plugin, ao->data, data, size, &error); g_mutex_lock(ao->mutex); if (nbytes == 0) { /* play()==0 means failure */ g_warning("\"%s\" [%s] failed to play: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao_close(ao, false); /* don't automatically reopen this device for 10 seconds */ assert(ao->fail_timer == NULL); ao->fail_timer = g_timer_new(); return false; } assert(nbytes <= size); assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0); data += nbytes; size -= nbytes; } return true; }
int main(int argc, char **argv) { struct audio_output ao; struct audio_format audio_format; struct audio_format_string af_string; bool success; GError *error = NULL; char buffer[4096]; ssize_t nbytes; size_t frame_size, length = 0, play_length, consumed; if (argc < 3 || argc > 4) { g_printerr("Usage: run_output CONFIG NAME [FORMAT] <IN\n"); return 1; } audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2); g_thread_init(NULL); /* read configuration file (mpd.conf) */ config_global_init(); success = config_read_file(argv[1], &error); if (!success) { g_printerr("%s:", error->message); g_error_free(error); return 1; } /* initialize the audio output */ if (!load_audio_output(&ao, argv[2])) return 1; /* parse the audio format */ if (argc > 3) { success = audio_format_parse(&audio_format, argv[3], false, &error); if (!success) { g_printerr("Failed to parse audio format: %s\n", error->message); g_error_free(error); return 1; } } /* open the audio output */ success = ao_plugin_open(ao.plugin, ao.data, &audio_format, &error); if (!success) { g_printerr("Failed to open audio output: %s\n", error->message); g_error_free(error); return 1; } g_printerr("audio_format=%s\n", audio_format_to_string(&audio_format, &af_string)); frame_size = audio_format_frame_size(&audio_format); /* play */ while (true) { if (length < sizeof(buffer)) { nbytes = read(0, buffer + length, sizeof(buffer) - length); if (nbytes <= 0) break; length += (size_t)nbytes; } play_length = (length / frame_size) * frame_size; if (play_length > 0) { consumed = ao_plugin_play(ao.plugin, ao.data, buffer, play_length, &error); if (consumed == 0) { g_printerr("Failed to play: %s\n", error->message); g_error_free(error); return 1; } assert(consumed <= length); assert(consumed % frame_size == 0); length -= consumed; memmove(buffer, buffer + consumed, length); } } /* cleanup and exit */ ao_plugin_close(ao.plugin, ao.data); ao_plugin_finish(ao.plugin, ao.data); g_mutex_free(ao.mutex); config_global_finish(); return 0; }
static bool ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) { const char *data = chunk->data; size_t size = chunk->length; GError *error = NULL; assert(ao != NULL); assert(ao->filter != NULL); assert(!music_chunk_is_empty(chunk)); assert(music_chunk_check_format(chunk, &ao->in_audio_format)); assert(size % audio_format_frame_size(&ao->in_audio_format) == 0); if (chunk->tag != NULL) { g_mutex_unlock(ao->mutex); ao_plugin_send_tag(ao->plugin, ao->data, chunk->tag); g_mutex_lock(ao->mutex); } /* update replay gain */ if (ao->replay_gain_filter != NULL && chunk->replay_gain_serial != ao->replay_gain_serial) { replay_gain_filter_set_info(ao->replay_gain_filter, chunk->replay_gain_serial != 0 ? &chunk->replay_gain_info : NULL); ao->replay_gain_serial = chunk->replay_gain_serial; } if (size == 0) return true; data = filter_filter(ao->filter, data, size, &size, &error); if (data == NULL) { g_warning("\"%s\" [%s] failed to filter: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao_close(ao, false); /* don't automatically reopen this device for 10 seconds */ ao->fail_timer = g_timer_new(); return false; } while (size > 0 && ao->command == AO_COMMAND_NONE) { size_t nbytes; g_mutex_unlock(ao->mutex); nbytes = ao_plugin_play(ao->plugin, ao->data, data, size, &error); g_mutex_lock(ao->mutex); if (nbytes == 0) { /* play()==0 means failure */ g_warning("\"%s\" [%s] failed to play: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao_close(ao, false); /* don't automatically reopen this device for 10 seconds */ ao->fail_timer = g_timer_new(); return false; } assert(nbytes <= size); assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0); data += nbytes; size -= nbytes; } return true; }