winwave: remove wait object when finalizing DAC voice
[qemu/cris-port.git] / audio / winwaveaudio.c
blob5bbce2abdc0d6b703c3e8f97c5034587d4137cf1
1 /* public domain */
3 #include "qemu-common.h"
4 #include "sysemu.h"
5 #include "audio.h"
7 #define AUDIO_CAP "winwave"
8 #include "audio_int.h"
10 #include <windows.h>
11 #include <mmsystem.h>
13 #include "audio_win_int.h"
15 static struct {
16 int dac_headers;
17 int dac_samples;
18 } conf = {
19 .dac_headers = 4,
20 .dac_samples = 1024
23 typedef struct {
24 HWVoiceOut hw;
25 HWAVEOUT hwo;
26 WAVEHDR *hdrs;
27 HANDLE event;
28 void *pcm_buf;
29 int avail;
30 int pending;
31 int curhdr;
32 CRITICAL_SECTION crit_sect;
33 } WaveVoiceOut;
35 static void winwave_log_mmresult (MMRESULT mr)
37 const char *str = "BUG";
39 switch (mr) {
40 case MMSYSERR_NOERROR:
41 str = "Success";
42 break;
44 case MMSYSERR_INVALHANDLE:
45 str = "Specified device handle is invalid";
46 break;
48 case MMSYSERR_BADDEVICEID:
49 str = "Specified device id is out of range";
50 break;
52 case MMSYSERR_NODRIVER:
53 str = "No device driver is present";
54 break;
56 case MMSYSERR_NOMEM:
57 str = "Unable to allocate or locl memory";
58 break;
60 case WAVERR_SYNC:
61 str = "Device is synchronous but waveOutOpen was called "
62 "without using the WINWAVE_ALLOWSYNC flag";
63 break;
65 case WAVERR_UNPREPARED:
66 str = "The data block pointed to by the pwh parameter "
67 "hasn't been prepared";
68 break;
70 default:
71 AUD_log (AUDIO_CAP, "Reason: Unknown (MMRESULT %#x)\n", mr);
72 return;
75 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
78 static void GCC_FMT_ATTR (2, 3) winwave_logerr (
79 MMRESULT mr,
80 const char *fmt,
81 ...
84 va_list ap;
86 va_start (ap, fmt);
87 AUD_vlog (AUDIO_CAP, fmt, ap);
88 va_end (ap);
90 winwave_log_mmresult (mr);
93 static void winwave_anal_close_out (WaveVoiceOut *wave)
95 MMRESULT mr;
97 mr = waveOutClose (wave->hwo);
98 if (mr != MMSYSERR_NOERROR) {
99 winwave_logerr (mr, "waveOutClose\n");
101 wave->hwo = NULL;
104 static void CALLBACK winwave_callback (
105 HWAVEOUT hwo,
106 UINT msg,
107 DWORD_PTR dwInstance,
108 DWORD_PTR dwParam1,
109 DWORD_PTR dwParam2
112 WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
114 switch (msg) {
115 case WOM_DONE:
117 WAVEHDR *h = (WAVEHDR *) dwParam1;
118 if (!h->dwUser) {
119 h->dwUser = 1;
120 EnterCriticalSection (&wave->crit_sect);
122 wave->avail += conf.dac_samples;
124 LeaveCriticalSection (&wave->crit_sect);
125 if (wave->hw.poll_mode) {
126 if (!SetEvent (wave->event)) {
127 AUD_log (AUDIO_CAP, "SetEvent failed %lx\n",
128 GetLastError ());
133 break;
135 case WOM_CLOSE:
136 case WOM_OPEN:
137 break;
139 default:
140 AUD_log (AUDIO_CAP, "unknown wave callback msg %x\n", msg);
144 static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
146 int i;
147 int err;
148 MMRESULT mr;
149 WAVEFORMATEX wfx;
150 WaveVoiceOut *wave;
152 wave = (WaveVoiceOut *) hw;
154 InitializeCriticalSection (&wave->crit_sect);
156 err = waveformat_from_audio_settings (&wfx, as);
157 if (err) {
158 goto err0;
161 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
162 (DWORD_PTR) winwave_callback,
163 (DWORD_PTR) wave, CALLBACK_FUNCTION);
164 if (mr != MMSYSERR_NOERROR) {
165 winwave_logerr (mr, "waveOutOpen\n");
166 goto err1;
169 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
170 sizeof (*wave->hdrs));
171 if (!wave->hdrs) {
172 goto err2;
175 audio_pcm_init_info (&hw->info, as);
176 hw->samples = conf.dac_samples * conf.dac_headers;
177 wave->avail = hw->samples;
179 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
180 conf.dac_headers << hw->info.shift);
181 if (!wave->pcm_buf) {
182 goto err3;
185 for (i = 0; i < conf.dac_headers; ++i) {
186 WAVEHDR *h = &wave->hdrs[i];
188 h->dwUser = 0;
189 h->dwBufferLength = conf.dac_samples << hw->info.shift;
190 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
191 h->dwFlags = 0;
193 mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
194 if (mr != MMSYSERR_NOERROR) {
195 winwave_logerr (mr, "waveOutPrepareHeader(%d)\n", wave->curhdr);
196 goto err4;
200 return 0;
202 err4:
203 qemu_free (wave->pcm_buf);
204 err3:
205 qemu_free (wave->hdrs);
206 err2:
207 winwave_anal_close_out (wave);
208 err1:
209 err0:
210 return -1;
213 static int winwave_write (SWVoiceOut *sw, void *buf, int len)
215 return audio_pcm_sw_write (sw, buf, len);
218 static int winwave_run_out (HWVoiceOut *hw, int live)
220 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
221 int decr;
222 int doreset;
224 EnterCriticalSection (&wave->crit_sect);
226 decr = audio_MIN (live, wave->avail);
227 decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
228 wave->pending += decr;
229 wave->avail -= decr;
231 LeaveCriticalSection (&wave->crit_sect);
233 doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
234 if (doreset && !ResetEvent (wave->event)) {
235 AUD_log (AUDIO_CAP, "ResetEvent failed %lx\n", GetLastError ());
238 while (wave->pending >= conf.dac_samples) {
239 MMRESULT mr;
240 WAVEHDR *h = &wave->hdrs[wave->curhdr];
242 h->dwUser = 0;
243 mr = waveOutWrite (wave->hwo, h, sizeof (*h));
244 if (mr != MMSYSERR_NOERROR) {
245 winwave_logerr (mr, "waveOutWrite(%d)\n", wave->curhdr);
246 break;
249 wave->pending -= conf.dac_samples;
250 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
253 return decr;
256 static void winwave_poll_out (void *opaque)
258 (void) opaque;
259 audio_run ("winwave_poll_out");
262 static void winwave_fini_out (HWVoiceOut *hw)
264 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
266 if (wave->event) {
267 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
268 if (!CloseHandle (wave->event)) {
269 AUD_log (AUDIO_CAP, "CloseHandle failed %lx\n", GetLastError ());
271 wave->event = NULL;
274 winwave_anal_close_out (wave);
276 qemu_free (wave->pcm_buf);
277 wave->pcm_buf = NULL;
279 qemu_free (wave->hdrs);
280 wave->hdrs = NULL;
283 static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
285 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
287 switch (cmd) {
288 case VOICE_ENABLE:
290 va_list ap;
291 int poll_mode;
293 va_start (ap, cmd);
294 poll_mode = va_arg (ap, int);
295 va_end (ap);
297 if (poll_mode && !wave->event) {
298 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
299 if (!wave->event) {
300 AUD_log (AUDIO_CAP,
301 "CreateEvent: %lx, poll mode will be disabled\n",
302 GetLastError ());
306 if (wave->event) {
307 int ret;
309 ret = qemu_add_wait_object (wave->event, winwave_poll_out,
310 wave);
311 hw->poll_mode = (ret == 0);
313 else {
314 hw->poll_mode = 0;
317 return 0;
319 case VOICE_DISABLE:
320 if (wave->event) {
321 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
323 return 0;
325 return -1;
328 static void *winwave_audio_init (void)
330 return &conf;
333 static void winwave_audio_fini (void *opaque)
335 (void) opaque;
338 static struct audio_option winwave_options[] = {
340 .name = "DAC_HEADERS",
341 .tag = AUD_OPT_INT,
342 .valp = &conf.dac_headers,
343 .descr = "DAC number of headers",
346 .name = "DAC_SAMPLES",
347 .tag = AUD_OPT_INT,
348 .valp = &conf.dac_samples,
349 .descr = "DAC number of samples per header",
351 { /* End of list */ }
354 static struct audio_pcm_ops winwave_pcm_ops = {
355 .init_out = winwave_init_out,
356 .fini_out = winwave_fini_out,
357 .run_out = winwave_run_out,
358 .write = winwave_write,
359 .ctl_out = winwave_ctl_out
362 struct audio_driver winwave_audio_driver = {
363 .name = "winwave",
364 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
365 .options = winwave_options,
366 .init = winwave_audio_init,
367 .fini = winwave_audio_fini,
368 .pcm_ops = &winwave_pcm_ops,
369 .can_be_default = 1,
370 .max_voices_out = INT_MAX,
371 .max_voices_in = 0,
372 .voice_size_out = sizeof (WaveVoiceOut),
373 .voice_size_in = 0