| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU DirectSound audio driver header | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2005 Vassili Karpov (malc) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  | #define NAME "capture buffer"
 | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  | #define NAME2 "DirectSoundCapture"
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #define TYPE in
 | 
					
						
							|  |  |  | #define IFACE IDirectSoundCaptureBuffer
 | 
					
						
							|  |  |  | #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
 | 
					
						
							|  |  |  | #define FIELD dsound_capture_buffer
 | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  | #define FIELD2 dsound_capture
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #define NAME "playback buffer"
 | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  | #define NAME2 "DirectSound"
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #define TYPE out
 | 
					
						
							|  |  |  | #define IFACE IDirectSoundBuffer
 | 
					
						
							|  |  |  | #define BUFPTR LPDIRECTSOUNDBUFFER
 | 
					
						
							|  |  |  | #define FIELD dsound_buffer
 | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  | #define FIELD2 dsound
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int glue (dsound_unlock_, TYPE) ( | 
					
						
							|  |  |  |     BUFPTR buf, | 
					
						
							|  |  |  |     LPVOID p1, | 
					
						
							|  |  |  |     LPVOID p2, | 
					
						
							|  |  |  |     DWORD blen1, | 
					
						
							|  |  |  |     DWORD blen2 | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HRESULT hr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); | 
					
						
							|  |  |  |     if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |         dsound_logerr (hr, "Could not unlock " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int glue (dsound_lock_, TYPE) ( | 
					
						
							|  |  |  |     BUFPTR buf, | 
					
						
							|  |  |  |     struct audio_pcm_info *info, | 
					
						
							|  |  |  |     DWORD pos, | 
					
						
							|  |  |  |     DWORD len, | 
					
						
							|  |  |  |     LPVOID *p1p, | 
					
						
							|  |  |  |     LPVOID *p2p, | 
					
						
							|  |  |  |     DWORD *blen1p, | 
					
						
							|  |  |  |     DWORD *blen2p, | 
					
						
							|  |  |  |     int entire | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HRESULT hr; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     LPVOID p1 = NULL, p2 = NULL; | 
					
						
							|  |  |  |     DWORD blen1 = 0, blen2 = 0; | 
					
						
							| 
									
										
										
										
											2006-07-04 16:51:32 +00:00
										 |  |  |     DWORD flag; | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-04 16:51:32 +00:00
										 |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  |     flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     flag = entire ? DSBLOCK_ENTIREBUFFER : 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |     for (i = 0; i < conf.lock_retries; ++i) { | 
					
						
							|  |  |  |         hr = glue (IFACE, _Lock) ( | 
					
						
							|  |  |  |             buf, | 
					
						
							|  |  |  |             pos, | 
					
						
							|  |  |  |             len, | 
					
						
							|  |  |  |             &p1, | 
					
						
							|  |  |  |             &blen1, | 
					
						
							|  |  |  |             &p2, | 
					
						
							|  |  |  |             &blen2, | 
					
						
							| 
									
										
										
										
											2006-07-04 16:51:32 +00:00
										 |  |  |             flag | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (FAILED (hr)) { | 
					
						
							|  |  |  | #ifndef DSBTYPE_IN
 | 
					
						
							|  |  |  |             if (hr == DSERR_BUFFERLOST) { | 
					
						
							|  |  |  |                 if (glue (dsound_restore_, TYPE) (buf)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |                     dsound_logerr (hr, "Could not lock " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |                     goto fail; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |             dsound_logerr (hr, "Could not lock " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (i == conf.lock_retries) { | 
					
						
							|  |  |  |         dolog ("%d attempts to lock " NAME " failed\n", i); | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { | 
					
						
							|  |  |  |         dolog ("DirectSound returned misaligned buffer %ld %ld\n", | 
					
						
							|  |  |  |                blen1, blen2); | 
					
						
							|  |  |  |         glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!p1 && blen1) { | 
					
						
							|  |  |  |         dolog ("warning: !p1 && blen1=%ld\n", blen1); | 
					
						
							|  |  |  |         blen1 = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!p2 && blen2) { | 
					
						
							|  |  |  |         dolog ("warning: !p2 && blen2=%ld\n", blen2); | 
					
						
							|  |  |  |         blen2 = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *p1p = p1; | 
					
						
							|  |  |  |     *p2p = p2; | 
					
						
							|  |  |  |     *blen1p = blen1; | 
					
						
							|  |  |  |     *blen2p = blen2; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     *p1p = NULL - 1; | 
					
						
							|  |  |  |     *p2p = NULL - 1; | 
					
						
							|  |  |  |     *blen1p = -1; | 
					
						
							|  |  |  |     *blen2p = -1; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  | static void dsound_fini_in (HWVoiceIn *hw) | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static void dsound_fini_out (HWVoiceOut *hw) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HRESULT hr; | 
					
						
							|  |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  |     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ds->FIELD) { | 
					
						
							|  |  |  |         hr = glue (IFACE, _Stop) (ds->FIELD); | 
					
						
							|  |  |  |         if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |             dsound_logerr (hr, "Could not stop " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = glue (IFACE, _Release) (ds->FIELD); | 
					
						
							|  |  |  |         if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |             dsound_logerr (hr, "Could not release " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         ds->FIELD = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							| 
									
										
										
										
											2008-12-03 22:48:44 +00:00
										 |  |  | static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as) | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2008-12-03 22:48:44 +00:00
										 |  |  | static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as) | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int err; | 
					
						
							|  |  |  |     HRESULT hr; | 
					
						
							|  |  |  |     dsound *s = &glob_dsound; | 
					
						
							|  |  |  |     WAVEFORMATEX wfx; | 
					
						
							| 
									
										
										
										
											2008-12-03 22:48:44 +00:00
										 |  |  |     struct audsettings obt_as; | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  |     const char *typ = "ADC"; | 
					
						
							|  |  |  |     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; | 
					
						
							|  |  |  |     DSCBUFFERDESC bd; | 
					
						
							|  |  |  |     DSCBCAPS bc; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     const char *typ = "DAC"; | 
					
						
							|  |  |  |     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; | 
					
						
							|  |  |  |     DSBUFFERDESC bd; | 
					
						
							|  |  |  |     DSBCAPS bc; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  |     if (!s->FIELD2) { | 
					
						
							| 
									
										
										
										
											2008-01-17 21:47:25 +00:00
										 |  |  |         dolog ("Attempt to initialize voice without " NAME2 " object\n"); | 
					
						
							| 
									
										
										
										
											2008-01-14 04:24:29 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |     err = waveformat_from_audio_settings (&wfx, as); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |     if (err) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memset (&bd, 0, sizeof (bd)); | 
					
						
							|  |  |  |     bd.dwSize = sizeof (bd); | 
					
						
							|  |  |  |     bd.lpwfxFormat = &wfx; | 
					
						
							|  |  |  | #ifdef DSBTYPE_IN
 | 
					
						
							|  |  |  |     bd.dwBufferBytes = conf.bufsize_in; | 
					
						
							|  |  |  |     hr = IDirectSoundCapture_CreateCaptureBuffer ( | 
					
						
							|  |  |  |         s->dsound_capture, | 
					
						
							|  |  |  |         &bd, | 
					
						
							|  |  |  |         &ds->dsound_capture_buffer, | 
					
						
							|  |  |  |         NULL | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; | 
					
						
							|  |  |  |     bd.dwBufferBytes = conf.bufsize_out; | 
					
						
							|  |  |  |     hr = IDirectSound_CreateSoundBuffer ( | 
					
						
							|  |  |  |         s->dsound, | 
					
						
							|  |  |  |         &bd, | 
					
						
							|  |  |  |         &ds->dsound_buffer, | 
					
						
							|  |  |  |         NULL | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |         dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |     if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         goto fail0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef DEBUG_DSOUND
 | 
					
						
							|  |  |  |     dolog (NAME "\n"); | 
					
						
							|  |  |  |     print_wave_format (&wfx); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memset (&bc, 0, sizeof (bc)); | 
					
						
							|  |  |  |     bc.dwSize = sizeof (bc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); | 
					
						
							|  |  |  |     if (FAILED (hr)) { | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |         goto fail0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |     err = waveformat_to_audio_settings (&wfx, &obt_as); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  |     if (err) { | 
					
						
							|  |  |  |         goto fail0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ds->first_time = 1; | 
					
						
							| 
									
										
										
										
											2006-07-04 21:47:22 +00:00
										 |  |  |     obt_as.endianness = 0; | 
					
						
							|  |  |  |     audio_pcm_init_info (&hw->info, &obt_as); | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (bc.dwBufferBytes & hw->info.align) { | 
					
						
							|  |  |  |         dolog ( | 
					
						
							|  |  |  |             "GetCaps returned misaligned buffer size %ld, alignment %d\n", | 
					
						
							|  |  |  |             bc.dwBufferBytes, hw->info.align + 1 | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     hw->samples = bc.dwBufferBytes >> hw->info.shift; | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef DEBUG_DSOUND
 | 
					
						
							|  |  |  |     dolog ("caps %ld, desc %ld\n", | 
					
						
							|  |  |  |            bc.dwBufferBytes, bd.dwBufferBytes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", | 
					
						
							| 
									
										
										
										
											2005-11-05 18:55:28 +00:00
										 |  |  |            hw->bufsize, settings.freq, settings.nchannels, settings.fmt); | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail0: | 
					
						
							|  |  |  |     glue (dsound_fini_, TYPE) (hw); | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef NAME
 | 
					
						
							| 
									
										
										
										
											2009-01-22 22:09:55 +00:00
										 |  |  | #undef NAME2
 | 
					
						
							| 
									
										
										
										
											2005-10-30 18:58:22 +00:00
										 |  |  | #undef TYPE
 | 
					
						
							|  |  |  | #undef IFACE
 | 
					
						
							|  |  |  | #undef BUFPTR
 | 
					
						
							|  |  |  | #undef FIELD
 | 
					
						
							| 
									
										
										
										
											2009-01-22 22:09:55 +00:00
										 |  |  | #undef FIELD2
 |