1 ////////////////////////////////////////////////////////////////////////////////
4 //03/11/08 Joshua M. Kriegshauser
6 //Copyright (c) 2008 Sony Online Entertainment, LLC. All rights reserved.
7 ////////////////////////////////////////////////////////////////////////////////
14 // Disable the nameless struct warning.
15 #pragma warning(disable:4201)
17 #define WIN32_EXTRA_LEAN
18 #define WIN32_LEAN_AND_MEAN
24 #define VIVOX_TYPES_ONLY 1 // We're importing from DLL, so only need the types
26 #include "VxcRequests.h"
27 #include "VxcResponses.h"
28 #include "VxcEvents.h"
31 HMODULE shVivoxDll
= 0;
32 #define DECLARE_FN( ret, name, parms ) name##_type name = 0
33 DECLARE_FN(void,destroy_resp
,(vx_resp_base_t
*pCmd
));
34 DECLARE_FN(void,destroy_evt
,(vx_evt_base_t
*pCmd
));
35 DECLARE_FN(int,vx_get_message
,(vx_message_base_t
** message
));
36 DECLARE_FN(int,vx_issue_request
,(vx_req_base_t
* request
));
37 DECLARE_FN(char*,vx_strdup
,(const char*));
38 DECLARE_FN(void,vx_req_connector_initiate_shutdown_create
,(vx_req_connector_initiate_shutdown_t
** req
));
39 DECLARE_FN(void,vx_req_account_logout_create
,(vx_req_account_logout_t
** req
));
40 DECLARE_FN(void,vx_req_connector_create_create
,(vx_req_connector_create_t
** req
));
41 DECLARE_FN(void,vx_req_account_login_create
,(vx_req_account_login_t
** req
));
42 DECLARE_FN(void,vx_req_account_channel_add_moderator_create
,(vx_req_account_channel_add_moderator
** req
));
43 DECLARE_FN(void,vx_req_account_channel_remove_moderator_create
,(vx_req_account_channel_remove_moderator
** req
));
44 DECLARE_FN(void,vx_req_channel_ban_user_create
,(vx_req_channel_ban_user
** req
));
45 DECLARE_FN(void,vx_req_channel_kick_user_create
,(vx_req_channel_kick_user
** req
));
46 DECLARE_FN(void,vx_req_channel_mute_user_create
,(vx_req_channel_mute_user
** req
));
47 DECLARE_FN(void,vx_req_channel_mute_all_users_create
,(vx_req_channel_mute_all_users
** req
));
48 DECLARE_FN(void,vx_req_account_channel_update_create
,(vx_req_account_channel_update
** req
));
49 DECLARE_FN(void,vx_req_account_channel_get_moderators_create
,(vx_req_account_channel_get_moderators
** req
));
50 DECLARE_FN(void,vx_req_sessiongroup_create_create
,(vx_req_sessiongroup_create_t
** req
));
51 DECLARE_FN(void,vx_req_sessiongroup_add_session_create
,(vx_req_sessiongroup_add_session_t
** req
));
52 DECLARE_FN(void,vx_req_sessiongroup_remove_session_create
,(vx_req_sessiongroup_remove_session_t
** req
));
53 DECLARE_FN(void,vx_req_sessiongroup_terminate_create
,(vx_req_sessiongroup_terminate_t
** req
));
54 DECLARE_FN(void,vx_req_session_create_create
,(vx_req_session_create_t
** req
));
55 DECLARE_FN(void,vx_req_session_terminate_create
,(vx_req_session_terminate_t
** req
));
56 DECLARE_FN(void,vx_req_session_media_disconnect_create
,(vx_req_session_media_disconnect
** req
));
57 DECLARE_FN(void,vx_req_session_send_message_create
,(vx_req_session_send_message
** req
));
58 DECLARE_FN(void,vx_req_connector_mute_local_mic_create
,(vx_req_connector_mute_local_mic
** req
));
59 DECLARE_FN(void,vx_req_connector_mute_local_speaker_create
,(vx_req_connector_mute_local_speaker
** req
));
60 DECLARE_FN(void,vx_req_connector_set_local_mic_volume_create
,(vx_req_connector_set_local_mic_volume
** req
));
61 DECLARE_FN(void,vx_req_connector_set_local_speaker_volume_create
,(vx_req_connector_set_local_speaker_volume
** req
));
62 DECLARE_FN(void,vx_req_session_set_participant_mute_for_me_create
,(vx_req_session_set_participant_mute_for_me
** req
));
63 DECLARE_FN(void,vx_req_session_set_participant_volume_for_me_create
,(vx_req_session_set_participant_volume_for_me
** req
));
64 DECLARE_FN(void,vx_req_aux_get_render_devices_create
,(vx_req_aux_get_render_devices
** req
));
65 DECLARE_FN(void,vx_req_aux_set_render_device_create
,(vx_req_aux_set_render_device
** req
));
66 DECLARE_FN(void,vx_req_aux_get_capture_devices_create
,(vx_req_aux_get_capture_devices
** req
));
67 DECLARE_FN(void,vx_req_aux_set_capture_device_create
,(vx_req_aux_set_capture_device
** req
));
68 DECLARE_FN(void,vx_req_aux_start_buffer_capture_create
,(vx_req_aux_start_buffer_capture
** req
));
69 DECLARE_FN(void,vx_req_aux_play_audio_buffer_create
,(vx_req_aux_play_audio_buffer
** req
));
70 DECLARE_FN(void,vx_req_aux_render_audio_stop_create
,(vx_req_aux_render_audio_stop
** req
));
71 DECLARE_FN(void,vx_req_session_set_3d_position_create
,(vx_req_session_set_3d_position
** req
));
72 DECLARE_FN(void,vx_req_sessiongroup_set_tx_session_create
,(vx_req_sessiongroup_set_tx_session
** req
));
73 DECLARE_FN(void,vx_req_aux_global_monitor_keyboard_mouse_create
,(vx_req_aux_global_monitor_keyboard_mouse_t
** req
));
74 DECLARE_FN(void,vx_req_session_mute_local_speaker_create
,(vx_req_session_mute_local_speaker
** req
));
75 DECLARE_FN(void,vx_req_session_set_local_speaker_volume_create
,(vx_req_session_set_local_speaker_volume
** req
));
76 DECLARE_FN(void,vx_req_session_send_notification_create
,(vx_req_session_send_notification
** req
));
77 DECLARE_FN(void,vx_req_aux_capture_audio_start_create
,(vx_req_aux_capture_audio_start
** req
));
78 DECLARE_FN(void,vx_req_aux_capture_audio_stop_create
,(vx_req_aux_capture_audio_stop
** req
));
79 DECLARE_FN(void,vx_req_aux_set_mic_level_create
,(vx_req_aux_set_mic_level
** req
));
80 DECLARE_FN(void,vx_req_aux_set_speaker_level_create
,(vx_req_aux_set_speaker_level
** req
));
81 DECLARE_FN(void,vx_on_application_exit
,());
82 #if VIVOX_VERSION >= 3
83 DECLARE_FN(void,vx_req_aux_diagnostic_state_dump_create
,(vx_req_aux_diagnostic_state_dump
** req
));
84 DECLARE_FN(int, vx_alloc_sdk_handle
,(const char *address
, unsigned short port
, VX_SDK_HANDLE
*handle
));
85 DECLARE_FN(int, vx_free_sdk_handle
,(VX_SDK_HANDLE sdkHandle
));
89 static bool sLoadAttempted
= false;
94 // Unload appears to crash randomly in versions prior to 3, even if calling vx_on_application_exit()
95 #if VIVOX_VERSION >= 3
98 // Call onExit function if retrieved
99 if ( vx_on_application_exit
)
101 vx_on_application_exit();
104 sLoadAttempted
= false;
105 FreeLibrary( shVivoxDll
);
107 #define CLEAR_FN(name) name = 0
108 CLEAR_FN(destroy_resp
);
109 CLEAR_FN(destroy_evt
);
110 CLEAR_FN(vx_get_message
);
111 CLEAR_FN(vx_issue_request
);
113 CLEAR_FN(vx_req_connector_initiate_shutdown_create
);
114 CLEAR_FN(vx_req_account_logout_create
);
115 CLEAR_FN(vx_req_connector_create_create
);
116 CLEAR_FN(vx_req_account_login_create
);
117 CLEAR_FN(vx_req_account_channel_add_moderator_create
);
118 CLEAR_FN(vx_req_account_channel_remove_moderator_create
);
119 CLEAR_FN(vx_req_channel_ban_user_create
);
120 CLEAR_FN(vx_req_channel_kick_user_create
);
121 CLEAR_FN(vx_req_channel_mute_user_create
);
122 CLEAR_FN(vx_req_channel_mute_all_users_create
);
123 CLEAR_FN(vx_req_account_channel_update_create
);
124 CLEAR_FN(vx_req_account_channel_get_moderators_create
);
125 CLEAR_FN(vx_req_sessiongroup_create_create
);
126 CLEAR_FN(vx_req_sessiongroup_add_session_create
);
127 CLEAR_FN(vx_req_sessiongroup_remove_session_create
);
128 CLEAR_FN(vx_req_sessiongroup_terminate_create
);
129 CLEAR_FN(vx_req_session_create_create
);
130 CLEAR_FN(vx_req_session_terminate_create
);
131 CLEAR_FN(vx_req_session_media_disconnect_create
);
132 CLEAR_FN(vx_req_session_send_message_create
);
133 CLEAR_FN(vx_req_connector_mute_local_mic_create
);
134 CLEAR_FN(vx_req_connector_mute_local_speaker_create
);
135 CLEAR_FN(vx_req_connector_set_local_mic_volume_create
);
136 CLEAR_FN(vx_req_connector_set_local_speaker_volume_create
);
137 CLEAR_FN(vx_req_session_set_participant_mute_for_me_create
);
138 CLEAR_FN(vx_req_session_set_participant_volume_for_me_create
);
139 CLEAR_FN(vx_req_aux_get_render_devices_create
);
140 CLEAR_FN(vx_req_aux_set_render_device_create
);
141 CLEAR_FN(vx_req_aux_get_capture_devices_create
);
142 CLEAR_FN(vx_req_aux_set_capture_device_create
);
143 CLEAR_FN(vx_req_aux_start_buffer_capture_create
);
144 CLEAR_FN(vx_req_aux_play_audio_buffer_create
);
145 CLEAR_FN(vx_req_aux_render_audio_stop_create
);
146 CLEAR_FN(vx_req_session_set_3d_position_create
);
147 CLEAR_FN(vx_req_sessiongroup_set_tx_session_create
);
148 CLEAR_FN(vx_req_aux_global_monitor_keyboard_mouse_create
);
149 CLEAR_FN(vx_req_session_mute_local_speaker_create
);
150 CLEAR_FN(vx_req_session_set_local_speaker_volume_create
);
151 CLEAR_FN(vx_req_session_send_notification_create
);
152 CLEAR_FN(vx_on_application_exit
);
153 CLEAR_FN(vx_req_aux_capture_audio_start_create
);
154 CLEAR_FN(vx_req_aux_capture_audio_stop_create
);
155 CLEAR_FN(vx_req_aux_set_mic_level_create
);
156 CLEAR_FN(vx_req_aux_set_speaker_level_create
);
157 #if VIVOX_VERSION >= 3
158 CLEAR_FN(vx_req_aux_diagnostic_state_dump_create
);
159 CLEAR_FN(vx_alloc_sdk_handle
);
160 CLEAR_FN(vx_free_sdk_handle
);
168 sStartService( const char* sExe
, const char* /*sIP*/, int log_level
)
170 // If the management process is available, start it and connect to it.
171 HANDLE hFile
= ::CreateFile( sExe
, GENERIC_READ
, FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0 );
172 if ( hFile
!= INVALID_HANDLE_VALUE
)
174 // File exists, start the process and set the ENV variable
175 ::CloseHandle( hFile
);
177 STARTUPINFO startupInfo
;
178 memset( &startupInfo
, 0, sizeof(startupInfo
) );
179 startupInfo
.cb
= sizeof(STARTUPINFO
);
181 PROCESS_INFORMATION processInfo
;
183 // Command line options:
185 // -lf <folder> log folder
186 // -lp <prefix> prefix for log files
187 // -ls <suffix> suffix for log files
189 char commandLine
[ 1024 ];
190 int pos
= _snprintf( commandLine
, sizeof(commandLine
), "%s -lf logs -lp vvs -ls .log", sExe
);
194 pos
+= _snprintf( commandLine
+ pos
, sizeof(commandLine
) - pos
, " -ll %d", log_level
);
197 commandLine
[ pos
] = '\0';
199 if ( TRUE
== ::CreateProcess( 0, commandLine
, 0, 0, FALSE
, 0, 0, 0, &startupInfo
, &processInfo
) )
209 sLoadVivoxDLL( void (*onLoadFunc
)( void ), void (*onWarning
)( const char* file
, int line
, const char* pattern
, ... ) )
214 if ( sLoadAttempted
)
216 // Something is broken, don't try loading again
219 sLoadAttempted
= true;
221 shVivoxDll
= LoadLibraryA( "vivoxsdk.dll" );
222 if ( 0 == shVivoxDll
)
224 // alert( "Failed to load vivoxsdk.dll" );
229 #define IMPORT_FN(name) name = (name##_type)GetProcAddress( shVivoxDll, #name ); if ( 0 == name ) { onWarning( __FILE__, __LINE__, "Failed to import function: %s", #name ); sUnloadVivoxDLL(); return false; }
230 IMPORT_FN(vx_on_application_exit
); // Import application exit function first
231 IMPORT_FN(destroy_resp
);
232 IMPORT_FN(destroy_evt
);
233 IMPORT_FN(vx_get_message
);
234 IMPORT_FN(vx_issue_request
);
235 IMPORT_FN(vx_strdup
);
236 IMPORT_FN(vx_req_connector_initiate_shutdown_create
);
237 IMPORT_FN(vx_req_account_logout_create
);
238 IMPORT_FN(vx_req_connector_create_create
);
239 IMPORT_FN(vx_req_account_login_create
);
240 IMPORT_FN(vx_req_account_channel_add_moderator_create
);
241 IMPORT_FN(vx_req_account_channel_remove_moderator_create
);
242 IMPORT_FN(vx_req_channel_ban_user_create
);
243 IMPORT_FN(vx_req_channel_kick_user_create
);
244 IMPORT_FN(vx_req_channel_mute_user_create
);
245 IMPORT_FN(vx_req_channel_mute_all_users_create
);
246 IMPORT_FN(vx_req_account_channel_update_create
);
247 IMPORT_FN(vx_req_account_channel_get_moderators_create
);
248 IMPORT_FN(vx_req_sessiongroup_create_create
);
249 IMPORT_FN(vx_req_sessiongroup_add_session_create
);
250 IMPORT_FN(vx_req_sessiongroup_remove_session_create
);
251 IMPORT_FN(vx_req_sessiongroup_terminate_create
);
252 IMPORT_FN(vx_req_session_create_create
);
253 IMPORT_FN(vx_req_session_terminate_create
);
254 IMPORT_FN(vx_req_session_media_disconnect_create
);
255 IMPORT_FN(vx_req_session_send_message_create
);
256 IMPORT_FN(vx_req_connector_mute_local_mic_create
);
257 IMPORT_FN(vx_req_connector_mute_local_speaker_create
);
258 IMPORT_FN(vx_req_connector_set_local_mic_volume_create
);
259 IMPORT_FN(vx_req_connector_set_local_speaker_volume_create
);
260 IMPORT_FN(vx_req_session_set_participant_mute_for_me_create
);
261 IMPORT_FN(vx_req_session_set_participant_volume_for_me_create
);
262 IMPORT_FN(vx_req_aux_get_render_devices_create
);
263 IMPORT_FN(vx_req_aux_set_render_device_create
);
264 IMPORT_FN(vx_req_aux_get_capture_devices_create
);
265 IMPORT_FN(vx_req_aux_set_capture_device_create
);
266 IMPORT_FN(vx_req_aux_start_buffer_capture_create
);
267 IMPORT_FN(vx_req_aux_play_audio_buffer_create
);
268 IMPORT_FN(vx_req_aux_render_audio_stop_create
);
269 IMPORT_FN(vx_req_session_set_3d_position_create
);
270 IMPORT_FN(vx_req_sessiongroup_set_tx_session_create
);
271 IMPORT_FN(vx_req_aux_global_monitor_keyboard_mouse_create
);
272 IMPORT_FN(vx_req_session_mute_local_speaker_create
);
273 IMPORT_FN(vx_req_session_set_local_speaker_volume_create
);
274 IMPORT_FN(vx_req_session_send_notification_create
);
275 IMPORT_FN(vx_req_aux_capture_audio_start_create
);
276 IMPORT_FN(vx_req_aux_capture_audio_stop_create
);
277 IMPORT_FN(vx_req_aux_set_mic_level_create
);
278 IMPORT_FN(vx_req_aux_set_speaker_level_create
);
279 #if VIVOX_VERSION >= 3
280 IMPORT_FN(vx_req_aux_diagnostic_state_dump_create
);
281 IMPORT_FN(vx_alloc_sdk_handle
);
282 IMPORT_FN(vx_free_sdk_handle
);
286 // Alright, we just loaded the DLL, now do all of the initial state setup
294 sGetKeyState( int iKeyCode
)
296 // Swap mouse buttons if necessary (see docs for GetAsyncKeyState)
297 if ( ( iKeyCode
== VK_LBUTTON
|| iKeyCode
== VK_RBUTTON
) && GetSystemMetrics( SM_SWAPBUTTON
) == TRUE
)
299 if ( iKeyCode
== VK_LBUTTON
)
300 iKeyCode
= VK_RBUTTON
;
302 iKeyCode
= VK_LBUTTON
;
305 // For numeric keypad keys, verify that numlock is on
306 const bool kbNumeric
= ( iKeyCode
>= VK_NUMPAD0
&& iKeyCode
<= VK_NUMPAD9
);
309 SHORT s
= GetKeyState( VK_NUMLOCK
);
310 if ( ( s
& 0x0001 ) == 0 )
312 // If the numeric key is still 'on', force it to be off
313 s
= GetKeyState( iKeyCode
);
314 if ( ( s
& 0x8000 ) != 0 )
317 if ( GetKeyboardState( keys
) == TRUE
)
319 keys
[ iKeyCode
] = 0;
320 SetKeyboardState( keys
);
327 SHORT s
= kbNumeric
? GetKeyState( iKeyCode
) : GetAsyncKeyState( iKeyCode
);
328 bool b
= ( s
& 0x8000 ) != 0;
332 // Handle generic control/alt/shift
333 if ( iKeyCode
== VK_CONTROL
)
334 b
= ( ( GetAsyncKeyState( VK_LCONTROL
) | GetAsyncKeyState( VK_RCONTROL
) ) & 0x8000 ) != 0;
335 else if ( iKeyCode
== VK_MENU
)
336 b
= ( ( GetAsyncKeyState( VK_LMENU
) | GetAsyncKeyState( VK_RMENU
) ) & 0x8000 ) != 0;
337 else if ( iKeyCode
== VK_SHIFT
)
338 b
= ( ( GetAsyncKeyState( VK_LSHIFT
) | GetAsyncKeyState( VK_RSHIFT
) ) & 0x8000 ) != 0;
346 sCheckMic( const std::string
& sDevice
, bool bFix
/*=false*/ )
354 } sIsVista
= UNKNOWN
;
356 if ( UNKNOWN
== sIsVista
)
359 OSVERSIONINFOEX info
;
360 info
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
361 ::GetVersionEx( (OSVERSIONINFO
*)&info
);
362 const bool kbIsVista
= ( 6 == info
.dwMajorVersion
&&
363 0 == info
.dwMinorVersion
&&
364 VER_NT_WORKSTATION
== info
.wProductType
);
366 sIsVista
= kbIsVista
? IS_VISTA
: IS_NOT_VISTA
;
369 if ( IS_VISTA
== sIsVista
)
376 const UINT num
= mixerGetNumDevs();
379 for ( UINT uDev
= 0; uDev
!= num
; ++uDev
)
382 if ( mixerGetDevCaps( uDev
, &caps
, sizeof(caps
) ) != MMSYSERR_NOERROR
)
388 // Skip this device if it's not the one we're looking for
389 if ( !sDevice
.empty() && sDevice
!= caps
.szPname
)
395 if ( mixerOpen( &h
, uDev
, 0, 0, MIXER_OBJECTF_MIXER
) != MMSYSERR_NOERROR
)
401 // Temp object to close the mixer device when we go out of scope (or continue;)
406 MixerCloser( HMIXER
& h
) : m_h( h
) {}
407 ~MixerCloser() { mixerClose( m_h
); m_h
= 0; }
410 MixerCloser
& operator= (const MixerCloser
&) { return *this; }
413 MIXERLINE lineWaveIn
;
414 lineWaveIn
.cbStruct
= sizeof(lineWaveIn
);
415 lineWaveIn
.dwComponentType
= MIXERLINE_COMPONENTTYPE_DST_WAVEIN
;
417 if ( mixerGetLineInfo( (HMIXEROBJ
)h
, &lineWaveIn
, MIXER_GETLINEINFOF_COMPONENTTYPE
) != MMSYSERR_NOERROR
)
423 DWORD dwDesiredLineID
= ~0U;
425 // Check the Wave In mixer device for Mute, Volume and MUX controls
426 if ( lineWaveIn
.cControls
!= 0 )
428 // Find the Mute All control (if it exists)
430 MIXERLINECONTROLS mxlc
;
431 memset( &mxlc
, 0, sizeof(mxlc
) );
432 mxlc
.cbStruct
= sizeof(mxlc
);
433 mxlc
.cbmxctrl
= sizeof(mxc
);
435 mxlc
.pamxctrl
= &mxc
;
436 mxlc
.dwLineID
= lineWaveIn
.dwLineID
;
437 mxlc
.dwControlType
= MIXERCONTROL_CONTROLTYPE_MUTE
;
438 if ( mixerGetLineControls( (HMIXEROBJ
)h
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE
) == MMSYSERR_NOERROR
)
440 // Found a Mute control. Query it and set it if necessary.
441 MIXERCONTROLDETAILS_BOOLEAN mxcdBool
;
442 MIXERCONTROLDETAILS mxcd
;
443 mxcd
.cbStruct
= sizeof(mxcd
);
444 mxcd
.dwControlID
= mxc
.dwControlID
;
446 mxcd
.cMultipleItems
= 0;
447 mxcd
.cbDetails
= sizeof(MIXERCONTROLDETAILS_BOOLEAN
);
448 mxcd
.paDetails
= &mxcdBool
;
449 if ( mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE
) == MMSYSERR_NOERROR
)
451 if ( mxcdBool
.fValue
== TRUE
)
456 mxcdBool
.fValue
= FALSE
;
457 if ( mixerSetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE
) != MMSYSERR_NOERROR
)
470 // Find the volume control (if it exists)
471 mxlc
.dwControlType
= MIXERCONTROL_CONTROLTYPE_VOLUME
;
472 if ( mixerGetLineControls( (HMIXEROBJ
)h
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE
) == MMSYSERR_NOERROR
)
474 // Found a Volume control. Query it and set it if necessary.
475 MIXERCONTROLDETAILS_UNSIGNED mxcdUns
;
476 MIXERCONTROLDETAILS mxcd
;
477 mxcd
.cbStruct
= sizeof(mxcd
);
478 mxcd
.dwControlID
= mxc
.dwControlID
;
480 mxcd
.cMultipleItems
= 0;
481 mxcd
.cbDetails
= sizeof(MIXERCONTROLDETAILS_UNSIGNED
);
482 mxcd
.paDetails
= &mxcdUns
;
483 if ( mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE
) == MMSYSERR_NOERROR
)
485 const float kfRange
= static_cast< float >( mxc
.Bounds
.dwMaximum
- mxc
.Bounds
.dwMinimum
);
486 DWORD desired
= static_cast< DWORD
>( 0.5f
* kfRange
) + mxc
.Bounds
.dwMinimum
;
488 if ( mxcdUns
.dwValue
< desired
)
490 retval
|= VCM_VOLUME_TOO_LOW
;
493 mxcdUns
.dwValue
= desired
;
494 if ( mixerSetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE
) != MMSYSERR_NOERROR
)
507 // Find the MUX control and determine if we have more than one device
508 mxlc
.dwControlType
= MIXERCONTROL_CONTROLTYPE_MUX
;
509 if ( mixerGetLineControls( (HMIXEROBJ
)h
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE
) == MMSYSERR_NOERROR
&&
510 mxc
.cMultipleItems
> 1 )
512 // Got a MUX control, now see what it's set to. We need to get the list because the MUX items
513 // might be sorted differently than the connections
515 std::vector
< MIXERCONTROLDETAILS_LISTTEXT
> aList( mxc
.cMultipleItems
);
516 MIXERCONTROLDETAILS mxcdList
;
517 mxcdList
.cbStruct
= sizeof(mxcdList
);
518 mxcdList
.dwControlID
= mxc
.dwControlID
;
519 mxcdList
.cChannels
= 1;
520 mxcdList
.cMultipleItems
= mxc
.cMultipleItems
;
521 mxcdList
.cbDetails
= sizeof(MIXERCONTROLDETAILS_LISTTEXT
);
522 mxcdList
.paDetails
= &aList
[ 0 ];
524 std::vector
< MIXERCONTROLDETAILS_BOOLEAN
> aBool( mxc
.cMultipleItems
);
525 MIXERCONTROLDETAILS mxcdBool
;
526 mxcdBool
.cbStruct
= sizeof(mxcdBool
);
527 mxcdBool
.dwControlID
= mxc
.dwControlID
;
528 mxcdBool
.cChannels
= 1;
529 mxcdBool
.cMultipleItems
= mxc
.cMultipleItems
;
530 mxcdBool
.cbDetails
= sizeof(MIXERCONTROLDETAILS_BOOLEAN
);
531 mxcdBool
.paDetails
= &aBool
[ 0 ];
533 if ( mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcdList
, MIXER_GETCONTROLDETAILSF_LISTTEXT
) == MMSYSERR_NOERROR
&&
534 mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcdBool
, MIXER_GETCONTROLDETAILSF_VALUE
) == MMSYSERR_NOERROR
)
536 // Whew, got all the control details we need for the MUX. See if it's set to the right value.
537 // We'll also change the values here, but we only send them back to the API if we're told to fix.
539 // We also must handle multiple microphones, as some devices have separate front/rear mics
541 // Loop through once to see if a mic is already selected
542 for ( unsigned int iVal
= 0; iVal
!= mxc
.cMultipleItems
; ++iVal
)
544 if ( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
== aList
[ iVal
].dwParam2
&&
545 aBool
[ iVal
].fValue
== TRUE
)
547 // Found a mic that was selected
548 dwDesiredLineID
= aList
[ iVal
].dwParam1
;
553 // If we don't have a desired mic, take the first one that is connected
554 if ( ~0U == dwDesiredLineID
)
556 for ( unsigned int iVal
= 0; iVal
!= mxc
.cMultipleItems
; ++iVal
)
558 if ( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
== aList
[ iVal
].dwParam2
)
561 line
.cbStruct
= sizeof(line
);
562 line
.dwLineID
= aList
[ iVal
].dwParam1
;
563 if ( mixerGetLineInfo( (HMIXEROBJ
)h
, &line
, MIXER_GETLINEINFOF_LINEID
) != MMSYSERR_NOERROR
)
569 if ( ( line
.fdwLine
& MIXERLINE_LINEF_DISCONNECTED
) == 0 )
571 // This line appears to be connected (if the line even supports notification about that)
573 dwDesiredLineID
= aList
[ iVal
].dwParam1
;
580 for ( unsigned int iVal
= 0; iVal
!= mxc
.cMultipleItems
; ++iVal
)
582 if ( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
== aList
[ iVal
].dwParam2
)
584 // Select this mic as the desired mic if we don't already have one
585 if ( dwDesiredLineID
== ~0U )
587 dwDesiredLineID
= aList
[ iVal
].dwParam1
;
590 // If this is the desired mic, make sure it's turned on
591 if ( dwDesiredLineID
== aList
[ iVal
].dwParam1
)
593 if ( aBool
[ iVal
].fValue
!= TRUE
)
594 retval
|= VCM_NOT_SELECTED
;
595 aBool
[ iVal
].fValue
= TRUE
;
599 // Not desired mic, make sure it's turned off
600 aBool
[ iVal
].fValue
= FALSE
;
605 // Set everything other than the mic to false
606 aBool
[ iVal
].fValue
= FALSE
;
612 // If told to fix but no desired mic was found, show as an error.
613 if ( dwDesiredLineID
== ~0U || mixerSetControlDetails( (HMIXEROBJ
)h
, &mxcdBool
, MIXER_SETCONTROLDETAILSF_VALUE
) != MMSYSERR_NOERROR
)
624 // Now find the Microphone connection and check it for Mic-specific Volume and Mute controls
625 for ( unsigned int iCon
= 0; iCon
!= lineWaveIn
.cConnections
; ++iCon
)
627 MIXERLINE line
= lineWaveIn
;
628 line
.dwSource
= iCon
;
630 if ( mixerGetLineInfo( (HMIXEROBJ
)h
, &line
, MIXER_GETLINEINFOF_SOURCE
) != MMSYSERR_NOERROR
)
636 if ( MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
!= line
.dwComponentType
)
639 // Only care about our desired line ID (if we have a desired line ID)
640 if ( dwDesiredLineID
!= ~0U && line
.dwLineID
!= dwDesiredLineID
)
643 if ( line
.fdwLine
& MIXERLINE_LINEF_DISCONNECTED
)
645 retval
|= VCM_DISCONNECTED
;
646 // This situation can't be fixed in code (at least... I don't think so)
649 if ( 0 == line
.cControls
)
652 // Find the Mute control (if it exists)
654 MIXERLINECONTROLS mxlc
;
655 memset( &mxlc
, 0, sizeof(mxlc
) );
656 mxlc
.cbStruct
= sizeof(mxlc
);
657 mxlc
.cbmxctrl
= sizeof(mxc
);
659 mxlc
.pamxctrl
= &mxc
;
660 mxlc
.dwLineID
= line
.dwLineID
;
661 mxlc
.dwControlType
= MIXERCONTROL_CONTROLTYPE_MUTE
;
662 if ( mixerGetLineControls( (HMIXEROBJ
)h
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE
) == MMSYSERR_NOERROR
)
664 // Found a Mute control. Query it and set it if necessary.
665 MIXERCONTROLDETAILS_BOOLEAN mxcdBool
;
666 MIXERCONTROLDETAILS mxcd
;
667 mxcd
.cbStruct
= sizeof(mxcd
);
668 mxcd
.dwControlID
= mxc
.dwControlID
;
670 mxcd
.cMultipleItems
= 0;
671 mxcd
.cbDetails
= sizeof(MIXERCONTROLDETAILS_BOOLEAN
);
672 mxcd
.paDetails
= &mxcdBool
;
673 if ( mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE
) == MMSYSERR_NOERROR
)
675 if ( mxcdBool
.fValue
== TRUE
)
680 mxcdBool
.fValue
= FALSE
;
681 if ( mixerSetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE
) != MMSYSERR_NOERROR
)
694 // Find the volume control (if it exists)
695 mxlc
.dwControlType
= MIXERCONTROL_CONTROLTYPE_VOLUME
;
696 if ( mixerGetLineControls( (HMIXEROBJ
)h
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE
) == MMSYSERR_NOERROR
)
698 // Found a Volume control. Query it and set it if necessary.
699 MIXERCONTROLDETAILS_UNSIGNED mxcdUns
;
700 MIXERCONTROLDETAILS mxcd
;
701 mxcd
.cbStruct
= sizeof(mxcd
);
702 mxcd
.dwControlID
= mxc
.dwControlID
;
704 mxcd
.cMultipleItems
= 0;
705 mxcd
.cbDetails
= sizeof(MIXERCONTROLDETAILS_UNSIGNED
);
706 mxcd
.paDetails
= &mxcdUns
;
707 if ( mixerGetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE
) == MMSYSERR_NOERROR
)
709 const float kfRange
= static_cast< float >( mxc
.Bounds
.dwMaximum
- mxc
.Bounds
.dwMinimum
);
710 DWORD desired
= static_cast< DWORD
>( 0.5f
* kfRange
) + mxc
.Bounds
.dwMinimum
;
712 if ( mxcdUns
.dwValue
< desired
)
714 retval
|= VCM_VOLUME_TOO_LOW
;
717 mxcdUns
.dwValue
= desired
;
718 if ( mixerSetControlDetails( (HMIXEROBJ
)h
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE
) != MMSYSERR_NOERROR
)
736 return (VivoxCheckMic
)retval
;
739 static HANDLE shVivoxMutex
= 0;
742 sGrabVivoxSystemMutex()
744 #if VIVOX_VERSION < 3
751 // Create/Open the named mutex
752 shVivoxMutex
= ::CreateMutex( 0, TRUE
, "{4355ce47-39f2-4f52-bd0e-f6e609b20f82}" );
753 if ( 0 == shVivoxMutex
)
756 if ( ERROR_ALREADY_EXISTS
== ::GetLastError() )
758 // Ok, it exists, but we weren't granted ownership
759 if ( WAIT_OBJECT_0
!= ::WaitForSingleObject( shVivoxMutex
, 0 ) )
761 // Failed to grab it, just release for now
762 ::CloseHandle( shVivoxMutex
);
773 sReleaseVivoxSystemMutex()
775 #if VIVOX_VERSION < 3
778 ::ReleaseMutex( shVivoxMutex
);
779 ::CloseHandle( shVivoxMutex
);