WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& d, const bool exclusiveMode) : device (d), sampleRate (0), defaultSampleRate (0), numChannels (0), actualNumChannels (0), minBufferSize (0), defaultBufferSize (0), latencySamples (0), useExclusiveMode (exclusiveMode), sampleRateHasChanged (false) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); ComSmartPtr <IAudioClient> tempClient (createClient()); if (tempClient == nullptr) return; REFERENCE_TIME defaultPeriod, minPeriod; if (! check (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) return; WAVEFORMATEX* mixFormat = nullptr; if (! check (tempClient->GetMixFormat (&mixFormat))) return; WAVEFORMATEXTENSIBLE format; copyWavFormat (format, mixFormat); CoTaskMemFree (mixFormat); actualNumChannels = numChannels = format.Format.nChannels; defaultSampleRate = format.Format.nSamplesPerSec; minBufferSize = refTimeToSamples (minPeriod, defaultSampleRate); defaultBufferSize = refTimeToSamples (defaultPeriod, defaultSampleRate); rates.addUsingDefaultSort (defaultSampleRate); static const int ratesToTest[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; for (int i = 0; i < numElementsInArray (ratesToTest); ++i) { if (ratesToTest[i] == defaultSampleRate) continue; format.Format.nSamplesPerSec = (DWORD) ratesToTest[i]; if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0))) if (! rates.contains (ratesToTest[i])) rates.addUsingDefaultSort (ratesToTest[i]); } }
WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& device_) : device (device_), sampleRate (0), numChannels (0), actualNumChannels (0), defaultSampleRate (0), minBufferSize (0), defaultBufferSize (0), latencySamples (0) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); ComSmartPtr <IAudioClient> tempClient (createClient()); if (tempClient == 0) return; REFERENCE_TIME defaultPeriod, minPeriod; if (! OK (tempClient->GetDevicePeriod (&defaultPeriod, &minPeriod))) return; WAVEFORMATEX* mixFormat = 0; if (! OK (tempClient->GetMixFormat (&mixFormat))) return; WAVEFORMATEXTENSIBLE format; wasapi_copyWavFormat (format, mixFormat); CoTaskMemFree (mixFormat); actualNumChannels = numChannels = format.Format.nChannels; defaultSampleRate = format.Format.nSamplesPerSec; minBufferSize = wasapi_refTimeToSamples (minPeriod, defaultSampleRate); defaultBufferSize = wasapi_refTimeToSamples (defaultPeriod, defaultSampleRate); FloatElementComparator<double> comparator; rates.addSorted (comparator, defaultSampleRate); static const double ratesToTest[] = { 44100.0, 48000.0, 88200.0, 96000.0 }; for (int i = 0; i < numElementsInArray (ratesToTest); ++i) { if (ratesToTest[i] == defaultSampleRate) continue; format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]); if (SUCCEEDED (tempClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0))) if (! rates.contains (ratesToTest[i])) rates.addSorted (comparator, ratesToTest[i]); } }
bool tryInitialisingWithFormat (const bool useFloat, const int bytesPerSampleToTry) { WAVEFORMATEXTENSIBLE format; zerostruct (format); if (numChannels <= 2 && bytesPerSampleToTry <= 2) { format.Format.wFormatTag = WAVE_FORMAT_PCM; } else { format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; format.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX); } format.Format.nSamplesPerSec = roundDoubleToInt (sampleRate); format.Format.nChannels = (WORD) numChannels; format.Format.wBitsPerSample = (WORD) (8 * bytesPerSampleToTry); format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * numChannels * bytesPerSampleToTry); format.Format.nBlockAlign = (WORD) (numChannels * bytesPerSampleToTry); format.SubFormat = useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM; format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample; switch (numChannels) { case 1: format.dwChannelMask = SPEAKER_FRONT_CENTER; break; case 2: format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; case 4: format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case 6: format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; case 8: format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; break; default: break; } WAVEFORMATEXTENSIBLE* nearestFormat = 0; HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat); logFailure (hr); if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) { wasapi_copyWavFormat (format, (WAVEFORMATEX*) nearestFormat); hr = S_OK; } CoTaskMemFree (nearestFormat); GUID session; if (hr == S_OK && OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, (WAVEFORMATEX*) &format, &session))) { actualNumChannels = format.Format.nChannels; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; bytesPerSample = format.Format.wBitsPerSample / 8; dataFormat = isFloat ? AudioDataConverters::float32LE : (bytesPerSample == 4 ? AudioDataConverters::int32LE : ((bytesPerSample == 3 ? AudioDataConverters::int24LE : AudioDataConverters::int16LE))); return true; } return false; }