diff options
Diffstat (limited to 'src/output/winmm_output_plugin.c')
-rw-r--r-- | src/output/winmm_output_plugin.c | 85 |
1 files changed, 54 insertions, 31 deletions
diff --git a/src/output/winmm_output_plugin.c b/src/output/winmm_output_plugin.c index 4312c635e..4d95834b9 100644 --- a/src/output/winmm_output_plugin.c +++ b/src/output/winmm_output_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,6 +18,7 @@ */ #include "config.h" +#include "winmm_output_plugin.h" #include "output_api.h" #include "pcm_buffer.h" #include "mixer_list.h" @@ -37,6 +38,8 @@ struct winmm_buffer { }; struct winmm_output { + struct audio_output base; + UINT device_id; HWAVEOUT handle; @@ -71,59 +74,80 @@ winmm_output_test_default_device(void) return waveOutGetNumDevs() > 0; } -static UINT -get_device_id(const char *device_name) +static bool +get_device_id(const char *device_name, UINT *device_id, GError **error_r) { /* if device is not specified use wave mapper */ - if (device_name == NULL) - return WAVE_MAPPER; + if (device_name == NULL) { + *device_id = WAVE_MAPPER; + return true; + } + + UINT numdevs = waveOutGetNumDevs(); /* check for device id */ char *endptr; UINT id = strtoul(device_name, &endptr, 0); - if (endptr > device_name && *endptr == 0) - return id; + if (endptr > device_name && *endptr == 0) { + if (id >= numdevs) + goto fail; + *device_id = id; + return true; + } /* check for device name */ - for (UINT i = 0; i < waveOutGetNumDevs(); i++) { + for (UINT i = 0; i < numdevs; i++) { WAVEOUTCAPS caps; MMRESULT result = waveOutGetDevCaps(i, &caps, sizeof(caps)); if (result != MMSYSERR_NOERROR) continue; /* szPname is only 32 chars long, so it is often truncated. Use partial match to work around this. */ - if (strstr(device_name, caps.szPname) == device_name) - return i; + if (strstr(device_name, caps.szPname) == device_name) { + *device_id = i; + return true; + } } - /* fallback to wave mapper */ - return WAVE_MAPPER; +fail: + g_set_error(error_r, winmm_output_quark(), 0, + "device \"%s\" is not found", device_name); + return false; } -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) +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); - wo->device_id = get_device_id(device); - return wo; + if (!get_device_id(device, &wo->device_id, error_r)) { + ao_base_finish(&wo->base); + g_free(wo); + return NULL; + } + + return &wo->base; } static void -winmm_output_finish(void *data) +winmm_output_finish(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; + ao_base_finish(&wo->base); g_free(wo); } static bool -winmm_output_open(void *data, struct audio_format *audio_format, +winmm_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error_r) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; wo->event = CreateEvent(NULL, false, false, NULL); if (wo->event == NULL) { @@ -137,7 +161,6 @@ winmm_output_open(void *data, struct audio_format *audio_format, case SAMPLE_FORMAT_S16: break; - case SAMPLE_FORMAT_S24: case SAMPLE_FORMAT_S24_P32: case SAMPLE_FORMAT_S32: case SAMPLE_FORMAT_UNDEFINED: @@ -179,9 +202,9 @@ winmm_output_open(void *data, struct audio_format *audio_format, } static void -winmm_output_close(void *data) +winmm_output_close(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i) pcm_buffer_deinit(&wo->buffers[i].buffer); @@ -248,9 +271,9 @@ winmm_drain_buffer(struct winmm_output *wo, struct winmm_buffer *buffer, } static size_t -winmm_output_play(void *data, const void *chunk, size_t size, GError **error_r) +winmm_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; /* get the next buffer from the ring and prepare it */ struct winmm_buffer *buffer = &wo->buffers[wo->next_buffer]; @@ -303,18 +326,18 @@ winmm_stop(struct winmm_output *wo) } static void -winmm_output_drain(void *data) +winmm_output_drain(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; if (!winmm_drain_all_buffers(wo, NULL)) winmm_stop(wo); } static void -winmm_output_cancel(void *data) +winmm_output_cancel(struct audio_output *ao) { - struct winmm_output *wo = data; + struct winmm_output *wo = (struct winmm_output *)ao; winmm_stop(wo); } |