[Sumover-dev] [svn commit] r4114 - rat/trunk
sumover-dev at cs.ucl.ac.uk
sumover-dev at cs.ucl.ac.uk
Fri Dec 14 05:04:07 GMT 2007
Author: douglask
Date: Fri Dec 14 05:04:03 2007
New Revision: 4114
Modified:
rat/trunk/auddev_win32.c
Log:
Realtek HD audio support
Modified: rat/trunk/auddev_win32.c
==============================================================================
--- rat/trunk/auddev_win32.c (original)
+++ rat/trunk/auddev_win32.c Fri Dec 14 05:04:03 2007
@@ -6,6 +6,10 @@
* Assorted fixes and multilingual comments from Michael Wallbaum
* <wallbaum at informatik.rwth-aachen.de>
*
+ * Added support for sound devices that pose as seperate input and output
+ * mixers, like the Realtek HD on WinXP
+ * Douglas Kosovic <douglask at itee.uq.edu.au> sponsored by VPAC.org
+ *
* Copyright (c) 1995-2001 University College London
* All rights reserved.
*/
@@ -33,6 +37,13 @@
#include "util.h"
#include "mmsystem.h"
+#ifndef DRV_QUERYDEVICEINTERFACE
+#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12)
+#endif
+#ifndef DRV_QUERYDEVICEINTERFACESIZE
+#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
+#endif
+
#define MAX_DEVICE_GAIN 0xffff
#define rat_to_device(x) (((x) * MAX_DEVICE_GAIN / MAX_AMP) << 16 | ((x) * MAX_DEVICE_GAIN / MAX_AMP))
#define device_to_rat(x) ((x & 0xffff) * MAX_AMP / MAX_DEVICE_GAIN)
@@ -40,6 +51,7 @@
#define W32SDK_MAX_DEVICES 20
static int have_probed[W32SDK_MAX_DEVICES];
static int w32sdk_probe_formats(audio_desc_t ad);
+static UINT mixerMapInputToOutput[W32SDK_MAX_DEVICES];
static int error = 0;
static char errorText[MAXERRORLENGTH];
@@ -47,6 +59,7 @@
#define MAX_DEV_NAME 64
static UINT mapAudioDescToMixerID(audio_desc_t ad);
+static UINT mapInputMixIDToOutputMixerID(UINT uMix);
/* mcd_elem_t is a node used to store control state so
* we can restore mixer controls when device closes.
@@ -57,14 +70,16 @@
struct s_mcd_elem *next;
} mcd_elem_t;
-static mcd_elem_t *control_list;
+static mcd_elem_t *control_list_in;
+static mcd_elem_t *control_list_out;
#define MIX_ERR_LEN 32
#define MIX_MAX_CTLS 8
#define MIX_MAX_GAIN 100
static int32_t play_vol, rec_vol;
-static HMIXER hMixer;
+static HMIXER hMixerIn;
+static HMIXER hMixerOut;
static DWORD dwRecLineID, dwVolLineID;
@@ -72,6 +87,9 @@
static int n_input_ports, n_loop_ports;
static int iport; /* Current input port */
+static int nSuitableMixers = 0;
+static UINT *mixerIdMap;
+
/* Macro to convert macro name to string so we diagnose controls and error */
/* codes. */
#define CASE_STRING(x) case x: return #x
@@ -183,7 +201,7 @@
* config when we release the device. Lots of request for this
*/
-int
+static int
mcd_elem_add_control(mcd_elem_t **pplist, MIXERCONTROLDETAILS *pmcd)
{
mcd_elem_t *elem;
@@ -198,7 +216,7 @@
return FALSE;
}
-MIXERCONTROLDETAILS*
+static MIXERCONTROLDETAILS*
mcd_elem_get_control(mcd_elem_t **pplist)
{
MIXERCONTROLDETAILS *pmcd;
@@ -214,7 +232,7 @@
return NULL;
}
-void
+static void
mixRestoreControls(UINT uMix, mcd_elem_t **pplist)
{
MIXERCONTROLDETAILS *pmcd;
@@ -234,7 +252,7 @@
assert(*pplist == NULL);
}
-void
+static void
mixSaveLine(UINT uMix, MIXERLINE *pml, mcd_elem_t **pplist)
{
MIXERCONTROLDETAILS *pmcd;
@@ -300,7 +318,7 @@
}
-void
+static void
mixSaveControls(UINT uMix, mcd_elem_t **pplist)
{
MIXERLINE ml, sml;
@@ -357,7 +375,7 @@
* Returns TRUE if successful.
*/
-int mixGetInputInfo(UINT uMix, UINT *puWavIn, DWORD *pdwLineID)
+static int mixGetInputInfo(UINT uMix, UINT *puWavIn, DWORD *pdwLineID)
{
UINT i, nWavIn;
MIXERLINE ml;
@@ -403,7 +421,7 @@
* and corresponding destination line of mixer. Returns TRUE if
* successful.
*/
-int
+static int
mixGetOutputInfo(UINT uMix, UINT *puWavOut, DWORD *pdwLineID)
{
UINT i, nWavOut;
@@ -443,6 +461,102 @@
return FALSE;
}
+
+
+/* mixerPairInputMixerToOutputMixer -Some sound drivers appear as seperate input and output mixers,
+ * so pair up each input mixer to an output mixer for the same audio device
+ */
+static int
+mixerPairInputMixerToOutputMixer()
+{
+ UINT i, j;
+ UINT uWavIn, uWavOut;
+ UINT isOutputMixer;
+ UINT isInputMixer;
+ MMRESULT mmr;
+
+ DWORD devicePathSize;
+ LPWSTR devicePath;
+ LPWSTR pWstr;
+
+ LPWSTR *inputMixerDeviceInterfaces = (LPWSTR *)xmalloc(sizeof(LPWSTR) * mixerGetNumDevs());
+ LPWSTR *outputMixerDeviceInterfaces = (LPWSTR *)xmalloc(sizeof(LPWSTR) * mixerGetNumDevs());
+
+ for(i = 0; i < mixerGetNumDevs(); i++) {
+ mixerMapInputToOutput[i] = i;
+ inputMixerDeviceInterfaces[i] = NULL;
+ outputMixerDeviceInterfaces[i] = NULL;
+ isOutputMixer = 0;
+ isInputMixer = 0;
+
+ if (mixGetInputInfo(i, &uWavIn, &dwRecLineID) == TRUE) {
+ isInputMixer = 1;
+ }
+
+ if (mixGetOutputInfo(i, &uWavOut, &dwVolLineID) == TRUE) {
+ isOutputMixer = 1;
+ }
+
+ /* For only input or only output mixers, obtain the sound device interface string */
+ if (isInputMixer ^ isOutputMixer) {
+ mmr = mixerMessage(i, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&devicePathSize, 0);
+ if (mmr != MMSYSERR_NOERROR) {
+ debug_msg("mixerMessage: %s\n", mixGetErrorText(mmr));
+ continue;
+ }
+ devicePath = xmalloc(devicePathSize);
+
+ mmr = mixerMessage(i, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)devicePath, devicePathSize);
+ if (mmr != MMSYSERR_NOERROR) {
+ debug_msg("mixerMessage: %s\n", mixGetErrorText(mmr));
+ continue;
+ }
+ /* strip everything after the last slash ('\'), which might be unique for each mixer */
+ pWstr = wcsrchr(devicePath, '}');
+ if (pWstr && pWstr[1] == '\\') {
+ pWstr[1] = (WCHAR)NULL;
+ }
+ if (isInputMixer) {
+ inputMixerDeviceInterfaces[i] = devicePath;
+ } else {
+ outputMixerDeviceInterfaces[i] = devicePath;
+ }
+ }
+ }
+
+ for(i = 0; i < mixerGetNumDevs(); i++) {
+ if (inputMixerDeviceInterfaces[i] == NULL) {
+ continue;
+ }
+
+ for(j = 0; j < mixerGetNumDevs(); j++) {
+ if (outputMixerDeviceInterfaces[j] == NULL) {
+ continue;
+ }
+ if (i == j) {
+ continue;
+ }
+ if (wcscmp(inputMixerDeviceInterfaces[i], outputMixerDeviceInterfaces[j]) == 0) {
+ mixerMapInputToOutput[i] = j;
+ break;
+ }
+ }
+ }
+
+ for(i = 0; i < mixerGetNumDevs(); i++) {
+ if (inputMixerDeviceInterfaces[i] != NULL) {
+ xfree(inputMixerDeviceInterfaces[i]);
+ }
+ if (outputMixerDeviceInterfaces[i] != NULL) {
+ xfree(outputMixerDeviceInterfaces[i]);
+ }
+ }
+ xfree(inputMixerDeviceInterfaces);
+ xfree(outputMixerDeviceInterfaces);
+
+}
+
+
/* mixerEnableInputLine - enables the input line whose name starts with beginning of portname.
* We cannot just use the port index like we do for volume because the mute controls are
* not necessarily in the same order as the volume controls (grrr!). The only card
@@ -741,7 +855,7 @@
for(i = 0; i < mlt.cConnections; i++) {
memcpy(&mlc, &mlt, sizeof(mlc));
mlc.dwSource = i;
- mmr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_HMIXER);
+ mmr = mixerGetLineInfo((HMIXEROBJ)hMix, &mlc, MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_HMIXER);
if (mmr != MMSYSERR_NOERROR) {
xfree(papd);
return 0;
@@ -783,22 +897,32 @@
{
MIXERCAPS mc;
MMRESULT res;
+ UINT uMixerIn = uMixer;
+ UINT uMixerOut = mapInputMixIDToOutputMixerID(uMixerIn);
- if (hMixer) {mixerClose(hMixer); hMixer = 0;}
+ if (hMixerIn) {mixerClose(hMixerIn); hMixerIn = 0;}
+ if (hMixerOut) {mixerClose(hMixerOut); hMixerOut = 0;}
- res = mixerOpen(&hMixer, uMixer, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER);
+ if (uMixerIn != uMixerOut) {
+ res = mixerOpen(&hMixerOut, uMixerOut, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER);
+ if (res != MMSYSERR_NOERROR) {
+ debug_msg("mixerOpen failed: %s\n", mixGetErrorText(res));
+ return FALSE;
+ }
+ }
+ res = mixerOpen(&hMixerIn, uMixerIn, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER);
if (res != MMSYSERR_NOERROR) {
debug_msg("mixerOpen failed: %s\n", mixGetErrorText(res));
return FALSE;
}
- res = mixerGetDevCaps((UINT)hMixer, &mc, sizeof(mc));
+ res = mixerGetDevCaps((UINT)hMixerIn, &mc, sizeof(mc));
if (res != MMSYSERR_NOERROR) {
debug_msg("mixerGetDevCaps failed: %s\n", mixGetErrorText(res));
return FALSE;
}
- if (mc.cDestinations < 2) {
+ if (mc.cDestinations < 2 && uMixerIn == uMixerOut) {
debug_msg("mixer does not have 2 destinations?\n");
return FALSE;
}
@@ -809,7 +933,7 @@
n_input_ports = 0;
}
- n_input_ports = mixQueryControls((HMIXEROBJ)hMixer, dwRecLineID, &input_ports);
+ n_input_ports = mixQueryControls((HMIXEROBJ)hMixerIn, dwRecLineID, &input_ports);
debug_msg("Input ports %d\n", n_input_ports);
if (n_input_ports == 0) {
return FALSE;
@@ -823,7 +947,7 @@
n_loop_ports = 0;
}
- n_loop_ports = mixQueryControls((HMIXEROBJ)hMixer, dwVolLineID, &loop_ports);
+ n_loop_ports = mixQueryControls((HMIXEROBJ)hMixerOut, dwVolLineID, &loop_ports);
debug_msg("Loop ports %d\n", n_loop_ports);
if (n_loop_ports == 0) {
return 0;
@@ -1259,6 +1383,9 @@
static int virgin;
WAVEFORMATEX owfx, wfx;
UINT uWavIn, uWavOut;
+ UINT uMixIn = ad;
+ UINT uMixOut = mapInputMixIDToOutputMixerID(uMixIn);
+ OSVERSIONINFO osinfo;
if (audio_dev_open) {
debug_msg("Device not closed! Fix immediately");
@@ -1270,13 +1397,13 @@
return FALSE; /* Only support L16 for time being */
}
- if (mixGetInputInfo(ad, &uWavIn, &dwRecLineID) != TRUE) {
- debug_msg("Could not get wave in or mixer destination for mix %u\n", ad);
+ if (mixGetInputInfo(uMixIn, &uWavIn, &dwRecLineID) != TRUE) {
+ debug_msg("Could not get wave in or mixer destination for mix %u\n", uMixIn);
return FALSE;
}
- if (mixGetOutputInfo(ad, &uWavOut, &dwVolLineID) != TRUE) {
- debug_msg("Could not get wave out or mixer destination for mix %u\n", ad);
+ if (mixGetOutputInfo(uMixOut, &uWavOut, &dwVolLineID) != TRUE) {
+ debug_msg("Could not get wave out or mixer destination for mix %u\n", uMixOut);
return FALSE;
}
@@ -1284,7 +1411,10 @@
return FALSE; /* Could not secure mixer */
}
- mixSaveControls(ad, &control_list);
+ mixSaveControls(uMixIn, &control_list_in);
+ if (uMixIn != uMixOut) {
+ mixSaveControls(uMixOut, &control_list_out);
+ }
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD)fmt->channels;
@@ -1297,9 +1427,17 @@
memcpy(&owfx, &wfx, sizeof(wfx));
- /* Use 1/8 sec device buffer */
blksz = fmt->bytes_per_block;
- nblks = (wfx.nAvgBytesPerSec / blksz) / 8;
+
+ osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osinfo);
+ if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT && osinfo.dwMajorVersion >= 6) {
+ /* Use 1/5 sec device buffer on Vista (or later) */
+ nblks = (wfx.nAvgBytesPerSec / blksz) / 5;
+ } else {
+ /* Use 1/8 sec device buffer */
+ nblks = (wfx.nAvgBytesPerSec / blksz) / 8;
+ }
if (w32sdk_audio_open_in_probe(uWavIn, &wfx, probe) == FALSE){
debug_msg("Open input failed\n");
@@ -1334,7 +1472,7 @@
static int
w32sdk_audio_open_mixer(audio_desc_t ad, audio_format *fmt, audio_format *ofmt)
{
- return w32sdk_audio_open_mixer_probe(ad, fmt, ofmt, 0);
+ return w32sdk_audio_open_mixer_probe(ad, fmt, ofmt, 0);
}
int
@@ -1348,6 +1486,8 @@
w32sdk_audio_close_mixer(audio_desc_t ad)
{
MMRESULT mmr;
+ UINT uMixIn = ad;
+ UINT uMixOut = mapInputMixIDToOutputMixerID(uMixIn);
debug_msg("Closing input device.\n");
w32sdk_audio_close_in();
@@ -1365,10 +1505,21 @@
loop_ports = NULL;
}
- mixRestoreControls(ad, &control_list);
- mmr = mixerClose(hMixer); hMixer = 0;
- if (mmr != MMSYSERR_NOERROR) {
- debug_msg("mixerClose failed: %s\n", mixGetErrorText(mmr));
+ mixRestoreControls(uMixIn, &control_list_in);
+ if (uMixIn != uMixOut) {
+ mixRestoreControls(uMixOut, &control_list_out);
+ }
+ if (hMixerIn) {
+ mmr = mixerClose(hMixerIn); hMixerIn = 0;
+ if (mmr != MMSYSERR_NOERROR) {
+ debug_msg("mixerClose failed: %s\n", mixGetErrorText(mmr));
+ }
+ }
+ if (hMixerOut) {
+ mmr = mixerClose(hMixerOut); hMixerOut = 0;
+ if (mmr != MMSYSERR_NOERROR) {
+ debug_msg("mixerClose failed: %s\n", mixGetErrorText(mmr));
+ }
}
audio_dev_open = FALSE;
@@ -1499,21 +1650,21 @@
for(i = 0; i < n_input_ports; i++) {
if (input_ports[i].port == port) {
/* save gain */
- gain = mixerGetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port);
+ gain = mixerGetLineGain((HMIXEROBJ)hMixerIn, input_ports[iport].port);
debug_msg("w32sdk_audio_iport_set: %s Old Gain %d\n", input_ports[iport].name, gain);
debug_msg("w32sdk_audio_iport_set: %s New Gain %d\n", input_ports[i].name, gain);
- if (mixerGetLineName((HMIXEROBJ)hMixer, input_ports[i].port, portname, MIXER_LONG_NAME_CHARS)) {
- mixerEnableInputLine((HMIXEROBJ)hMixer, portname);
+ if (mixerGetLineName((HMIXEROBJ)hMixerIn, input_ports[i].port, portname, MIXER_LONG_NAME_CHARS)) {
+ mixerEnableInputLine((HMIXEROBJ)hMixerIn, portname);
}
- mixerSetLineGain((HMIXEROBJ)hMixer, input_ports[i].port, gain);
+ mixerSetLineGain((HMIXEROBJ)hMixerIn, input_ports[i].port, gain);
/* Do loopback */
for(j = 0; j < n_loop_ports && nLoopGain != 0; j++) {
if (strcmp(loop_ports[j].name, input_ports[i].name) == 0) {
- mixerEnableOutputLine((HMIXEROBJ)hMixer, loop_ports[j].port, 1);
+ mixerEnableOutputLine((HMIXEROBJ)hMixerOut, loop_ports[j].port, 1);
debug_msg("w32sdk_audio_iport_set: Enabling loop: %s Gain %d\n", loop_ports[j].name, 1);
- /* mixerSetLineGain((HMIXEROBJ)hMixer, loop_ports[j].port, nLoopGain); */
+ /* mixerSetLineGain((HMIXEROBJ)hMixerOut, loop_ports[j].port, nLoopGain); */
}
}
iport = i;
@@ -1551,7 +1702,7 @@
{
UNUSED(ad);
assert(iport >= 0 && iport < n_input_ports);
- mixerSetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port, level);
+ mixerSetLineGain((HMIXEROBJ)hMixerIn, input_ports[iport].port, level);
}
int
@@ -1559,7 +1710,7 @@
{
UNUSED(ad);
assert(iport >= 0 && iport < n_input_ports);
- return mixerGetLineGain((HMIXEROBJ)hMixer, input_ports[iport].port);
+ return mixerGetLineGain((HMIXEROBJ)hMixerIn, input_ports[iport].port);
}
/* Probing support */
@@ -1624,15 +1775,18 @@
return FALSE;
}
-static int nMixersWithFullDuplex = 0;
-static UINT *mixerIdMap;
-
static UINT
mapAudioDescToMixerID(audio_desc_t ad)
{
return mixerIdMap[ad];
}
+static UINT
+mapInputMixIDToOutputMixerID(UINT uMix)
+{
+ return mixerMapInputToOutput[uMix];
+}
+
int
w32sdk_audio_init(void)
{
@@ -1641,21 +1795,25 @@
mixerIdMap = (UINT*)xmalloc(sizeof(UINT) * mixerGetNumDevs());
+ for (i = 0; i < W32SDK_MAX_DEVICES; i++) {
+ mixerMapInputToOutput[i] = i;
+ }
+
af.bits_per_sample = 16;
af.bytes_per_block = 320;
af.channels = 1;
af.encoding = DEV_S16;
af.sample_rate = 8000;
+ mixerPairInputMixerToOutputMixer();
for(i = 0; i < mixerGetNumDevs(); i++) {
if (w32sdk_audio_open_mixer_probe(i, &af, &af, 1)) {
w32sdk_audio_close_mixer(i);
- mixerIdMap[nMixersWithFullDuplex] = i;
- nMixersWithFullDuplex++;
+ mixerIdMap[nSuitableMixers] = i;
+ nSuitableMixers++;
}
}
-
- return nMixersWithFullDuplex;
+ return nSuitableMixers;
}
int
@@ -1669,7 +1827,7 @@
w32sdk_get_device_count(void)
{
/* We are only interested in devices with mixers */
- return (int)nMixersWithFullDuplex;
+ return (int)nSuitableMixers;
}
static char tmpname[MAXPNAMELEN];
More information about the Sumover-dev
mailing list