static void ao_open(struct audio_output *ao) { bool success; GError *error = NULL; const struct audio_format *filter_audio_format; struct audio_format_string af_string; assert(!ao->open); assert(ao->pipe != NULL); assert(ao->chunk == NULL); assert(audio_format_valid(&ao->in_audio_format)); if (ao->fail_timer != NULL) { /* this can only happen when this output thread fails while audio_output_open() is run in the player thread */ g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } /* enable the device (just in case the last enable has failed) */ if (!ao_enable(ao)) /* still no luck */ return; /* open the filter */ filter_audio_format = ao_filter_open(ao, &ao->in_audio_format, &error); if (filter_audio_format == NULL) { g_warning("Failed to open filter for \"%s\" [%s]: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao->fail_timer = g_timer_new(); return; } assert(audio_format_valid(filter_audio_format)); ao->out_audio_format = *filter_audio_format; audio_format_mask_apply(&ao->out_audio_format, &ao->config_audio_format); g_mutex_unlock(ao->mutex); success = ao_plugin_open(ao->plugin, ao->data, &ao->out_audio_format, &error); g_mutex_lock(ao->mutex); assert(!ao->open); if (!success) { g_warning("Failed to open \"%s\" [%s]: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao_filter_close(ao); ao->fail_timer = g_timer_new(); return; } convert_filter_set(ao->convert_filter, &ao->out_audio_format); ao->open = true; g_debug("opened plugin=%s name=\"%s\" " "audio_format=%s", ao->plugin->name, ao->name, audio_format_to_string(&ao->out_audio_format, &af_string)); if (!audio_format_equals(&ao->in_audio_format, &ao->out_audio_format)) g_debug("converting from %s", audio_format_to_string(&ao->in_audio_format, &af_string)); }
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; }