00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "WindowsAudioInputDevice_common.hh"
00023 #include <GroupsockHelper.hh>
00024
00026
00027 unsigned WindowsAudioInputDevice_common::_bitsPerSample = 16;
00028
00029 WindowsAudioInputDevice_common
00030 ::WindowsAudioInputDevice_common(UsageEnvironment& env, int inputPortNumber,
00031 unsigned char bitsPerSample,
00032 unsigned char numChannels,
00033 unsigned samplingFrequency,
00034 unsigned granularityInMS)
00035 : AudioInputDevice(env, bitsPerSample, numChannels, samplingFrequency, granularityInMS),
00036 fCurPortIndex(-1), fHaveStarted(False) {
00037 _bitsPerSample = bitsPerSample;
00038 }
00039
00040 WindowsAudioInputDevice_common::~WindowsAudioInputDevice_common() {
00041 }
00042
00043 Boolean WindowsAudioInputDevice_common::initialSetInputPort(int portIndex) {
00044 if (!setInputPort(portIndex)) {
00045 char errMsgPrefix[100];
00046 sprintf(errMsgPrefix, "Failed to set audio input port number to %d: ", portIndex);
00047 char* errMsgSuffix = strDup(envir().getResultMsg());
00048 envir().setResultMsg(errMsgPrefix, errMsgSuffix);
00049 delete[] errMsgSuffix;
00050 return False;
00051 } else {
00052 return True;
00053 }
00054 }
00055
00056 void WindowsAudioInputDevice_common::doGetNextFrame() {
00057 if (!fHaveStarted) {
00058
00059 while (readHead != NULL) releaseHeadBuffer();
00060 fHaveStarted = True;
00061 }
00062 fTotalPollingDelay = 0;
00063 audioReadyPoller1();
00064 }
00065
00066 void WindowsAudioInputDevice_common::doStopGettingFrames() {
00067
00068 envir().taskScheduler().unscheduleDelayedTask(nextTask()); nextTask() = NULL;
00069 }
00070
00071 double WindowsAudioInputDevice_common::getAverageLevel() const {
00072
00073
00074 if (readHead != NULL) {
00075 double levelTotal = 0.0;
00076 unsigned totNumSamples = 0;
00077 WAVEHDR* curHdr = readHead;
00078 while (1) {
00079 short* samplePtr = (short*)(curHdr->lpData);
00080 unsigned numSamples = blockSize/2;
00081 totNumSamples += numSamples;
00082
00083 while (numSamples-- > 0) {
00084 short sample = *samplePtr++;
00085 if (sample < 0) sample = -sample;
00086 levelTotal += (unsigned short)sample;
00087 }
00088
00089 if (curHdr == readTail) break;
00090 curHdr = curHdr->lpNext;
00091 }
00092 averageLevel = levelTotal/(totNumSamples*(double)0x8000);
00093 }
00094 return averageLevel;
00095 }
00096
00097 void WindowsAudioInputDevice_common::audioReadyPoller(void* clientData) {
00098 WindowsAudioInputDevice_common* inputDevice = (WindowsAudioInputDevice_common*)clientData;
00099 inputDevice->audioReadyPoller1();
00100 }
00101
00102 void WindowsAudioInputDevice_common::audioReadyPoller1() {
00103 if (readHead != NULL) {
00104 onceAudioIsReady();
00105 } else {
00106 unsigned const maxPollingDelay = (100 + fGranularityInMS)*1000;
00107 if (fTotalPollingDelay > maxPollingDelay) {
00108
00109 handleClosure(this);
00110 return;
00111 }
00112
00113
00114 unsigned const uSecondsToDelay = fGranularityInMS*1000;
00115 fTotalPollingDelay += uSecondsToDelay;
00116 nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToDelay,
00117 (TaskFunc*)audioReadyPoller, this);
00118 }
00119 }
00120
00121 void WindowsAudioInputDevice_common::onceAudioIsReady() {
00122 fFrameSize = readFromBuffers(fTo, fMaxSize, fPresentationTime);
00123 if (fFrameSize == 0) {
00124
00125 handleClosure(this);
00126 return;
00127 }
00128 fDurationInMicroseconds = 1000000/fSamplingFrequency;
00129
00130
00131
00132
00133 afterGetting(this);
00134 }
00135
00136 static void CALLBACK waveInCallback(HWAVEIN , UINT uMsg,
00137 DWORD , DWORD dwParam1, DWORD ) {
00138 switch (uMsg) {
00139 case WIM_DATA:
00140 WAVEHDR* hdr = (WAVEHDR*)dwParam1;
00141 WindowsAudioInputDevice_common::waveInProc(hdr);
00142 break;
00143 }
00144 }
00145
00146 Boolean WindowsAudioInputDevice_common::openWavInPort(int index, unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS) {
00147 uSecsPerByte = (8*1e6)/(_bitsPerSample*numChannels*samplingFrequency);
00148
00149
00150 WAVEFORMATEX wfx;
00151 wfx.wFormatTag = WAVE_FORMAT_PCM;
00152 wfx.nChannels = numChannels;
00153 wfx.nSamplesPerSec = samplingFrequency;
00154 wfx.wBitsPerSample = _bitsPerSample;
00155 wfx.nBlockAlign = (numChannels*_bitsPerSample)/8;
00156 wfx.nAvgBytesPerSec = samplingFrequency*wfx.nBlockAlign;
00157 wfx.cbSize = 0;
00158
00159 blockSize = (wfx.nAvgBytesPerSec*granularityInMS)/1000;
00160
00161
00162
00163 unsigned const bufferSeconds = 10;
00164 numBlocks = (bufferSeconds*1000)/granularityInMS;
00165
00166 if (!waveIn_open(index, wfx)) return False;
00167
00168
00169
00170 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
00171 return True;
00172 }
00173
00174 Boolean WindowsAudioInputDevice_common::waveIn_open(unsigned uid, WAVEFORMATEX& wfx) {
00175 if (shWaveIn != NULL) return True;
00176
00177 do {
00178 waveIn_reset();
00179 if (waveInOpen(&shWaveIn, uid, &wfx,
00180 (DWORD)waveInCallback, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) break;
00181
00182
00183 readData = new unsigned char[numBlocks*blockSize];
00184 if (readData == NULL) break;
00185
00186 readHdrs = new WAVEHDR[numBlocks];
00187 if (readHdrs == NULL) break;
00188 readHead = readTail = NULL;
00189
00190 readTimes = new struct timeval[numBlocks];
00191 if (readTimes == NULL) break;
00192
00193
00194 for (unsigned i = 0; i < numBlocks; ++i) {
00195 readHdrs[i].lpData = (char*)&readData[i*blockSize];
00196 readHdrs[i].dwBufferLength = blockSize;
00197 readHdrs[i].dwFlags = 0;
00198 if (waveInPrepareHeader(shWaveIn, &readHdrs[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR) break;
00199 if (waveInAddBuffer(shWaveIn, &readHdrs[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR) break;
00200 }
00201
00202 if (waveInStart(shWaveIn) != MMSYSERR_NOERROR) break;
00203
00204 hAudioReady = CreateEvent(NULL, TRUE, FALSE, "waveIn Audio Ready");
00205 return True;
00206 } while (0);
00207
00208 waveIn_reset();
00209 return False;
00210 }
00211
00212 void WindowsAudioInputDevice_common::waveIn_close() {
00213 if (shWaveIn == NULL) return;
00214
00215 waveInStop(shWaveIn);
00216 waveInReset(shWaveIn);
00217
00218 for (unsigned i = 0; i < numBlocks; ++i) {
00219 if (readHdrs[i].dwFlags & WHDR_PREPARED) {
00220 waveInUnprepareHeader(shWaveIn, &readHdrs[i], sizeof (WAVEHDR));
00221 }
00222 }
00223
00224 waveInClose(shWaveIn);
00225 waveIn_reset();
00226 }
00227
00228 void WindowsAudioInputDevice_common::waveIn_reset() {
00229 shWaveIn = NULL;
00230
00231 delete[] readData; readData = NULL;
00232 bytesUsedAtReadHead = 0;
00233
00234 delete[] readHdrs; readHdrs = NULL;
00235 readHead = readTail = NULL;
00236
00237 delete[] readTimes; readTimes = NULL;
00238
00239 hAudioReady = NULL;
00240 }
00241
00242 unsigned WindowsAudioInputDevice_common::readFromBuffers(unsigned char* to, unsigned numBytesWanted, struct timeval& creationTime) {
00243
00244 if (readHead != NULL) {
00245 int hdrIndex = readHead - readHdrs;
00246 creationTime = readTimes[hdrIndex];
00247
00248
00249 if (bytesUsedAtReadHead > 0) {
00250 creationTime.tv_usec += (unsigned)(uSecsPerByte*bytesUsedAtReadHead);
00251 creationTime.tv_sec += creationTime.tv_usec/1000000;
00252 creationTime.tv_usec %= 1000000;
00253 }
00254 }
00255
00256
00257 unsigned numBytesRead = 0;
00258 while (readHead != NULL && numBytesRead < numBytesWanted) {
00259 unsigned thisRead = min(readHead->dwBytesRecorded - bytesUsedAtReadHead, numBytesWanted - numBytesRead);
00260 memmove(&to[numBytesRead], &readHead->lpData[bytesUsedAtReadHead], thisRead);
00261 numBytesRead += thisRead;
00262 bytesUsedAtReadHead += thisRead;
00263 if (bytesUsedAtReadHead == readHead->dwBytesRecorded) {
00264
00265 releaseHeadBuffer();
00266 }
00267 }
00268
00269 return numBytesRead;
00270 }
00271
00272 void WindowsAudioInputDevice_common::releaseHeadBuffer() {
00273 WAVEHDR* toRelease = readHead;
00274 if (readHead == NULL) return;
00275
00276 readHead = readHead->lpNext;
00277 if (readHead == NULL) readTail = NULL;
00278
00279 toRelease->lpNext = NULL;
00280 toRelease->dwBytesRecorded = 0;
00281 toRelease->dwFlags &= ~WHDR_DONE;
00282 waveInAddBuffer(shWaveIn, toRelease, sizeof (WAVEHDR));
00283 bytesUsedAtReadHead = 0;
00284 }
00285
00286 void WindowsAudioInputDevice_common::waveInProc(WAVEHDR* hdr) {
00287 unsigned hdrIndex = hdr - readHdrs;
00288
00289
00290 int dontCare;
00291 gettimeofday(&readTimes[hdrIndex], &dontCare);
00292
00293
00294 hdr->lpNext = NULL;
00295 if (readTail != NULL) {
00296 readTail->lpNext = hdr;
00297 readTail = hdr;
00298 } else {
00299 readHead = readTail = hdr;
00300 }
00301 SetEvent(hAudioReady);
00302 }
00303
00304 HWAVEIN WindowsAudioInputDevice_common::shWaveIn = NULL;
00305
00306 unsigned WindowsAudioInputDevice_common::blockSize = 0;
00307 unsigned WindowsAudioInputDevice_common::numBlocks = 0;
00308
00309 unsigned char* WindowsAudioInputDevice_common::readData = NULL;
00310 DWORD WindowsAudioInputDevice_common::bytesUsedAtReadHead = 0;
00311 double WindowsAudioInputDevice_common::uSecsPerByte = 0.0;
00312 double WindowsAudioInputDevice_common::averageLevel = 0.0;
00313
00314 WAVEHDR* WindowsAudioInputDevice_common::readHdrs = NULL;
00315 WAVEHDR* WindowsAudioInputDevice_common::readHead = NULL;
00316 WAVEHDR* WindowsAudioInputDevice_common::readTail = NULL;
00317
00318 struct timeval* WindowsAudioInputDevice_common::readTimes = NULL;
00319
00320 HANDLE WindowsAudioInputDevice_common::hAudioReady = NULL;