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 Windows Store. Reportez-vous à la documentation de CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerExet GetOverlappedResultEx. consultez l’exemple de Windows 8 StreamEffect dans la galerie d’exemples SDK Windows.

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

Exécution des lectures de mémoire tampon dans le thread de streaming

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. Initialise une structure OVERLAPPED.

    La structure est utilisée pour vérifier à quel moment 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 lit le streaming audio.

    hr = pSourceVoice->Start( 0, 0 );
    
  4. Boucle lorsque la position de lecture actuelle ne reçoit pas la fin du fichier audio.

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

    Dans la boucle, procédez comme suit :

    1. Lecture d’un segment de données à partir 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 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 en file d’attente sur la voix source soit inférieur au nombre de tampons de lecture.

      L’état de la voix source est vérifié à l’aide de 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éfinit l’index de la mémoire tampon de lecture en cours 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 tampons mis en file d’attente restants.

    Lorsque les mémoires tampons restantes sont terminées, le son s’arrête et le thread peut se fermer 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 streaming de se mettre en veille jusqu’à ce que l’événement indique qu’XAudio2 a fini de lire à partir d’une mémoire tampon audio. Pour plus d’informations sur l’utilisation de rappels avec XAudio2, consultez Comment : utiliser des rappels vocaux source.

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

Diffusion en continu 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