Bagikan melalui


Cara: Mengalirkan Suara dari Disk

Catatan

Konten ini hanya berlaku untuk aplikasi desktop dan akan memerlukan revisi untuk berfungsi di aplikasi Bursa Windows. Silakan lihat dokumentasi untuk CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx, dan GetOverlappedResultEx. Lihat sampel Windows 8 StreamEffect dari Galeri Sampel Windows SDK.

 

Anda dapat melakukan streaming data audio di XAudio2 dengan membuat utas terpisah dan melakukan pembacaan buffer data audio di utas streaming, lalu menggunakan panggilan balik untuk mengontrol utas tersebut.

Melakukan pembacaan buffer di utas streaming

Untuk melakukan pembacaan buffer di utas streaming, ikuti langkah-langkah berikut:

  1. Buat array buffer baca.

    #define STREAMING_BUFFER_SIZE 65536
    #define MAX_BUFFER_COUNT 3
    BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
    
  2. Menginisialisasi struktur YANG TUMPANG TINDIH.

    Struktur digunakan untuk memeriksa kapan pembacaan disk asinkron telah selesai.

    OVERLAPPED Overlapped = {0};
    Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
  3. Panggil fungsi Mulai pada suara sumber yang akan memutar audio streaming.

    hr = pSourceVoice->Start( 0, 0 );
    
  4. Perulangan saat posisi baca saat ini tidak melewati akhir file audio.

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

    Dalam perulangan, lakukan hal berikut:

    1. Baca potongan data dari disk ke dalam buffer baca saat ini.

      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. Gunakan fungsi GetOverlappedResult untuk menunggu peristiwa yang menandakan pembacaan telah selesai.

      DWORD NumberBytesTransferred;
      ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
      
    3. Tunggu hingga jumlah buffer yang diantrekan pada suara sumber kurang dari jumlah buffer baca.

      Status suara sumber diperiksa dengan fungsi GetState .

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. Kirim buffer baca saat ini ke suara sumber menggunakan fungsi 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. Atur indeks buffer baca saat ini ke buffer berikutnya.

      CurrentDiskReadBuffer++;
      CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
      
  5. Setelah perulangan selesai, tunggu buffer antrean yang tersisa selesai diputar.

    Ketika buffer yang tersisa telah selesai diputar, suara berhenti, dan utas dapat keluar atau digunakan kembali untuk mengalirkan suara lain.

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

Membuat kelas panggilan balik

Untuk membuat kelas panggilan balik, buat kelas yang mewarisi dari antarmuka IXAudio2VoiceCallback .

Kelas harus mengatur peristiwa dalam metode OnBufferEnd-nya . Ini memungkinkan utas streaming untuk membuat dirinya tertidur sampai peristiwa memberi sinyal bahwa XAudio2 telah selesai membaca dari buffer audio. Untuk informasi selengkapnya tentang menggunakan panggilan balik dengan XAudio2, lihat Cara: Menggunakan Panggilan Balik Suara Sumber.

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

Streaming Audio Data

Panggilan Balik XAudio2

Panduan Pemrograman XAudio2

Cara: Membangun Grafik Pemrosesan Audio Dasar

Cara: Menggunakan Panggilan Balik Suara Sumber