Ecco una domanda apparentemente semplice:Come utilizzare System.Media.SoundPlayer per riprodurre in modo asincrono un file audio?
Qual è il modo corretto di giocare in modo asincrono un file di risorse wav incorporato in Windows Form?
Tentativo # 1:
var player = new SoundPlayer();
player.Stream = Resources.ResourceManager.GetStream("mySound");
player.Play(); // Note that Play is asynchronous
- Buono: non blocca il thread UI
- Bad: non SoundPlayer e il flusso risorsa incorporata sono immediatamente smaltiti.
Tentativo # 2:
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.Play();
}
}
- Buono: thread UI non è bloccato, SoundPlayer e flusso di memoria audio vengono immediatamente smaltiti.
- Scorretto: condizioni di gara! Play() è asincrono e se la memoria audio viene eliminata prima che il gioco sia fatto ... boom! Viene generata l'eccezione di runtime.
Tentativo # 3:
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.PlaySync();
}
}
- Buono: Player e flusso audio vengono immediatamente smaltiti.
- Bad: PlaySync blocca il thread UI
Tentativo # 4:
ThreadPool.QueueUserWorkItem(ignoredState =>
{
using (var audioMemory = Resources.ResourceManager.GetStream("mySound"))
{
using (var player = new SoundPlayer(audioMemory))
{
player.PlaySync();
}
}
});
- Buono: interfaccia utente non congelare, giocatore e flusso di memoria vengono immediatamente smaltiti.
- Scorretto: poiché questo si attiva spesso, è possibile che si esauriscano i thread del pool di thread! Vedi Larry Osterman's what's wrong with this code part 26.
Sembra che SoundPlayer abbia un evento PlayAsyncCompleted. Sfortunatamente, nessun evento del genere esiste. Mi sto perdendo qualcosa? Qual è il modo corretto per riprodurre in modo asincrono una risorsa incorporata .wav in Windows Form?
Grazie per il feedback. La mia app è un'app client/server con RPC asincrono, con un suono riprodotto quando un utente remoto invia un messaggio. È esattamente il tipo di problema che Osterman descrive, sfortunatamente. La mia app non è semplice, tuttavia, penso che "riprodurre in modo asincrono un file audio da una risorsa incorporata" sia uno scenario semplice. –
Sono d'accordo che "in modo asincrono la riproduzione di un file audio da una risorsa incorporata" è uno scenario semplice, ma il vostro requisito per riprodurre un suono quando un utente remoto invia un messaggio (dato che è possibile ottenere tonnellate di messaggi) non è così ... Se l'audio è già in riproduzione e arriva un nuovo messaggio. Vuoi (a) ignorare il messaggio perché il suono è già in riproduzione? Se è così, non usare il threadpool, basta usare un thread con nome e se il thread è già in esecuzione, non fare nulla. se il thread non è in esecuzione, avvialo. – BlueShepherd
(b) mettere in coda il suono "SAME" per riprodurlo? in tal caso, ogni volta che ricevi un messaggio, incrementa una variabile condivisa (o, se zero, avvia il thread). nel thread del threadpool, ogni volta che si riproduce il messaggio, decrementa la variabile in loop. (c) mettere in coda un suono diverso? Dovrai creare una coda per "trattenere" i suoni da riprodurre. Metti i suoni in coda quando ricevi un messaggio, toglili quando li suoni – BlueShepherd