00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <WindowsAudioInputDevice_mixer.hh>
00022
00024
00025 class AudioInputPort {
00026 public:
00027 int tag;
00028 DWORD dwComponentType;
00029 char name[MIXER_LONG_NAME_CHARS];
00030 };
00031
00032 class Mixer {
00033 public:
00034 Mixer();
00035 virtual ~Mixer();
00036
00037 void open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS);
00038 void open();
00039 void getPortsInfo();
00040 Boolean enableInputPort(unsigned portIndex, char const*& errReason, MMRESULT& errCode);
00041 void close();
00042
00043 unsigned index;
00044 HMIXER hMixer;
00045 DWORD dwRecLineID;
00046 unsigned numPorts;
00047 AudioInputPort* ports;
00048 char name[MAXPNAMELEN];
00049 };
00050
00051
00053
00054 AudioInputDevice*
00055 AudioInputDevice::createNew(UsageEnvironment& env, int inputPortNumber,
00056 unsigned char bitsPerSample,
00057 unsigned char numChannels,
00058 unsigned samplingFrequency,
00059 unsigned granularityInMS) {
00060 Boolean success;
00061 WindowsAudioInputDevice* newSource
00062 = new WindowsAudioInputDevice(env, inputPortNumber,
00063 bitsPerSample, numChannels,
00064 samplingFrequency, granularityInMS,
00065 success);
00066 if (!success) {delete newSource; newSource = NULL;}
00067
00068 return newSource;
00069 }
00070
00071 AudioPortNames* AudioInputDevice::getPortNames() {
00072 WindowsAudioInputDevice::initializeIfNecessary();
00073
00074 AudioPortNames* portNames = new AudioPortNames;
00075 portNames->numPorts = WindowsAudioInputDevice::numInputPortsTotal;
00076 portNames->portName = new char*[WindowsAudioInputDevice::numInputPortsTotal];
00077
00078
00079
00080
00081 char portNameBuffer[2*MAXPNAMELEN+10];
00082 char mixerNameBuffer[MAXPNAMELEN];
00083 char const* portNameFmt;
00084 if (WindowsAudioInputDevice::numMixers <= 1) {
00085 portNameFmt = "%s";
00086 } else {
00087 portNameFmt = "%s (%s)";
00088 }
00089
00090 unsigned curPortNum = 0;
00091 for (unsigned i = 0; i < WindowsAudioInputDevice::numMixers; ++i) {
00092 Mixer& mixer = WindowsAudioInputDevice::ourMixers[i];
00093
00094 if (WindowsAudioInputDevice::numMixers <= 1) {
00095 mixerNameBuffer[0] = '\0';
00096 } else {
00097 strncpy(mixerNameBuffer, mixer.name, sizeof mixerNameBuffer);
00098 #if 0
00099
00100 for (int k = 0; k < sizeof mixerNameBuffer && mixerNameBuffer[k] != '\0'; ++k) {
00101 if (mixerNameBuffer[k] == ' ') {
00102 mixerNameBuffer[k] = '\0';
00103 break;
00104 }
00105 }
00106 #endif
00107 }
00108
00109 for (unsigned j = 0; j < mixer.numPorts; ++j) {
00110 sprintf(portNameBuffer, portNameFmt, mixer.ports[j].name, mixerNameBuffer);
00111 portNames->portName[curPortNum++] = strDup(portNameBuffer);
00112 }
00113 }
00114
00115 return portNames;
00116 }
00117
00118
00120
00121 WindowsAudioInputDevice
00122 ::WindowsAudioInputDevice(UsageEnvironment& env, int inputPortNumber,
00123 unsigned char bitsPerSample,
00124 unsigned char numChannels,
00125 unsigned samplingFrequency,
00126 unsigned granularityInMS,
00127 Boolean& success)
00128 : WindowsAudioInputDevice_common(env, inputPortNumber,
00129 bitsPerSample, numChannels, samplingFrequency, granularityInMS),
00130 fCurMixerId(-1) {
00131 success = initialSetInputPort(inputPortNumber);
00132 }
00133
00134 WindowsAudioInputDevice::~WindowsAudioInputDevice() {
00135 if (fCurMixerId >= 0) ourMixers[fCurMixerId].close();
00136
00137 delete[] ourMixers; ourMixers = NULL;
00138 numMixers = numInputPortsTotal = 0;
00139 }
00140
00141 void WindowsAudioInputDevice::initializeIfNecessary() {
00142 if (ourMixers != NULL) return;
00143 numMixers = mixerGetNumDevs();
00144 ourMixers = new Mixer[numMixers];
00145
00146
00147 numInputPortsTotal = 0;
00148 for (unsigned i = 0; i < numMixers; ++i) {
00149 Mixer& mixer = ourMixers[i];
00150 mixer.index = i;
00151 mixer.open();
00152 if (mixer.hMixer != NULL) {
00153
00154 mixer.getPortsInfo();
00155 mixer.close();
00156
00157 if (mixer.numPorts == 0) continue;
00158
00159 numInputPortsTotal += mixer.numPorts;
00160 } else {
00161 mixer.ports = NULL;
00162 mixer.numPorts = 0;
00163 }
00164 }
00165 }
00166
00167 Boolean WindowsAudioInputDevice::setInputPort(int portIndex) {
00168 initializeIfNecessary();
00169
00170 if (portIndex < 0 || portIndex >= (int)numInputPortsTotal) {
00171 envir().setResultMsg("Bad input port index\n");
00172 return False;
00173 }
00174
00175
00176 int newMixerId, portWithinMixer, portIndexCount = 0;
00177 for (newMixerId = 0; newMixerId < (int)numMixers; ++newMixerId) {
00178 int prevPortIndexCount = portIndexCount;
00179 portIndexCount += ourMixers[newMixerId].numPorts;
00180 if (portIndexCount > portIndex) {
00181 portWithinMixer = portIndex - prevPortIndexCount;
00182 break;
00183 }
00184 }
00185
00186
00187 if (allowedDeviceNames != NULL) {
00188 int i;
00189 for (i = 0; allowedDeviceNames[i] != NULL; ++i) {
00190 if (strncmp(ourMixers[newMixerId].name, allowedDeviceNames[i],
00191 strlen(allowedDeviceNames[i])) == 0) {
00192
00193 break;
00194 }
00195 }
00196 if (allowedDeviceNames[i] == NULL) {
00197 envir().setResultMsg("Access to this audio device is not allowed\n");
00198 return False;
00199 }
00200 }
00201
00202 if (newMixerId != fCurMixerId) {
00203
00204 if (fCurMixerId >= 0) ourMixers[fCurMixerId].close();
00205 fCurMixerId = newMixerId;
00206 ourMixers[fCurMixerId].open(fNumChannels, fSamplingFrequency, fGranularityInMS);
00207 }
00208 if (portIndex != fCurPortIndex) {
00209
00210 fCurPortIndex = portIndex;
00211 char const* errReason;
00212 MMRESULT errCode;
00213 if (!ourMixers[newMixerId].enableInputPort(portWithinMixer, errReason, errCode)) {
00214 char resultMsg[100];
00215 sprintf(resultMsg, "Failed to enable input port: %s failed (0x%08x)\n", errReason, errCode);
00216 envir().setResultMsg(resultMsg);
00217 return False;
00218 }
00219
00220 }
00221 return True;
00222 }
00223
00224 unsigned WindowsAudioInputDevice::numMixers = 0;
00225
00226 Mixer* WindowsAudioInputDevice::ourMixers = NULL;
00227
00228 unsigned WindowsAudioInputDevice::numInputPortsTotal = 0;
00229
00230
00232
00233 Mixer::Mixer()
00234 : hMixer(NULL), dwRecLineID(0), numPorts(0), ports(NULL) {
00235 }
00236
00237 Mixer::~Mixer() {
00238 delete[] ports;
00239 }
00240
00241 void Mixer::open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS) {
00242 HMIXER newHMixer = NULL;
00243 do {
00244 MIXERCAPS mc;
00245 if (mixerGetDevCaps(index, &mc, sizeof mc) != MMSYSERR_NOERROR) break;
00246
00247
00248 strncpy(name, mc.szPname, MAXPNAMELEN);
00249
00250
00251 unsigned i, uWavIn;
00252 unsigned nWavIn = waveInGetNumDevs();
00253 for (i = 0; i < nWavIn; ++i) {
00254 WAVEINCAPS wic;
00255 if (waveInGetDevCaps(i, &wic, sizeof wic) != MMSYSERR_NOERROR) continue;
00256
00257 MIXERLINE ml;
00258 ml.cbStruct = sizeof ml;
00259 ml.Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
00260 strncpy(ml.Target.szPname, wic.szPname, MAXPNAMELEN);
00261 ml.Target.vDriverVersion = wic.vDriverVersion;
00262 ml.Target.wMid = wic.wMid;
00263 ml.Target.wPid = wic.wPid;
00264
00265 if (mixerGetLineInfo((HMIXEROBJ)index, &ml, MIXER_GETLINEINFOF_TARGETTYPE) == MMSYSERR_NOERROR) {
00266
00267 uWavIn = i;
00268 dwRecLineID = ml.dwLineID;
00269 break;
00270 }
00271 }
00272 if (i >= nWavIn) break;
00273
00274 if (mixerOpen(&newHMixer, index, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER) != MMSYSERR_NOERROR) break;
00275 if (newHMixer == NULL) break;
00276
00277
00278 if (mixerGetDevCaps((UINT)newHMixer, &mc, sizeof mc) != MMSYSERR_NOERROR) break;
00279 if (mc.cDestinations < 1) break;
00280
00281 if (!WindowsAudioInputDevice_common::openWavInPort(uWavIn, numChannels, samplingFrequency, granularityInMS)) break;
00282
00283 hMixer = newHMixer;
00284 return;
00285 } while (0);
00286
00287
00288 close();
00289 }
00290
00291 void Mixer::open() {
00292 open(1, 8000, 20);
00293 }
00294
00295 void Mixer::getPortsInfo() {
00296 MIXERCAPS mc;
00297 mixerGetDevCaps((UINT)hMixer, &mc, sizeof mc);
00298
00299 MIXERLINE mlt;
00300 unsigned i;
00301 for (i = 0; i < mc.cDestinations; ++i) {
00302 memset(&mlt, 0, sizeof mlt);
00303 mlt.cbStruct = sizeof mlt;
00304 mlt.dwDestination = i;
00305 if (mixerGetLineInfo((HMIXEROBJ)hMixer, &mlt, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR) continue;
00306 if (mlt.dwLineID == dwRecLineID) break;
00307 }
00308 ports = new AudioInputPort[mlt.cConnections];
00309
00310 numPorts = mlt.cConnections;
00311 for (i = 0; i < numPorts; ++i) {
00312 MIXERLINE mlc;
00313 memcpy(&mlc, &mlt, sizeof mlc);
00314 mlc.dwSource = i;
00315 mixerGetLineInfo((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINEINFOF_SOURCE);
00316 ports[i].tag = mlc.dwLineID;
00317 ports[i].dwComponentType = mlc.dwComponentType;
00318 strncpy(ports[i].name, mlc.szName, MIXER_LONG_NAME_CHARS);
00319 }
00320
00321
00322 for (i = 1; i < numPorts; ++i) {
00323 #ifdef OLD_MICROPHONE_TESTING_CODE
00324 if (_strnicmp("mic", ports[i].name, 3) == 0 ||
00325 _strnicmp("mik", ports[i].name, 3) == 0) {
00326 #else
00327 if (ports[i].dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
00328 #endif
00329 AudioInputPort tmp = ports[0];
00330 ports[0] = ports[i];
00331 ports[i] = tmp;
00332 }
00333 }
00334 }
00335
00336 Boolean Mixer::enableInputPort(unsigned portIndex, char const*& errReason, MMRESULT& errCode) {
00337 errReason = NULL;
00338 AudioInputPort& port = ports[portIndex];
00339
00340 MIXERCONTROL mc;
00341 mc.cMultipleItems = 1;
00342 MIXERLINECONTROLS mlc;
00343 #if 0 // the following doesn't seem to be needed, and can fail:
00344 mlc.cbStruct = sizeof mlc;
00345 mlc.pamxctrl = &mc;
00346 mlc.cbmxctrl = sizeof (MIXERCONTROL);
00347 mlc.dwLineID = port.tag;
00348 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
00349 if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE)) != MMSYSERR_NOERROR) {
00350 errReason = "mixerGetLineControls()";
00351 return False;
00352 }
00353 #endif
00354
00355 MIXERLINE ml;
00356 memset(&ml, 0, sizeof (MIXERLINE));
00357 ml.cbStruct = sizeof (MIXERLINE);
00358 ml.dwLineID = port.tag;
00359 if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID)) != MMSYSERR_NOERROR) {
00360 errReason = "mixerGetLineInfo()1";
00361 return False;
00362 }
00363
00364 char portname[MIXER_LONG_NAME_CHARS+1];
00365 strncpy(portname, ml.szName, MIXER_LONG_NAME_CHARS);
00366
00367 memset(&ml, 0, sizeof (MIXERLINE));
00368 ml.cbStruct = sizeof (MIXERLINE);
00369 ml.dwLineID = dwRecLineID;
00370 if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID)) != MMSYSERR_NOERROR) {
00371 errReason = "mixerGetLineInfo()2";
00372 return False;
00373 }
00374
00375
00376 mlc.cbStruct = sizeof mlc;
00377 mlc.dwLineID = ml.dwLineID;
00378 mlc.cControls = 1;
00379 mc.cbStruct = sizeof mc;
00380 mc.dwControlID = 0xDEADBEEF;
00381 mlc.pamxctrl = &mc;
00382 mlc.cbmxctrl = sizeof mc;
00383 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
00384 if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE)) != MMSYSERR_NOERROR) {
00385 mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER;
00386 mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
00387 }
00388
00389 unsigned matchLine = 0;
00390 if (mc.cMultipleItems > 1) {
00391
00392
00393 MIXERCONTROLDETAILS mcd;
00394 mcd.cbStruct = sizeof mcd;
00395 mcd.cChannels = ml.cChannels;
00396 mcd.cMultipleItems = mc.cMultipleItems;
00397 MIXERCONTROLDETAILS_LISTTEXT* mcdlText = new MIXERCONTROLDETAILS_LISTTEXT[mc.cMultipleItems];
00398 mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_LISTTEXT);
00399 mcd.paDetails = mcdlText;
00400
00401 if (mc.dwControlID != 0xDEADBEEF) {
00402 mcd.dwControlID = mc.dwControlID;
00403 if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT)) != MMSYSERR_NOERROR) {
00404 delete[] mcdlText;
00405 errReason = "mixerGetControlDetails()1";
00406 return False;
00407 }
00408 } else {
00409
00410 for (mc.dwControlID = 0; mc.dwControlID < 32; ++mc.dwControlID) {
00411 mcd.dwControlID = mc.dwControlID;
00412 if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT)) == MMSYSERR_NOERROR) break;
00413 }
00414 if (mc.dwControlID == 32) {
00415 delete[] mcdlText;
00416 errReason = "mixerGetControlDetails()2";
00417 return False;
00418 }
00419 }
00420
00421 for (unsigned i = 0; i < mcd.cMultipleItems; ++i) {
00422 if (strcmp(mcdlText[i].szName, portname) == 0) {
00423 matchLine = i;
00424 break;
00425 }
00426 }
00427 delete[] mcdlText;
00428 }
00429
00430
00431 MIXERCONTROLDETAILS mcd;
00432 mcd.cbStruct = sizeof mcd;
00433 mcd.dwControlID = mc.dwControlID;
00434 mcd.cChannels = ml.cChannels;
00435 mcd.cMultipleItems = mc.cMultipleItems;
00436 MIXERCONTROLDETAILS_BOOLEAN* mcdbState = new MIXERCONTROLDETAILS_BOOLEAN[mc.cMultipleItems];
00437 mcd.paDetails = mcdbState;
00438 mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_BOOLEAN);
00439
00440 if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR) {
00441 delete[] mcdbState;
00442 errReason = "mixerGetControlDetails()3";
00443 return False;
00444 }
00445
00446 for (unsigned j = 0; j < mcd.cMultipleItems; ++j) {
00447 mcdbState[j].fValue = (j == matchLine);
00448 }
00449
00450 if ((errCode = mixerSetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_OBJECTF_HMIXER)) != MMSYSERR_NOERROR) {
00451 delete[] mcdbState;
00452 errReason = "mixerSetControlDetails()";
00453 return False;
00454 }
00455 delete[] mcdbState;
00456
00457 return True;
00458 }
00459
00460
00461 void Mixer::close() {
00462 WindowsAudioInputDevice_common::waveIn_close();
00463 if (hMixer != NULL) mixerClose(hMixer);
00464 hMixer = NULL; dwRecLineID = 0;
00465 }