방법: 디스크에서 소리 스트리밍

참고

이 콘텐츠는 데스크톱 앱에만 적용 되며 Windows 스토어 앱에서 작동 하려면 수정이 필요 합니다. CreateFile2, createeventex, WaitForSingleObjectEx, setfilepointerexGetOverlappedResultEx 에 대 한 설명서를 참조 하세요. Windows SDK 샘플 갤러리에서 streameffect Windows 8 샘플을 참조 하세요.

별도의 스레드를 만들고 스트리밍 스레드에서 오디오 데이터의 버퍼 읽기를 수행한 다음 콜백을 사용 하 여 해당 스레드를 제어 함으로써 오디오 데이터를 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. 스트리밍 오디오를 재생 하는 소스 음성 에서 시작 함수를 호출 합니다.

    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 프로그래밍 가이드

방법: 기본 오디오 처리 Graph 빌드

방법: 소스 음성 콜백 사용