static void * recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, const struct config_param *param, GError **error_r) { struct recorder_output *recorder = g_new(struct recorder_output, 1); const char *encoder_name; const struct encoder_plugin *encoder_plugin; /* read configuration */ encoder_name = config_get_block_string(param, "encoder", "vorbis"); encoder_plugin = encoder_plugin_get(encoder_name); if (encoder_plugin == NULL) { g_set_error(error_r, recorder_output_quark(), 0, "No such encoder: %s", encoder_name); return NULL; } recorder->path = config_get_block_string(param, "path", NULL); if (recorder->path == NULL) { g_set_error(error_r, recorder_output_quark(), 0, "'path' not configured"); return NULL; } /* initialize encoder */ recorder->encoder = encoder_init(encoder_plugin, param, error_r); if (recorder->encoder == NULL) return NULL; return recorder; }
static bool input_curl_init(const struct config_param *param, G_GNUC_UNUSED GError **error_r) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); if (code != CURLE_OK) { g_warning("curl_global_init() failed: %s\n", curl_easy_strerror(code)); return false; } http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK"); proxy = config_get_block_string(param, "proxy", NULL); proxy_port = config_get_block_unsigned(param, "proxy_port", 0); proxy_user = config_get_block_string(param, "proxy_user", NULL); proxy_password = config_get_block_string(param, "proxy_password", NULL); if (proxy == NULL) { /* deprecated proxy configuration */ proxy = config_get_string(CONF_HTTP_PROXY_HOST, NULL); proxy_port = config_get_positive(CONF_HTTP_PROXY_PORT, 0); proxy_user = config_get_string(CONF_HTTP_PROXY_USER, NULL); proxy_password = config_get_string(CONF_HTTP_PROXY_PASSWORD, ""); } return true; }
static bool vorbis_encoder_configure(struct vorbis_encoder *encoder, const struct config_param *param, GError **error) { const char *value; char *endptr; value = config_get_block_string(param, "quality", NULL); if (value != NULL) { /* a quality was configured (VBR) */ encoder->quality = g_ascii_strtod(value, &endptr); if (*endptr != '\0' || encoder->quality < -1.0 || encoder->quality > 10.0) { g_set_error(error, vorbis_encoder_quark(), 0, "quality \"%s\" is not a number in the " "range -1 to 10, line %i", value, param->line); return false; } if (config_get_block_string(param, "bitrate", NULL) != NULL) { g_set_error(error, vorbis_encoder_quark(), 0, "quality and bitrate are " "both defined (line %i)", param->line); return false; } } else { /* a bit rate was configured */ value = config_get_block_string(param, "bitrate", NULL); if (value == NULL) { g_set_error(error, vorbis_encoder_quark(), 0, "neither bitrate nor quality defined " "at line %i", param->line); return false; } encoder->quality = -2.0; encoder->bitrate = g_ascii_strtoll(value, &endptr, 10); if (*endptr != '\0' || encoder->bitrate <= 0) { g_set_error(error, vorbis_encoder_quark(), 0, "bitrate at line %i should be a positive integer", param->line); return false; } } return true; }
static struct mixer * alsa_mixer_init(G_GNUC_UNUSED void *ao, const struct config_param *param, G_GNUC_UNUSED GError **error_r) { struct alsa_mixer *am = g_new(struct alsa_mixer, 1); mixer_init(&am->base, &alsa_mixer_plugin); am->device = config_get_block_string(param, "mixer_device", VOLUME_MIXER_ALSA_DEFAULT); am->control = config_get_block_string(param, "mixer_control", VOLUME_MIXER_ALSA_CONTROL_DEFAULT); am->index = config_get_block_unsigned(param, "mixer_index", VOLUME_MIXER_ALSA_INDEX_DEFAULT); return &am->base; }
static void * winmm_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, G_GNUC_UNUSED const struct config_param *param, G_GNUC_UNUSED GError **error) { struct winmm_output *wo = g_new(struct winmm_output, 1); const char *device = config_get_block_string(param, "device", NULL); wo->device_id = get_device_id(device); return wo; }
static bool lastfm_init(const struct config_param *param) { const char *user = config_get_block_string(param, "user", NULL); const char *passwd = config_get_block_string(param, "password", NULL); if (user == NULL || passwd == NULL) { g_debug("disabling the last.fm playlist plugin " "because account is not configured"); return false; } lastfm_config.user = g_uri_escape_string(user, NULL, false); if (strlen(passwd) != 32) lastfm_config.md5 = g_compute_checksum_for_string(G_CHECKSUM_MD5, passwd, strlen(passwd)); else lastfm_config.md5 = g_strdup(passwd); return true; }
static struct audio_output * solaris_output_init(const struct config_param *param, GError **error_r) { struct solaris_output *so = g_new(struct solaris_output, 1); if (!ao_base_init(&so->base, &solaris_output_plugin, param, error_r)) { g_free(so); return NULL; } so->device = config_get_block_string(param, "device", "/dev/audio"); return &so->base; }
static const struct config_param * find_named_config_block(const char *block, const char *name) { const struct config_param *param = NULL; while ((param = config_get_next_param(block, param)) != NULL) { const char *current_name = config_get_block_string(param, "name", NULL); if (current_name != NULL && strcmp(current_name, name) == 0) return param; } return NULL; }
static void * httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, const struct config_param *param, GError **error) { struct httpd_output *httpd = g_new(struct httpd_output, 1); const char *encoder_name; const struct encoder_plugin *encoder_plugin; guint port; struct sockaddr_in *sin; /* read configuration */ port = config_get_block_unsigned(param, "port", 8000); encoder_name = config_get_block_string(param, "encoder", "vorbis"); encoder_plugin = encoder_plugin_get(encoder_name); if (encoder_plugin == NULL) { g_set_error(error, httpd_output_quark(), 0, "No such encoder: %s", encoder_name); return NULL; } if (strcmp(encoder_name, "vorbis") == 0) httpd->content_type = "application/x-ogg"; else if (strcmp(encoder_name, "lame") == 0) httpd->content_type = "audio/mpeg"; else httpd->content_type = "application/octet-stream"; /* initialize listen address */ sin = (struct sockaddr_in *)&httpd->address; memset(sin, 0, sizeof(sin)); sin->sin_port = htons(port); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; httpd->address_size = sizeof(*sin); /* initialize encoder */ httpd->encoder = encoder_init(encoder_plugin, param, error); if (httpd->encoder == NULL) return NULL; httpd->mutex = g_mutex_new(); return httpd; }
static struct audio_output * pulse_output_init(const struct config_param *param, GError **error_r) { struct pulse_output *po; g_setenv("PULSE_PROP_media.role", "music", true); po = g_new(struct pulse_output, 1); if (!ao_base_init(&po->base, &pulse_output_plugin, param, error_r)) { g_free(po); return NULL; } po->name = config_get_block_string(param, "name", "mpd_pulse"); po->server = config_get_block_string(param, "server", NULL); po->sink = config_get_block_string(param, "sink", NULL); po->mixer = NULL; po->mainloop = NULL; po->context = NULL; po->stream = NULL; return &po->base; }
/** * Determines the mixer type which should be used for the specified * configuration block. * * This handles the deprecated options mixer_type (global) and * mixer_enabled, if the mixer_type setting is not configured. */ static enum mixer_type audio_output_mixer_type(const struct config_param *param) { /* read the local "mixer_type" setting */ const char *p = config_get_block_string(param, "mixer_type", NULL); if (p != NULL) return mixer_type_parse(p); /* try the local "mixer_enabled" setting next (deprecated) */ if (!config_get_block_bool(param, "mixer_enabled", true)) return MIXER_TYPE_NONE; /* fall back to the global "mixer_type" setting (also deprecated) */ return mixer_type_parse(config_get_string("mixer_type", "hardware")); }
static bool wildmidi_init(const struct config_param *param) { const char *config_file; int ret; config_file = config_get_block_string(param, "config_file", "/etc/timidity/timidity.cfg"); if (!g_file_test(config_file, G_FILE_TEST_IS_REGULAR)) { g_debug("configuration file does not exist: %s", config_file); return false; } ret = WildMidi_Init(config_file, WILDMIDI_SAMPLE_RATE, 0); return ret == 0; }
static void * openal_init(G_GNUC_UNUSED const struct audio_format *audio_format, const struct config_param *param, G_GNUC_UNUSED GError **error) { const char *device_name = config_get_block_string(param, "device", NULL); struct openal_data *od; if (device_name == NULL) { device_name = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); } od = g_new(struct openal_data, 1); od->device_name = device_name; return od; }
static struct audio_output * winmm_output_init(const struct config_param *param, GError **error_r) { struct winmm_output *wo = g_new(struct winmm_output, 1); if (!ao_base_init(&wo->base, &winmm_output_plugin, param, error_r)) { g_free(wo); return NULL; } const char *device = config_get_block_string(param, "device", NULL); if (!get_device_id(device, &wo->device_id, error_r)) { ao_base_finish(&wo->base); g_free(wo); return NULL; } return &wo->base; }
/** * Find the "decoder" configuration block for the specified plugin. * * @param plugin_name the name of the decoder plugin * @return the configuration block, or NULL if none was configured */ static const struct config_param * decoder_plugin_config(const char *plugin_name) { const struct config_param *param = NULL; while ((param = config_get_next_param(CONF_DECODER, param)) != NULL) { const char *name = config_get_block_string(param, "plugin", NULL); if (name == NULL) g_error("decoder configuration without 'plugin' name in line %d", param->line); if (strcmp(name, plugin_name) == 0) return param; } return NULL; }
static void osx_output_configure(struct osx_output *oo, const struct config_param *param) { const char *device = config_get_block_string(param, "device", NULL); if (device == NULL || 0 == strcmp(device, "default")) { oo->component_subtype = kAudioUnitSubType_DefaultOutput; oo->device_name = NULL; } else if (0 == strcmp(device, "system")) { oo->component_subtype = kAudioUnitSubType_SystemOutput; oo->device_name = NULL; } else { oo->component_subtype = kAudioUnitSubType_HALOutput; /* XXX am I supposed to g_strdup() this? */ oo->device_name = device; } }
/** * Find the "playlist" configuration block for the specified plugin. * * @param plugin_name the name of the playlist plugin * @return the configuration block, or NULL if none was configured */ static const struct config_param * playlist_plugin_config(const char *plugin_name) { const struct config_param *param = NULL; assert(plugin_name != NULL); while ((param = config_get_next_param(CONF_PLAYLIST_PLUGIN, param)) != NULL) { const char *name = config_get_block_string(param, "name", NULL); if (name == NULL) g_error("playlist configuration without 'plugin' name in line %d", param->line); if (strcmp(name, plugin_name) == 0) return param; } return NULL; }
/** * Find the "input" configuration block for the specified plugin. * * @param plugin_name the name of the input plugin * @return the configuration block, or NULL if none was configured */ static const struct config_param * input_plugin_config(const char *plugin_name, GError **error_r) { const struct config_param *param = NULL; while ((param = config_get_next_param(CONF_INPUT, param)) != NULL) { const char *name = config_get_block_string(param, "plugin", NULL); if (name == NULL) { g_set_error(error_r, input_quark(), 0, "input configuration without 'plugin' name in line %d", param->line); return NULL; } if (strcmp(name, plugin_name) == 0) return param; } return NULL; }
static bool fluidsynth_init(const struct config_param *param) { GError *error = NULL; sample_rate = config_get_block_unsigned(param, "sample_rate", 48000); if (!audio_check_sample_rate(sample_rate, &error)) { g_warning("%s\n", error->message); g_error_free(error); return false; } soundfont_path = config_get_block_string(param, "soundfont", "/usr/share/sounds/sf2/FluidR3_GM.sf2"); fluid_set_log_function(LAST_LOG_LEVEL, fluidsynth_mpd_log_function, NULL); return true; }
bool audio_output_init(struct audio_output *ao, const struct config_param *param, GError **error_r) { const struct audio_output_plugin *plugin = NULL; GError *error = NULL; if (param) { const char *p; p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL); if (p == NULL) { g_set_error(error_r, audio_output_quark(), 0, "Missing \"type\" configuration"); return false; } plugin = audio_output_plugin_get(p); if (plugin == NULL) { g_set_error(error_r, audio_output_quark(), 0, "No such audio output plugin: %s", p); return false; } ao->name = config_get_block_string(param, AUDIO_OUTPUT_NAME, NULL); if (ao->name == NULL) { g_set_error(error_r, audio_output_quark(), 0, "Missing \"name\" configuration"); return false; } p = config_get_block_string(param, AUDIO_OUTPUT_FORMAT, NULL); if (p != NULL) { bool success = audio_format_parse(&ao->config_audio_format, p, true, error_r); if (!success) return false; } else audio_format_clear(&ao->config_audio_format); } else { g_warning("No \"%s\" defined in config file\n", CONF_AUDIO_OUTPUT); plugin = audio_output_detect(error_r); if (plugin == NULL) return false; g_message("Successfully detected a %s audio device", plugin->name); ao->name = "default detected output"; audio_format_clear(&ao->config_audio_format); } ao->plugin = plugin; ao->always_on = config_get_block_bool(param, "always_on", false); ao->enabled = config_get_block_bool(param, "enabled", true); ao->really_enabled = false; ao->open = false; ao->pause = false; ao->fail_timer = NULL; pcm_buffer_init(&ao->cross_fade_buffer); /* set up the filter chain */ ao->filter = filter_chain_new(); assert(ao->filter != NULL); /* create the replay_gain filter */ const char *replay_gain_handler = config_get_block_string(param, "replay_gain_handler", "software"); if (strcmp(replay_gain_handler, "none") != 0) { ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin, param, NULL); assert(ao->replay_gain_filter != NULL); ao->replay_gain_serial = 0; ao->other_replay_gain_filter = filter_new(&replay_gain_filter_plugin, param, NULL); assert(ao->other_replay_gain_filter != NULL); ao->other_replay_gain_serial = 0; } else { ao->replay_gain_filter = NULL; ao->other_replay_gain_filter = NULL; } /* create the normalization filter (if configured) */ if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) { struct filter *normalize_filter = filter_new(&normalize_filter_plugin, NULL, NULL); assert(normalize_filter != NULL); filter_chain_append(ao->filter, autoconvert_filter_new(normalize_filter)); } filter_chain_parse(ao->filter, config_get_block_string(param, AUDIO_FILTERS, ""), &error ); // It's not really fatal - Part of the filter chain has been set up already // and even an empty one will work (if only with unexpected behaviour) if (error != NULL) { g_warning("Failed to initialize filter chain for '%s': %s", ao->name, error->message); g_error_free(error); } ao->thread = NULL; ao->command = AO_COMMAND_NONE; ao->mutex = g_mutex_new(); ao->cond = g_cond_new(); ao->data = ao_plugin_init(plugin, &ao->config_audio_format, param, error_r); if (ao->data == NULL) return false; ao->mixer = audio_output_load_mixer(ao->data, param, plugin->mixer_plugin, ao->filter, &error); if (ao->mixer == NULL && error != NULL) { g_warning("Failed to initialize hardware mixer for '%s': %s", ao->name, error->message); g_error_free(error); } /* use the hardware mixer for replay gain? */ if (strcmp(replay_gain_handler, "mixer") == 0) { if (ao->mixer != NULL) replay_gain_filter_set_mixer(ao->replay_gain_filter, ao->mixer, 100); else g_warning("No such mixer for output '%s'", ao->name); } else if (strcmp(replay_gain_handler, "software") != 0 && ao->replay_gain_filter != NULL) { g_set_error(error_r, audio_output_quark(), 0, "Invalid \"replay_gain_handler\" value"); return false; } /* the "convert" filter must be the last one in the chain */ ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL); assert(ao->convert_filter != NULL); filter_chain_append(ao->filter, ao->convert_filter); /* done */ return true; }
port = config_get_block_unsigned(param, "port", 0); if (port == 0) { g_set_error(error, shout_output_quark(), 0, "shout port must be configured"); return NULL; } check_block_param("password"); passwd = block_param->value; check_block_param("name"); name = block_param->value; public = config_get_block_bool(param, "public", false); user = config_get_block_string(param, "user", "source"); value = config_get_block_string(param, "quality", NULL); if (value != NULL) { sd->quality = strtod(value, &test); if (*test != '\0' || sd->quality < -1.0 || sd->quality > 10.0) { g_set_error(error, shout_output_quark(), 0, "shout quality \"%s\" is not a number in the " "range -1 to 10, line %i", value, param->line); return NULL; } if (config_get_block_string(param, "bitrate", NULL) != NULL) { g_set_error(error, shout_output_quark(), 0,
/** * Parse the "routes" section, a string on the form * a>b, c>d, e>f, ... * where a... are non-unique, non-negative integers * and input channel a gets copied to output channel b, etc. * @param param the configuration block to read * @param filter a route_filter whose min_channels and sources[] to set * @return true on success, false on error */ static bool route_filter_parse(const struct config_param *param, struct route_filter *filter, GError **error_r) { /* TODO: * With a more clever way of marking "don't copy to output N", * This could easily be merged into a single loop with some * dynamic g_realloc() instead of one count run and one g_malloc(). */ gchar **tokens; int number_of_copies; // A cowardly default, just passthrough stereo const char *routes = config_get_block_string(param, "routes", "0>0, 1>1"); filter->min_input_channels = 0; filter->min_output_channels = 0; tokens = g_strsplit(routes, ",", 255); number_of_copies = g_strv_length(tokens); // Start by figuring out a few basic things about the routing set for (int c=0; c<number_of_copies; ++c) { // String and int representations of the source/destination gchar **sd; int source, dest; // Squeeze whitespace g_strstrip(tokens[c]); // Split the a>b string into source and destination sd = g_strsplit(tokens[c], ">", 2); if (g_strv_length(sd) != 2) { g_set_error(error_r, config_quark(), 1, "Invalid copy around %d in routes spec: %s", param->line, tokens[c]); g_strfreev(sd); g_strfreev(tokens); return false; } source = strtol(sd[0], NULL, 10); dest = strtol(sd[1], NULL, 10); // Keep track of the highest channel numbers seen // as either in- or outputs if (source >= filter->min_input_channels) filter->min_input_channels = source + 1; if (dest >= filter->min_output_channels) filter->min_output_channels = dest + 1; g_strfreev(sd); } if (!audio_valid_channel_count(filter->min_output_channels)) { g_strfreev(tokens); g_set_error(error_r, audio_format_quark(), 0, "Invalid number of output channels requested: %d", filter->min_output_channels); return false; } // Allocate a map of "copy nothing to me" filter->sources = g_malloc(filter->min_output_channels * sizeof(signed char)); for (int i=0; i<filter->min_output_channels; ++i) filter->sources[i] = -1; // Run through the spec again, and save the // actual mapping output <- input for (int c=0; c<number_of_copies; ++c) { // String and int representations of the source/destination gchar **sd; int source, dest; // Split the a>b string into source and destination sd = g_strsplit(tokens[c], ">", 2); if (g_strv_length(sd) != 2) { g_set_error(error_r, config_quark(), 1, "Invalid copy around %d in routes spec: %s", param->line, tokens[c]); g_strfreev(sd); g_strfreev(tokens); return false; } source = strtol(sd[0], NULL, 10); dest = strtol(sd[1], NULL, 10); filter->sources[dest] = source; g_strfreev(sd); } g_strfreev(tokens); return true; }
static struct audio_output * httpd_output_init(const struct config_param *param, GError **error) { struct httpd_output *httpd = g_new(struct httpd_output, 1); if (!ao_base_init(&httpd->base, &httpd_output_plugin, param, error)) { g_free(httpd); return NULL; } const char *encoder_name, *bind_to_address; const struct encoder_plugin *encoder_plugin; guint port; /* read configuration */ httpd->name = config_get_block_string(param, "name", "Set name in config"); httpd->genre = config_get_block_string(param, "genre", "Set genre in config"); httpd->website = config_get_block_string(param, "website", "Set website in config"); port = config_get_block_unsigned(param, "port", 8000); encoder_name = config_get_block_string(param, "encoder", "vorbis"); encoder_plugin = encoder_plugin_get(encoder_name); if (encoder_plugin == NULL) { g_set_error(error, httpd_output_quark(), 0, "No such encoder: %s", encoder_name); ao_base_finish(&httpd->base); g_free(httpd); return NULL; } httpd->clients_max = config_get_block_unsigned(param,"max_clients", 0); /* set up bind_to_address */ httpd->server_socket = server_socket_new(httpd_listen_in_event, httpd); bind_to_address = config_get_block_string(param, "bind_to_address", NULL); bool success = bind_to_address != NULL && strcmp(bind_to_address, "any") != 0 ? server_socket_add_host(httpd->server_socket, bind_to_address, port, error) : server_socket_add_port(httpd->server_socket, port, error); if (!success) { ao_base_finish(&httpd->base); g_free(httpd); return NULL; } /* initialize metadata */ httpd->metadata = NULL; httpd->unflushed_input = 0; /* initialize encoder */ httpd->encoder = encoder_init(encoder_plugin, param, error); if (httpd->encoder == NULL) { ao_base_finish(&httpd->base); g_free(httpd); return NULL; } /* determine content type */ httpd->content_type = encoder_get_mime_type(httpd->encoder); if (httpd->content_type == NULL) { httpd->content_type = "application/octet-stream"; } httpd->mutex = g_mutex_new(); return &httpd->base; }
static struct audio_output * ao_output_init(const struct config_param *param, GError **error) { struct ao_data *ad = g_new(struct ao_data, 1); if (!ao_base_init(&ad->base, &ao_output_plugin, param, error)) { g_free(ad); return NULL; } ao_info *ai; const char *value; ad->options = NULL; ad->write_size = config_get_block_unsigned(param, "write_size", 1024); if (ao_output_ref == 0) { ao_initialize(); } ao_output_ref++; value = config_get_block_string(param, "driver", "default"); if (0 == strcmp(value, "default")) ad->driver = ao_default_driver_id(); else ad->driver = ao_driver_id(value); if (ad->driver < 0) { g_set_error(error, ao_output_quark(), 0, "\"%s\" is not a valid ao driver", value); ao_base_finish(&ad->base); g_free(ad); return NULL; } if ((ai = ao_driver_info(ad->driver)) == NULL) { g_set_error(error, ao_output_quark(), 0, "problems getting driver info"); ao_base_finish(&ad->base); g_free(ad); return NULL; } g_debug("using ao driver \"%s\" for \"%s\"\n", ai->short_name, config_get_block_string(param, "name", NULL)); value = config_get_block_string(param, "options", NULL); if (value != NULL) { gchar **options = g_strsplit(value, ";", 0); for (unsigned i = 0; options[i] != NULL; ++i) { gchar **key_value = g_strsplit(options[i], "=", 2); if (key_value[0] == NULL || key_value[1] == NULL) { g_set_error(error, ao_output_quark(), 0, "problems parsing options \"%s\"", options[i]); ao_base_finish(&ad->base); g_free(ad); return NULL; } ao_append_option(&ad->options, key_value[0], key_value[1]); g_strfreev(key_value); } g_strfreev(options); } return &ad->base; }