winwave: make error logging more consistent
[qemu/cris-port.git] / audio / winwaveaudio.c
blobbd64a0c4be3ebd7480b628b188929f9ee8ee4237
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 int paused;
33 CRITICAL_SECTION crit_sect;
34 } WaveVoiceOut;
36 static void winwave_log_mmresult (MMRESULT mr)
38 const char *str = "BUG";
40 switch (mr) {
41 case MMSYSERR_NOERROR:
42 str = "Success";
43 break;
45 case MMSYSERR_INVALHANDLE:
46 str = "Specified device handle is invalid";
47 break;
49 case MMSYSERR_BADDEVICEID:
50 str = "Specified device id is out of range";
51 break;
53 case MMSYSERR_NODRIVER:
54 str = "No device driver is present";
55 break;
57 case MMSYSERR_NOMEM:
58 str = "Unable to allocate or locl memory";
59 break;
61 case WAVERR_SYNC:
62 str = "Device is synchronous but waveOutOpen was called "
63 "without using the WINWAVE_ALLOWSYNC flag";
64 break;
66 case WAVERR_UNPREPARED:
67 str = "The data block pointed to by the pwh parameter "
68 "hasn't been prepared";
69 break;
71 case WAVERR_STILLPLAYING:
72 str = "There are still buffers in the queue";
73 break;
75 default:
76 AUD_log (AUDIO_CAP, "Reason: Unknown (MMRESULT %#x)\n", mr);
77 return;
80 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
83 static void GCC_FMT_ATTR (2, 3) winwave_logerr (
84 MMRESULT mr,
85 const char *fmt,
86 ...
89 va_list ap;
91 va_start (ap, fmt);
92 AUD_vlog (AUDIO_CAP, fmt, ap);
93 va_end (ap);
95 AUD_log (NULL, " failed\n");
96 winwave_log_mmresult (mr);
99 static void winwave_anal_close_out (WaveVoiceOut *wave)
101 MMRESULT mr;
103 mr = waveOutClose (wave->hwo);
104 if (mr != MMSYSERR_NOERROR) {
105 winwave_logerr (mr, "waveOutClose");
107 wave->hwo = NULL;
110 static void CALLBACK winwave_callback (
111 HWAVEOUT hwo,
112 UINT msg,
113 DWORD_PTR dwInstance,
114 DWORD_PTR dwParam1,
115 DWORD_PTR dwParam2
118 WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
120 switch (msg) {
121 case WOM_DONE:
123 WAVEHDR *h = (WAVEHDR *) dwParam1;
124 if (!h->dwUser) {
125 h->dwUser = 1;
126 EnterCriticalSection (&wave->crit_sect);
128 wave->avail += conf.dac_samples;
130 LeaveCriticalSection (&wave->crit_sect);
131 if (wave->hw.poll_mode) {
132 if (!SetEvent (wave->event)) {
133 AUD_log (AUDIO_CAP, "SetEvent failed %lx\n",
134 GetLastError ());
139 break;
141 case WOM_CLOSE:
142 case WOM_OPEN:
143 break;
145 default:
146 AUD_log (AUDIO_CAP, "unknown wave callback msg %x\n", msg);
150 static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
152 int i;
153 int err;
154 MMRESULT mr;
155 WAVEFORMATEX wfx;
156 WaveVoiceOut *wave;
158 wave = (WaveVoiceOut *) hw;
160 InitializeCriticalSection (&wave->crit_sect);
162 err = waveformat_from_audio_settings (&wfx, as);
163 if (err) {
164 goto err0;
167 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
168 (DWORD_PTR) winwave_callback,
169 (DWORD_PTR) wave, CALLBACK_FUNCTION);
170 if (mr != MMSYSERR_NOERROR) {
171 winwave_logerr (mr, "waveOutOpen");
172 goto err1;
175 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
176 sizeof (*wave->hdrs));
177 if (!wave->hdrs) {
178 goto err2;
181 audio_pcm_init_info (&hw->info, as);
182 hw->samples = conf.dac_samples * conf.dac_headers;
183 wave->avail = hw->samples;
185 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
186 conf.dac_headers << hw->info.shift);
187 if (!wave->pcm_buf) {
188 goto err3;
191 for (i = 0; i < conf.dac_headers; ++i) {
192 WAVEHDR *h = &wave->hdrs[i];
194 h->dwUser = 0;
195 h->dwBufferLength = conf.dac_samples << hw->info.shift;
196 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
197 h->dwFlags = 0;
199 mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
200 if (mr != MMSYSERR_NOERROR) {
201 winwave_logerr (mr, "waveOutPrepareHeader(%d)", wave->curhdr);
202 goto err4;
206 return 0;
208 err4:
209 qemu_free (wave->pcm_buf);
210 err3:
211 qemu_free (wave->hdrs);
212 err2:
213 winwave_anal_close_out (wave);
214 err1:
215 err0:
216 return -1;
219 static int winwave_write (SWVoiceOut *sw, void *buf, int len)
221 return audio_pcm_sw_write (sw, buf, len);
224 static int winwave_run_out (HWVoiceOut *hw, int live)
226 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
227 int decr;
228 int doreset;
230 EnterCriticalSection (&wave->crit_sect);
232 decr = audio_MIN (live, wave->avail);
233 decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
234 wave->pending += decr;
235 wave->avail -= decr;
237 LeaveCriticalSection (&wave->crit_sect);
239 doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
240 if (doreset && !ResetEvent (wave->event)) {
241 AUD_log (AUDIO_CAP, "ResetEvent failed %lx\n", GetLastError ());
244 while (wave->pending >= conf.dac_samples) {
245 MMRESULT mr;
246 WAVEHDR *h = &wave->hdrs[wave->curhdr];
248 h->dwUser = 0;
249 mr = waveOutWrite (wave->hwo, h, sizeof (*h));
250 if (mr != MMSYSERR_NOERROR) {
251 winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
252 break;
255 wave->pending -= conf.dac_samples;
256 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
259 return decr;
262 static void winwave_poll_out (void *opaque)
264 (void) opaque;
265 audio_run ("winwave_poll_out");
268 static void winwave_fini_out (HWVoiceOut *hw)
270 int i;
271 MMRESULT mr;
272 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
274 mr = waveOutReset (wave->hwo);
275 if (mr != MMSYSERR_NOERROR) {
276 winwave_logerr (mr, "waveOutReset");
279 for (i = 0; i < conf.dac_headers; ++i) {
280 mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
281 sizeof (wave->hdrs[i]));
282 if (mr != MMSYSERR_NOERROR) {
283 winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
287 winwave_anal_close_out (wave);
289 if (wave->event) {
290 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
291 if (!CloseHandle (wave->event)) {
292 AUD_log (AUDIO_CAP, "CloseHandle failed %lx\n", GetLastError ());
294 wave->event = NULL;
297 qemu_free (wave->pcm_buf);
298 wave->pcm_buf = NULL;
300 qemu_free (wave->hdrs);
301 wave->hdrs = NULL;
304 static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
306 MMRESULT mr;
307 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
309 switch (cmd) {
310 case VOICE_ENABLE:
312 va_list ap;
313 int poll_mode;
315 va_start (ap, cmd);
316 poll_mode = va_arg (ap, int);
317 va_end (ap);
319 if (poll_mode && !wave->event) {
320 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
321 if (!wave->event) {
322 AUD_log (AUDIO_CAP,
323 "CreateEvent: %lx, poll mode will be disabled\n",
324 GetLastError ());
328 if (wave->event) {
329 int ret;
331 ret = qemu_add_wait_object (wave->event, winwave_poll_out,
332 wave);
333 hw->poll_mode = (ret == 0);
335 else {
336 hw->poll_mode = 0;
338 if (wave->paused) {
339 mr = waveOutRestart (wave->hwo);
340 if (mr != MMSYSERR_NOERROR) {
341 winwave_logerr (mr, "waveOutRestart");
343 wave->paused = 0;
346 return 0;
348 case VOICE_DISABLE:
349 if (!wave->paused) {
350 mr = waveOutPause (wave->hwo);
351 if (mr != MMSYSERR_NOERROR) {
352 winwave_logerr (mr, "waveOutPause");
354 else {
355 wave->paused = 1;
358 if (wave->event) {
359 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
361 return 0;
363 return -1;
366 static void *winwave_audio_init (void)
368 return &conf;
371 static void winwave_audio_fini (void *opaque)
373 (void) opaque;
376 static struct audio_option winwave_options[] = {
378 .name = "DAC_HEADERS",
379 .tag = AUD_OPT_INT,
380 .valp = &conf.dac_headers,
381 .descr = "DAC number of headers",
384 .name = "DAC_SAMPLES",
385 .tag = AUD_OPT_INT,
386 .valp = &conf.dac_samples,
387 .descr = "DAC number of samples per header",
389 { /* End of list */ }
392 static struct audio_pcm_ops winwave_pcm_ops = {
393 .init_out = winwave_init_out,
394 .fini_out = winwave_fini_out,
395 .run_out = winwave_run_out,
396 .write = winwave_write,
397 .ctl_out = winwave_ctl_out
400 struct audio_driver winwave_audio_driver = {
401 .name = "winwave",
402 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
403 .options = winwave_options,
404 .init = winwave_audio_init,
405 .fini = winwave_audio_fini,
406 .pcm_ops = &winwave_pcm_ops,
407 .can_be_default = 1,
408 .max_voices_out = INT_MAX,
409 .max_voices_in = 0,
410 .voice_size_out = sizeof (WaveVoiceOut),
411 .voice_size_in = 0