Procédure : diffuser un son en continu à partir du disque

Notes

Ce contenu s’applique uniquement aux applications de bureau et nécessite une révision pour fonctionner dans une application du Windows Store. Reportez-vous à la documentation pour CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx et GetOverlappedResultEx. Consultez l’exemple streamEffect Windows 8 dans la galerie d’exemples du SDK Windows.

 

Vous pouvez diffuser en continu des données audio dans XAudio2 en créant un thread distinct et en effectuant des lectures de mémoire tampon des données audio dans le thread de diffusion en continu, puis en utilisant des rappels pour contrôler ce thread.

Exécution de lectures de mémoire tampon dans le thread de diffusion en continu

Pour effectuer des lectures de mémoire tampon dans le thread de streaming, procédez comme suit :

  1. Créez un tableau de mémoires tampons de lecture.

    #define STREAMING_BUFFER_SIZE 65536
    #define MAX_BUFFER_COUNT 3
    BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
    
  2. Initialisez une structure CHEVAUCHÉE.

    La structure est utilisée pour case activée lorsqu’une lecture de disque asynchrone est terminée.

    OVERLAPPED Overlapped = {0};
    Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
  3. Appelez la fonction Start sur la voix source qui va lire l’audio de streaming.

    hr = pSourceVoice->Start( 0, 0 );
    
  4. Boucle pendant que la position de lecture actuelle n’est pas passée à la fin du fichier audio.

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

    Dans la boucle, procédez comme suit :

    1. Lit un bloc de données du disque dans la mémoire tampon de lecture actuelle.

      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. Utilisez la fonction GetOverlappedResult pour attendre que l’événement qui signale que la lecture est terminée.

      DWORD NumberBytesTransferred;
      ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
      
    3. Attendez que le nombre de mémoires tampons mises en file d’attente sur la voix source soit inférieur au nombre de mémoires tampons de lecture.

      L’état de la voix source est vérifié avec la fonction GetState .

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. Envoyez la mémoire tampon de lecture actuelle à la voix source à l’aide de la fonction 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. Définissez l’index actuel de la mémoire tampon de lecture sur la mémoire tampon suivante.

      CurrentDiskReadBuffer++;
      CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
      
  5. Une fois la boucle terminée, attendez la fin de la lecture des mémoires tampons en file d’attente restantes.

    Une fois la lecture des mémoires tampons restantes terminée, le son s’arrête et le thread peut quitter ou être réutilisé pour diffuser un autre son.

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

Création de la classe de rappel

Pour créer la classe de rappel, créez une classe qui hérite de l’interface IXAudio2VoiceCallback .

La classe doit définir un événement dans sa méthode OnBufferEnd . Cela permet au thread de diffusion en continu de se mettre en veille jusqu’à ce que l’événement indique que XAudio2 a terminé la lecture à partir d’une mémoire tampon audio. Pour plus d’informations sur l’utilisation des rappels avec XAudio2, consultez How to: Use Source Voice Callbacks.

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

Streaming de données audio

Rappels XAudio2

Guide de programmation XAudio2

Procédure : créer un graphique de traitement audio de base

Procédure : utiliser des rappels de voix source