in Shared/Audio/AudioStreamReader.cpp [21:167]
HRESULT AudioStreamReader::Initialize(SpeechSynthesisStream^ speechSynthesisStream)
{
BOOL mfStarted = FALSE;
auto hr = MFStartup(MF_VERSION);
mfStarted = SUCCEEDED(hr);
ComPtr<IUnknown> streamUnknown = reinterpret_cast<IUnknown*>(speechSynthesisStream);
ComPtr<IMFByteStream> byteStream;
if (SUCCEEDED(hr))
{
hr = MFCreateMFByteStreamOnStreamEx(streamUnknown.Get(), &byteStream);
}
ComPtr<IMFSourceReader> reader;
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromByteStream(byteStream.Get(), nullptr, &reader);
}
// Select the first audio stream, and deselect all other streams.
if (SUCCEEDED(hr))
{
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_ALL_STREAMS), FALSE);
}
if (SUCCEEDED(hr))
{
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
}
// Create a partial media type that specifies uncompressed PCM audio.
ComPtr<IMFMediaType> partialType;
if (SUCCEEDED(hr))
{
hr = MFCreateMediaType(&partialType);
}
if (SUCCEEDED(hr))
{
hr = partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
}
if (SUCCEEDED(hr))
{
hr = partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
}
// Set this type on the source reader. The source reader will load the necessary decoder.
if (SUCCEEDED(hr))
{
hr = reader->SetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), nullptr, partialType.Get());
}
// Get the complete uncompressed format
ComPtr<IMFMediaType> uncompressedAudioType;
if (SUCCEEDED(hr))
{
hr = reader->GetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &uncompressedAudioType);
}
// Ensure the stream is selected.
if (SUCCEEDED(hr))
{
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
}
// Get the audio block size and number of bytes/second from the audio format.
if (SUCCEEDED(hr))
{
WAVEFORMATEX* format = nullptr;
UINT32 size = 0;
hr = MFCreateWaveFormatExFromMFMediaType(uncompressedAudioType.Get(), &format, &size);
// Only mono PCM files are supported for HRTF processing
if (SUCCEEDED(hr) && format->wFormatTag != WAVE_FORMAT_PCM && format->nChannels != 1)
{
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr))
{
CopyMemory(&_format, format, sizeof WAVEFORMATEX);
}
if (format)
{
CoTaskMemFree(format);
}
}
// Get audio samples from the source reader.
_audioData.resize(0);
while (SUCCEEDED(hr))
{
DWORD dwFlags = 0;
// Read the next sample.
ComPtr<IMFSample> sample;
hr = reader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, nullptr, &dwFlags, nullptr, &sample);
if (SUCCEEDED(hr) && (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) != 0)
{
// End of stream
break;
}
if (SUCCEEDED(hr) && sample == nullptr)
{
// No sample, keep going
continue;
}
// Get a pointer to the audio data in the sample.
ComPtr<IMFMediaBuffer> buffer;
if (SUCCEEDED(hr))
{
hr = sample->ConvertToContiguousBuffer(&buffer);
}
DWORD bufferSize = 0;
if (SUCCEEDED(hr))
{
BYTE* data;
hr = buffer->Lock(&data, nullptr, &bufferSize);
auto currentDataSize = _audioData.size();
if (SUCCEEDED(hr))
{
_audioData.resize(currentDataSize + bufferSize);
}
if (SUCCEEDED(hr))
{
CopyMemory(_audioData.data() + currentDataSize, data, bufferSize);
// Unlock the buffer
hr = buffer->Unlock();
}
}
}
if (mfStarted)
{
MFShutdown();
}
return hr;
}