Sdílet prostřednictvím


Postupy: Streamování zvuku z disku

Poznámka

Tento obsah platí jenom pro desktopové aplikace (a aby fungoval v aplikaci pro UPW), vyžadoval by revizi. Projděte si dokumentaci k CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerExa GetOverlappedResultEx. Podívejte se na ukázkovou aplikaci "XAudio2 audio stream effect" systému Windows 8 z nyní archivované Galerie ukázek sady Windows SDK.

V XAudio2 můžete streamovat zvuková data tím, že vytvoříte samostatné vlákno pro čtení vyrovnávací paměti zvukových dat přímo ve streamovacím vlákně a poté použijete zpětná volání pro ovládání tohoto vlákna.

Provádění čtení vyrovnávací paměti ve vlákně pro streamování

Chcete-li provádět čtení vyrovnávací paměti ve vlákně streamování, postupujte takto:

  1. Vytvořte pole vyrovnávacích pamětí pro čtení.

    #define STREAMING_BUFFER_SIZE 65536
    #define MAX_BUFFER_COUNT 3
    BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
    
  2. Inicializace překrývající se struktury

    Struktura se používá ke kontrole dokončení asynchronního čtení disku.

    OVERLAPPED Overlapped = {0};
    Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
  3. Zavolejte funkci Start na zdrojový hlas, který bude přehrávat streamované audio.

    hr = pSourceVoice->Start( 0, 0 );
    
  4. Opakujte, dokud aktuální pozice čtení nepřekročí konec zvukového souboru.

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

    Ve smyčce udělejte toto:

    1. Načtěte blok dat z disku do aktuální vyrovnávací paměti pro čtení.

      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. Pomocí funkce GetOverlappedResult počkejte na událost, která signalizuje dokončení čtení.

      DWORD NumberBytesTransferred;
      ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
      
    3. Počkejte, než bude počet vyrovnávacích pamětí zařazených do fronty na hlasovém zdroji menší než počet vyrovnávacích pamětí určených pro čtení.

      Stav zdrojového hlasu je zkontrolován pomocí funkce GetState.

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. Pomocí funkce SubmitSourceBuffer odešlete aktuální vyrovnávací paměti pro čtení do zvukového zdroje .

      XAUDIO2_BUFFER buf = {0};
      buf.AudioBytes = cbValid;
      buf.pAudioData = buffers[CurrentDiskReadBuffer];
      if( CurrentPosition >= cbWaveSize )
      {
          buf.Flags = XAUDIO2_END_OF_STREAM;
      }
      pSourceVoice->SubmitSourceBuffer( &buf );
      
    5. Nastavte aktuální index vyrovnávací paměti pro čtení na další vyrovnávací paměť.

      CurrentDiskReadBuffer++;
      CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
      
  5. Po dokončení smyčky počkejte na přehrání zbývajících bufferů, které jsou ve frontě.

    Po dokončení přehrávání zbývajících vyrovnávacích pamětí se zvuk zastaví a vlákno může být ukončeno nebo znovu použito ke streamování jiného zvuku.

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

Vytvoření třídy zpětného volání

Chcete-li vytvořit třídu pro zpětné volání, vytvořte třídu, která dědí z rozhraní IXAudio2VoiceCallback.

Třída by měla nastavit událost ve své metodě OnBufferEnd. To umožňuje, aby vlákno streamování přešlo do režimu spánku, dokud mu událost nesignalizuje, že XAudio2 dokončil čtení ze zvukové vyrovnávací paměti. Další informace o použití zpětných volání s XAudio2 naleznete v tématu Postupy: Použití zpětného volání zdrojového hlasu.

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

streamování zvukových dat

zpětná volání XAudio2

Průvodce programováním v XAudio2

Postupy: Vytvoření grafu základního zpracování zvuku

Jak na to: Použití callbacků ve zdrojových hlasových voláních