Руководство: организация звукового потока с диска
Примечание
Это содержимое применяется только к классическим приложениям и потребует редакции для работы в приложении Магазина Windows. Ознакомьтесь с документацией по CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx и GetOverlappedResultEx. См. пример Windows 8 StreamEffect из коллекции примеров windows SDK.
Вы можете выполнять потоковую передачу звуковых данных в XAudio2, создав отдельный поток и выполняя чтение звуковых данных в буфере в потоке потоковой передачи, а затем использовать обратные вызовы для управления этим потоком.
Выполнение операций чтения буфера в потоке потоковой передачи
Чтобы выполнить операции чтения буфера в потоке потоковой передачи, выполните следующие действия.
Создайте массив буферов чтения.
#define STREAMING_BUFFER_SIZE 65536 #define MAX_BUFFER_COUNT 3 BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
Инициализация структуры OVERLAPPED.
Структура используется для проверка после завершения асинхронного чтения диска.
OVERLAPPED Overlapped = {0}; Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
Вызовите функцию Start для исходного голоса , который будет воспроизводить потоковый звук.
hr = pSourceVoice->Start( 0, 0 );
Цикл, пока текущая позиция чтения не передается в конец звукового файла.
CurrentDiskReadBuffer = 0; CurrentPosition = 0; while ( CurrentPosition < cbWaveSize ) { ... }
В цикле выполните следующие действия.
Считывает блок данных с диска в текущий буфер чтения.
DWORD dwRead; if( SUCCEEDED(hr) && 0 == ReadFile( hFile, pData, dwDataSize, &dwRead, pOverlapped ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); DWORD cbValid = min( STREAMING_BUFFER_SIZE, cbWaveSize - CurrentPosition ); DWORD dwRead; if( 0 == ReadFile( hFile, buffers[CurrentDiskReadBuffer], STREAMING_BUFFER_SIZE, &dwRead, &Overlapped ) ) hr = HRESULT_FROM_WIN32( GetLastError() ); Overlapped.Offset += cbValid; //update the file position to where it will be once the read finishes CurrentPosition += cbValid;
Используйте функцию GetOverlappedResult , чтобы дождаться события, которое сообщает о завершении чтения.
DWORD NumberBytesTransferred; ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
Дождитесь, пока количество буферов, помещенных в очередь в исходном голосе , будет меньше числа буферов чтения.
Состояние исходного голоса проверяется с помощью функции GetState .
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1) { WaitForSingleObject( Context.hBufferEndEvent, INFINITE ); }
Отправьте текущий буфер чтения в исходный голос с помощью функции SubmitSourceBuffer .
XAUDIO2_BUFFER buf = {0}; buf.AudioBytes = cbValid; buf.pAudioData = buffers[CurrentDiskReadBuffer]; if( CurrentPosition >= cbWaveSize ) { buf.Flags = XAUDIO2_END_OF_STREAM; } pSourceVoice->SubmitSourceBuffer( &buf );
Задайте для текущего индекса буфера чтения следующий буфер.
CurrentDiskReadBuffer++; CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
После завершения цикла дождитесь завершения воспроизведения оставшихся буферов в очереди.
После завершения воспроизведения оставшихся буферов звук останавливается, а поток может выйти или повторно использоваться для потоковой передачи другого звука.
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 ) { WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE ); }
Создание класса обратного вызова
Чтобы создать класс обратного вызова, создайте класс, наследующий от интерфейса IXAudio2VoiceCallback .
Класс должен задать событие в методе OnBufferEnd . Это позволяет потоку потоковой передачи переходить в спящий режим, пока событие не сообщает ему о завершении чтения XAudio2 из звукового буфера. Дополнительные сведения об использовании обратных вызовов с XAudio2 см. в разделе Практическое руководство. Использование обратных вызовов исходной голосовой связи.
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
HANDLE hBufferEndEvent;
StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
...
};
Связанные темы
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по