So wird's gemacht: Streamen von Sound von einem Datenträger
Hinweis
Dieser Inhalt gilt nur für Desktop-Apps und erfordert eine Überarbeitung, um in einer Windows Store-App zu funktionieren. Weitere Informationen finden Sie in der Dokumentation zu CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx und GetOverlappedResultEx. Sehen Sie sich das StreamEffect-Windows 8 Beispiel aus dem Windows SDK-Beispielkatalog an.
Sie können Audiodaten in XAudio2 streamen, indem Sie einen separaten Thread erstellen und Pufferlesevorgänge der Audiodaten im Streamingthread ausführen und dann Rückrufe verwenden, um diesen Thread zu steuern.
Ausführen von Pufferlesevorgängen im Streamingthread
Führen Sie die folgenden Schritte aus, um Pufferlesevorgänge im Streamingthread auszuführen:
Erstellen Sie ein Array von Lesepuffern.
#define STREAMING_BUFFER_SIZE 65536 #define MAX_BUFFER_COUNT 3 BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
Initialisieren Sie eine ÜBERLAPPENDE Struktur.
Die Struktur wird verwendet, um zu überprüfen, wann ein asynchroner Datenträgerlesevorgang abgeschlossen ist.
OVERLAPPED Overlapped = {0}; Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
Rufen Sie die Startfunktion für die Quellstimme auf, die das Streamingaudio abgibt.
hr = pSourceVoice->Start( 0, 0 );
Schleife, während die aktuelle Leseposition nicht am Ende der Audiodatei übergeben wird.
CurrentDiskReadBuffer = 0; CurrentPosition = 0; while ( CurrentPosition < cbWaveSize ) { ... }
Führen Sie in der Schleife die folgenden Schritte aus:
Liest einen Datenblock vom Datenträger in den aktuellen Lesepuffer.
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;
Verwenden Sie die GetOverlappedResult-Funktion , um auf das Ereignis zu warten, das signalisiert, dass der Lesevorgang abgeschlossen ist.
DWORD NumberBytesTransferred; ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
Warten Sie, bis die Anzahl der Puffer, die in der Quellstimme in die Warteschlange eingereiht wurden, kleiner als die Anzahl der Lesepuffer ist.
Der Zustand der Quellstimme wird mit der GetState-Funktion überprüft.
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1) { WaitForSingleObject( Context.hBufferEndEvent, INFINITE ); }
Übermitteln Sie den aktuellen Lesepuffer mithilfe der SubmitSourceBuffer-Funktion an die Quellstimme.
XAUDIO2_BUFFER buf = {0}; buf.AudioBytes = cbValid; buf.pAudioData = buffers[CurrentDiskReadBuffer]; if( CurrentPosition >= cbWaveSize ) { buf.Flags = XAUDIO2_END_OF_STREAM; } pSourceVoice->SubmitSourceBuffer( &buf );
Legen Sie den aktuellen Lesepufferindex auf den nächsten Puffer fest.
CurrentDiskReadBuffer++; CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
Nachdem die Schleife abgeschlossen ist, warten Sie, bis die restlichen Puffer in der Warteschlange mit der Wiedergabe fertig sind.
Wenn die restlichen Puffer die Wiedergabe beendet haben, wird der Sound beendet, und der Thread kann beendet oder wiederverwendet werden, um einen anderen Sound zu streamen.
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 ) { WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE ); }
Erstellen der Rückrufklasse
Um die Rückrufklasse zu erstellen, erstellen Sie eine Klasse, die von der IXAudio2VoiceCallback-Schnittstelle erbt.
Die -Klasse sollte ein Ereignis in ihrer OnBufferEnd-Methode festlegen. Dadurch kann sich der Streamingthread in den Ruhezustand versetzen, bis das Ereignis signalisiert, dass XAudio2 das Lesen aus einem Audiopuffer beendet hat. Weitere Informationen zur Verwendung von Rückrufen mit XAudio2 finden Sie unter Vorgehensweise: Verwenden von Quell-VoIP-Rückrufen.
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
HANDLE hBufferEndEvent;
StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
...
};
Zugehörige Themen
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für