共用方式為


操作說明:從磁碟串流聲音

注意

此內容僅適用於傳統型應用程式(且需要修訂才能在 UWP 應用程式中運作)。 請參閱 CreateFile2、CreateEventEx、WaitForSingleObjectExSetFilePointerEx 和 GetOverlappedResultEx 的檔。 請參閱 XAudio2 音訊串流效果 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. 等候在來源語音排入佇列的緩衝區數目小於讀取緩衝區的數目。

      來源語音的狀態會使用 GetState 函式進行檢查。

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. 使用 SubmitSourceBuffer 函式將目前的讀取緩衝區提交至來源語音。

      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 介面的類別。

類別應該在其 OnBufferEnd 方法中設定事件。 這可讓串流線程自行進入睡眠狀態,直到事件發出 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 程式設計指南

操作說明:建置基本音訊處理圖形

操作說明:使用來源聲音回撥