qt: add device preferences for mmdevice
[vlc.git] / modules / audio_output / winstore.c
blobd345673249527f556761a32067d93a13b2caf4d8
1 /*****************************************************************************
2 * mmdevice.c : Windows Multimedia Device API audio output plugin for VLC
3 *****************************************************************************
4 * Copyright (C) 2012 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #define INITGUID
26 #define COBJMACROS
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <audiopolicy.h>
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_aout.h>
35 #include <vlc_modules.h>
36 #include "audio_output/mmdevice.h"
38 DEFINE_GUID (GUID_VLC_AUD_OUT, 0x4533f59d, 0x59ee, 0x00c6,
39 0xad, 0xb2, 0xc6, 0x8b, 0x50, 0x1a, 0x66, 0x55);
41 static void EnterMTA(void)
43 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
44 if (unlikely(FAILED(hr)))
45 abort();
48 static void LeaveMTA(void)
50 CoUninitialize();
53 struct aout_sys_t
55 aout_stream_t *stream; /**< Underlying audio output stream */
56 module_t *module;
57 IAudioClient *client;
60 static int vlc_FromHR(audio_output_t *aout, HRESULT hr)
62 aout_sys_t* sys = aout->sys;
63 /* Select the default device (and restart) on unplug */
64 if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
65 hr == AUDCLNT_E_RESOURCES_INVALIDATED))
67 sys->client = NULL;
69 return SUCCEEDED(hr) ? 0 : -1;
72 static int VolumeSet(audio_output_t *aout, float vol)
74 aout_sys_t *sys = aout->sys;
75 if( unlikely( sys->client == NULL ) )
76 return VLC_EGENERIC;
77 HRESULT hr;
78 ISimpleAudioVolume *pc_AudioVolume = NULL;
79 float gain = 1.f;
81 vol = vol * vol * vol; /* ISimpleAudioVolume is tapered linearly. */
83 if (vol > 1.f)
85 gain = vol;
86 vol = 1.f;
89 aout_GainRequest(aout, gain);
91 hr = IAudioClient_GetService(sys->client, &IID_ISimpleAudioVolume, &pc_AudioVolume);
92 if (FAILED(hr))
94 msg_Err(aout, "cannot get volume service (error 0x%lx)", hr);
95 goto done;
98 hr = ISimpleAudioVolume_SetMasterVolume(pc_AudioVolume, vol, NULL);
99 if (FAILED(hr))
101 msg_Err(aout, "cannot set volume (error 0x%lx)", hr);
102 goto done;
105 done:
106 ISimpleAudioVolume_Release(pc_AudioVolume);
108 return SUCCEEDED(hr) ? 0 : -1;
111 static int MuteSet(audio_output_t *aout, bool mute)
113 aout_sys_t *sys = aout->sys;
114 if( unlikely( sys->client == NULL ) )
115 return VLC_EGENERIC;
116 HRESULT hr;
117 ISimpleAudioVolume *pc_AudioVolume = NULL;
119 hr = IAudioClient_GetService(sys->client, &IID_ISimpleAudioVolume, &pc_AudioVolume);
120 if (FAILED(hr))
122 msg_Err(aout, "cannot get volume service (error 0x%lx)", hr);
123 goto done;
126 hr = ISimpleAudioVolume_SetMute(pc_AudioVolume, mute, NULL);
127 if (FAILED(hr))
129 msg_Err(aout, "cannot set mute (error 0x%lx)", hr);
130 goto done;
133 done:
134 ISimpleAudioVolume_Release(pc_AudioVolume);
136 return SUCCEEDED(hr) ? 0 : -1;
139 static int TimeGet(audio_output_t *aout, mtime_t *restrict delay)
141 aout_sys_t *sys = aout->sys;
142 if( unlikely( sys->client == NULL ) )
143 return VLC_EGENERIC;
144 HRESULT hr;
146 EnterMTA();
147 hr = aout_stream_TimeGet(sys->stream, delay);
148 LeaveMTA();
150 return SUCCEEDED(hr) ? 0 : -1;
153 static void Play(audio_output_t *aout, block_t *block)
155 aout_sys_t *sys = aout->sys;
156 if( unlikely( sys->client == NULL ) )
157 return;
159 EnterMTA();
160 HRESULT hr = aout_stream_Play(sys->stream, block);
161 LeaveMTA();
163 vlc_FromHR(aout, hr);
166 static void Pause(audio_output_t *aout, bool paused, mtime_t date)
168 aout_sys_t *sys = aout->sys;
169 if( unlikely( sys->client == NULL ) )
170 return;
172 EnterMTA();
173 HRESULT hr = aout_stream_Pause(sys->stream, paused);
174 LeaveMTA();
176 (void) date;
177 vlc_FromHR(aout, hr);
180 static void Flush(audio_output_t *aout, bool wait)
182 aout_sys_t *sys = aout->sys;
183 if( unlikely( sys->client == NULL ) )
184 return;
186 EnterMTA();
187 HRESULT hr = aout_stream_Flush(sys->stream, wait);
188 LeaveMTA();
190 vlc_FromHR(aout, hr);
193 static HRESULT ActivateDevice(void *opaque, REFIID iid, PROPVARIANT *actparms,
194 void **restrict pv)
196 IAudioClient *client = opaque;
198 if (!IsEqualIID(iid, &IID_IAudioClient))
199 return E_NOINTERFACE;
200 if (actparms != NULL || client == NULL )
201 return E_INVALIDARG;
203 IAudioClient_AddRef(client);
204 *pv = opaque;
206 return S_OK;
209 static int aout_stream_Start(void *func, va_list ap)
211 aout_stream_start_t start = func;
212 aout_stream_t *s = va_arg(ap, aout_stream_t *);
213 audio_sample_format_t *fmt = va_arg(ap, audio_sample_format_t *);
214 HRESULT *hr = va_arg(ap, HRESULT *);
216 *hr = start(s, fmt, &GUID_VLC_AUD_OUT);
217 return SUCCEEDED(*hr) ? VLC_SUCCESS : VLC_EGENERIC;
220 static void aout_stream_Stop(void *func, va_list ap)
222 aout_stream_stop_t stop = func;
223 aout_stream_t *s = va_arg(ap, aout_stream_t *);
225 stop(s);
228 static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
230 aout_sys_t *sys = aout->sys;
231 HRESULT hr;
233 aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
234 if (unlikely(s == NULL))
235 return -1;
237 s->owner.device = sys->client;
238 s->owner.activate = ActivateDevice;
240 EnterMTA();
241 sys->module = vlc_module_load(s, "aout stream", NULL, false,
242 aout_stream_Start, s, fmt, &hr);
243 LeaveMTA();
245 if (sys->module == NULL)
247 vlc_object_release(s);
248 return -1;
251 assert (sys->stream == NULL);
252 sys->stream = s;
253 return 0;
256 static void Stop(audio_output_t *aout)
258 aout_sys_t *sys = aout->sys;
260 assert (sys->stream != NULL);
262 EnterMTA();
263 vlc_module_unload(sys->stream, sys->module, aout_stream_Stop, sys->stream);
264 LeaveMTA();
266 vlc_object_release(sys->stream);
267 sys->stream = NULL;
270 static int DeviceSelect(audio_output_t *aout, const char* psz_device)
272 if( psz_device == NULL )
273 return VLC_EGENERIC;
274 char* psz_end;
275 intptr_t ptr = strtoll( psz_device, &psz_end, 16 );
276 if ( *psz_end != 0 )
277 return VLC_EGENERIC;
278 if (aout->sys->client == (IAudioClient*)ptr)
279 return VLC_SUCCESS;
280 aout->sys->client = (IAudioClient*)ptr;
281 var_SetAddress( aout->obj.parent, "winstore-client", aout->sys->client );
282 aout_RestartRequest( aout, AOUT_RESTART_OUTPUT );
283 return VLC_SUCCESS;
286 static int Open(vlc_object_t *obj)
288 audio_output_t *aout = (audio_output_t *)obj;
290 aout_sys_t *sys = malloc(sizeof (*sys));
291 if (unlikely(sys == NULL))
292 return VLC_ENOMEM;
294 aout->sys = sys;
295 sys->stream = NULL;
296 aout->sys->client = var_CreateGetAddress( aout->obj.parent, "winstore-client" );
297 if (aout->sys->client != NULL)
298 msg_Dbg( aout, "Reusing previous client: %p", aout->sys->client );
299 aout->start = Start;
300 aout->stop = Stop;
301 aout->time_get = TimeGet;
302 aout->volume_set = VolumeSet;
303 aout->mute_set = MuteSet;
304 aout->play = Play;
305 aout->pause = Pause;
306 aout->flush = Flush;
307 aout->device_select = DeviceSelect;
308 return VLC_SUCCESS;
311 static void Close(vlc_object_t *obj)
313 audio_output_t *aout = (audio_output_t *)obj;
314 aout_sys_t *sys = aout->sys;
316 free(sys);
319 vlc_module_begin()
320 set_shortname("winstore")
321 set_description("Windows Store audio output")
322 set_capability("audio output", 0)
323 set_category(CAT_AUDIO)
324 set_subcategory(SUBCAT_AUDIO_AOUT)
325 add_shortcut("wasapi")
326 set_callbacks(Open, Close)
327 vlc_module_end()