Руководство: организация звукового потока с диска

Примечание

это содержимое применяется только к классическим приложениям, и для работы в приложении для магазина Windows потребуется редакция. Обратитесь к документации по CreateFile2, креативентекс, WaitForSingleObjectEx, сетфилепоинтерекси жетоверлаппедресултекс. см. пример Windows 8 стреамеффект из коллекции примеров Windows SDK.

Вы можете выполнять потоковую передачу звуковых данных в XAudio2, создавая отдельный поток и выполняя операции чтения звуковых данных в потоке потоковой передачи, а затем используя обратные вызовы для управления этим потоком.

Выполнение операций чтения буфера в потоке потоковой передачи

Чтобы выполнить операции чтения буфера в потоке потоковой передачи, выполните следующие действия:

  1. Создайте массив буферов чтения.

    #define STREAMING_BUFFER_SIZE 65536
    #define MAX_BUFFER_COUNT 3
    BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
    
  2. Инициализация структуры с перекрытием.

    Структура используется для проверки завершения асинхронного чтения с диска.

    OVERLAPPED Overlapped = {0};
    Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
  3. Вызовите функцию Start для исходного голоса , который будет воспроизводить потоковую передачу звука.

    hr = pSourceVoice->Start( 0, 0 );
    
  4. Цикл, пока текущая точка чтения не прошла конец звукового файла.

    CurrentDiskReadBuffer = 0;
    CurrentPosition = 0;
    while ( CurrentPosition < cbWaveSize )
    {
        ...
    }
    

    В цикле выполните следующие действия.

    1. Считывает фрагмент данных с диска в текущий буфер чтения.

      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;
      
    2. Используйте функцию GetOverlappedResult для ожидания события, которое сигнализирует о завершении чтения.

      DWORD NumberBytesTransferred;
      ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
      
    3. Подождите, пока количество буферов, помещенных в очередь исходного голоса , будет меньше числа буферов чтения.

      Состояние исходного голоса проверяется с помощью функции- State .

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. Отправьте текущий буфер чтения в Исходный голоса с помощью функции субмитсаурцебуффер .

      XAUDIO2_BUFFER buf = {0};
      buf.AudioBytes = cbValid;
      buf.pAudioData = buffers[CurrentDiskReadBuffer];
      if( CurrentPosition >= cbWaveSize )
      {
          buf.Flags = XAUDIO2_END_OF_STREAM;
      }
      pSourceVoice->SubmitSourceBuffer( &buf );
      
    5. Установите текущий индекс буфера чтения в следующий буфер.

      CurrentDiskReadBuffer++;
      CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
      
  5. После завершения цикла дождитесь завершения воспроизведения оставшихся буферов в очереди.

    Когда оставшиеся буферы завершают воспроизведение, звук останавливается, и поток может выйти из программы или повторно использовать для потоковой передачи другого звука.

    XAUDIO2_VOICE_STATE state;
    while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 )
    {
        WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE );
    }
    

Создание класса обратного вызова

Чтобы создать класс обратного вызова, создайте класс, наследующий от интерфейса IXAudio2VoiceCallback .

Класс должен задавать событие в методе онбуфференд . Это позволяет потоку потоковой передачи переключаться в спящий режим до тех пор, пока событие не выдает ему сигнал о том, что XAudio2 закончил чтение из буфера аудио. Дополнительные сведения об использовании обратных вызовов с XAudio2 см. в статье Использование исходных обратных вызовов.

struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
    HANDLE hBufferEndEvent;
    StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
    ~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
    void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
    ...
};

Потоковая передача звуковых данных

Обратные вызовы в XAudio2

Руководство по программированию для XAudio2

Руководство: создание базовой схемы обработки звука

Руководство: использование обратных вызовов речевых источников