Procedura: trasmettere in streaming un suono da disco
Nota
Questo contenuto si applica solo alle app desktop e richiede la revisione per funzionare in un'app UWP. Fare riferimento alla documentazione per CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx e GetOverlappedResultEx. Vedi l'app di esempio dell'effetto flusso audio XAudio2 di Windows 8 dalla raccolta di esempi di Windows SDK, ora archiviata.
È possibile trasmettere dati audio in XAudio2 creando un thread separato ed eseguendo letture buffer dei dati audio nel thread di streaming e quindi usare i callback per controllare tale thread.
Esecuzione di letture del buffer nel thread di streaming
Per eseguire letture del buffer nel thread di streaming, seguire questa procedura:
Creare una matrice di buffer di lettura.
#define STREAMING_BUFFER_SIZE 65536 #define MAX_BUFFER_COUNT 3 BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
Inizializzare una struttura OVERLAPPED.
La struttura viene usata per verificare quando è stata completata la lettura di un disco asincrono.
OVERLAPPED Overlapped = {0}; Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
Chiamare la funzione Start sulla voce sorgente che riprodurrà l'audio in streaming.
hr = pSourceVoice->Start( 0, 0 );
Ripeti il ciclo finché la posizione di lettura corrente non ha superato la fine del file audio.
CurrentDiskReadBuffer = 0; CurrentPosition = 0; while ( CurrentPosition < cbWaveSize ) { ... }
Nel ciclo eseguire le operazioni seguenti:
Leggere un blocco di dati dal disco nel buffer di lettura corrente.
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;
Usare la funzione GetOverlappedResult per attendere l'evento che segnala il completamento della lettura.
DWORD NumberBytesTransferred; ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
Attendere che il numero di buffer accodati nella voce di origine sia minore del numero di buffer da leggere.
Lo stato della voce di origine viene controllato con la funzione GetState.
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1) { WaitForSingleObject( Context.hBufferEndEvent, INFINITE ); }
Inviare il buffer di lettura corrente alla voce di origine usando la funzione SubmitSourceBuffer.
XAUDIO2_BUFFER buf = {0}; buf.AudioBytes = cbValid; buf.pAudioData = buffers[CurrentDiskReadBuffer]; if( CurrentPosition >= cbWaveSize ) { buf.Flags = XAUDIO2_END_OF_STREAM; } pSourceVoice->SubmitSourceBuffer( &buf );
Impostare l'indice del buffer di lettura attuale sul buffer successivo.
CurrentDiskReadBuffer++; CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
Dopo che il ciclo è terminato, attendere che i buffer in coda rimanenti finiscano di riprodursi.
Al termine della riproduzione dei buffer rimanenti, il suono si interrompe e il thread può uscire o essere riutilizzato per trasmettere un altro suono.
XAUDIO2_VOICE_STATE state; while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 ) { WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE ); }
Creazione della classe di callback
Per creare la classe di callback, creare una classe che eredita dall'interfaccia IXAudio2VoiceCallback .
La classe deve impostare un evento nel suo metodo OnBufferEnd. In questo modo il thread di streaming può essere sospeso fino a quando l'evento segnala che XAudio2 ha terminato la lettura da un buffer audio. Per ulteriori informazioni sull'uso dei callback vocali di origine con XAudio2, vedere Procedura: Utilizzare i callback vocali di origine.
struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
HANDLE hBufferEndEvent;
StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
...
};
Argomenti correlati