View Full Version : c# streaming audio
dyablo96
30-07-2014, 16:12
buon giorno a tutti, sto cercando di creare un programma in c# che mi permetta di riprodurre l'audio in entrata sul microfono del pc sul un altro ipotetico pc sulla stessa rete come se fosse una cassa.
ho cercato online ed ho trovato NAudio, una utilissima libreria.
per il momento sono riuscito a fare in modo che l'audio in entrata sul microfono venga salvato sotto forma di file.
ora io vorrei sostituire al salvataggio venga fatto partire lo streaming attraverso la rete fino ad arrivare all'host che dovrà riprodurre.
questo è il codice fino ad ora:
static WaveFormat waveFormat = new WaveFormat(44100, 8, 1);
WaveFileWriter writer = new WaveFileWriter("nomeFile", waveFormat);
WaveIn waveIn = new WaveIn();
private void BtnStartRecording_Click(object sender, RoutedEventArgs e)
{
int waveInDevices = WaveIn.DeviceCount;
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
MessageBox.Show("Device found\n" + waveInDevice + ": " + deviceInfo.ProductName + ", "+ deviceInfo.Channels +" channels");
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += waveIn_DataAvailable;
waveIn.WaveFormat = new WaveFormat(44100, 1);
writer = new WaveFileWriter("uno.wav", waveIn.WaveFormat);
waveIn.StartRecording();
}
}
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
if (writer == null)
return;
writer.WriteData(e.Buffer, 0, e.BytesRecorded);
writer.Flush();
}
private void BtnStop_Click(object sender, RoutedEventArgs e)
{
if (waveIn != null)
{
waveIn.StopRecording();
waveIn.Dispose();
waveIn = null;
}
if(writer != null)
{
writer.Dispose();
writer = null;
}
}
grazie in anticipo a tutti quelli che mi aiuteranno :)
dyablo96
31-07-2014, 08:44
Nessuno?
dyablo96
01-08-2014, 08:44
Up
Daniels118
01-08-2014, 11:49
Non conosco il c#, però suppongo che basterebbe sostituire il WaveFileWriter con un socket. Ovviamente dovrai creare un programma complementare che legga i dati dal socket e li invii al dispositivo di riproduzione.
Naturalmente stai facendo qualcosa a livello sperimentale, perché senza applicare un algoritmo di compressione consumi una banda enorme.
Sicuramente esistono librerie per lo streaming audio in c#, prova a fare una ricerca in rete.
dyablo96
01-08-2014, 18:44
Scusa ma non conosco i società, potresti spiegarmi cosa sono e come funzionano, magari anche in un altro linguaggio, io poi cerco per il c#.
Ovviamente dovrò creare una applicazione per la ricezione dei dati.
Si, é tutto a livello sperimentale.
Per quanto riguarda la compressione dei consumi non saprei come fare se hai qualche idea suggerisci pure anche in altri linguaggi.
Ho provato a cercare ma con scarsi risultati, proverò a cercare in modo ancora più approfondito :)
dyablo96
01-08-2014, 18:45
Socket non società, correttore automatico di merd* :P
Daniels118
01-08-2014, 19:05
Socket non società, correttore automatico di merd* :P
Leggendo quella parola mi stava venendo un infarto :D
I socket sono un meccanismo software che consente l'utilizzo della rete attraverso il protocollo IP. In particolare a te serve un socket TCP, ovvero un meccanismo che ti mette a disposizione uno stream. Per stream si intende un flusso continuo e ordinato di dati.
Immagina che la rete sia un tubo, ad un'estremità inserisci delle biglie, dall'altro lato le biglie usciranno nello stesso ordine in cui sono entrate. Se al posto delle biglie inserisci WaveInEventArgs.Buffer, dall'altro lato usciranno i byte che rappresentano il segnale audio.
Quando utilizzi un socket ci sono sempre due parti: il client e il server.
Prima di tutto il server si mette in ascolto su una porta.
Il client effettua una connessione specificando l'indirizzo ip e la porta del server. Se il server lo consente, più client possono connettersi contemporaneamente.
La connessione è bidirezionale (sia il client che il server possono inviare e ricevere i dati), una volta stabilita non c'è più differenza tra client e server, di seguito li chiamerò semplicemente "parti".
Supponiamo che la parte A invii dati a B; in B si verificherà un evento, proprio come "waveIn_DataAvailable", non lo chiama nessuno, si scatena da solo. In alternativa B può fare un loop per controllare quando sono disponibili i dati, oppure fare una lettura bloccante (cioè chiama il metodo di lettura e l'operazione si blocca finché non ci sono dati disponibili).
B legge i dati e li elabora, per esempio mandandoli sul buffer di output della periferica di riproduzione.
dyablo96
01-08-2014, 19:13
ah ok, ho capito :)
è come se creassi una connessione tcp tra i due host e iniziano a scambiarsi i dati.
ok, la parte relativa alla rete la conosco, so come funzionano tcp udp ecc ecc, questanno ho fatto la prima delle certificazioni cisco e diciamo che questi erano all'ordine del giorno :D :D :D
non li avevo mai visti applicati ad un programma, adesso cercherò come creare la connessione e passare i dati.
sul come ridurre i consumi sulla banda sai dirmi niente? se vuoi puoi farmi degli esempi anche con altri linguaggi, c, java ecc ecc.
intanto grazie :D
EDIT:
avrei un altra domanda, sto leggnedo online come fare connessioni con socket, ci sono due tipi di connessioni, sincroni e asincroni, io avrei pensato di costruire il programma in modo asincrono così che i due programmi non debbanno bloccarsi e proseguire in parallelo, secondo te è azzecata la mia scelta?.
leggo online che nel pc ricevente avverà un evento ricezione come dici te, che però sarà bloccante, quindi fermerà il programma fino a che non avrà ricevuto tutti i dati.
io però vorrei fare in modo che quando arrivano i dati vengano subito riprodotti e avrei pensato di fare così per risolvere.
sul pc B faccio partire il programma per la ricezione dei dati.
il programma crea un thread che resta in ascolto ed in attesa dei dati.
ora iniziano ad arrivare i dati
il thread inizia a ricevere ed eleaborare le informazioni salvandole sul pc B
un secondo thread iniziera a leggere le informazioni scritte sul disco dal primo thread e a riprodurle.
dici che così potrebbe funzionare?
Daniels118
01-08-2014, 19:34
La compressione è un argomento abbastanza vasto, si tratta fondamentalmente di ridurre la dimensione dei dati senza alterarne*** il contenuto. Esistono svariati algoritmi, alcuni detti lossless (letteralmente "senza perdita") che consentono di ricostruire i dati esattamente com'erano prima (esempi: zip, png), ed altri detti lossy che invece consentono di ricostruire un'approssimazione del dato originale (per esempio jpeg, mp3).
Prima di tutto ti mostro un esempio in pseudocodice di come dovrebbe venire:
waveIn_DataAvailable(dati) {
dati_compressi = comprimi(dati);
socket.invia(dati_compressi);
}
socket_DataAvailable(dati_compressi) {
dati = decomprimi(dati_compressi);
waveOut.scrivi(dati);
}
le funzioni comprimi e decomprimi dipendono dall'algoritmo di compressione scelto. Se vuoi divertirti un po' ti consiglio di utilizzare l'ADPCM che è un algoritmo di compressione utilizzato in telefonia, è abbastanza semplice sia da comprendere che da implementare.
Se non vuoi scrivere tu l'algoritmo puoi affidarti a librerie già pronte che puoi sicuramente trovare in rete.
dyablo96
01-08-2014, 19:36
le funzioni comprimi e decomprimi dipendono dall'algoritmo di compressione scelto. Se vuoi divertirti un po' ti consiglio di utilizzare l'ADPCM che è un algoritmo di compressione utilizzato in telefonia, è abbastanza semplice sia da comprendere che da implementare.
Se non vuoi scrivere tu l'algoritmo puoi affidarti a librerie già pronte che puoi sicuramente trovare in rete.
ok, grazie, ora guardo anche come funziona questo algoritmo di compressione.
credo che costruirò io la funzione all'interno di una classe compressione.
dyablo96
02-08-2014, 14:24
E per il fatto del trasferimento dati che ho descritto prima dici che possa funzionare?
Daniels118
02-08-2014, 15:35
Il c# è un linguaggio di altissimo livello, ha sicuramente la possibilità di gestire i socket con gli eventi, quindi non hai bisogno di avviare un thread per utilizzare la modalità non bloccante.
Cosa molto più importante, non devi assolutamente scrivere il dati su disco, ma devi inviarli direttamente al buffer di riproduzione.
dyablo96
02-08-2014, 18:41
Ok grazie :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.