2012-02-11 20 views
29

Sto provando a trasmettere l'audio dal microfono da 1 Android a un altro tramite WiFi. Dopo aver esaminato alcuni esempi, ho realizzato 2 applicazioni con una singola attività in ciascuna, 1 per acquisire e inviare audio e l'altra per ricevere.Streaming voce tra telefoni Android tramite WiFi

Ho utilizzato le classi Audiorecord e Audiotrack per acquisire e riprodurre. Tuttavia, sento solo alcuni suoni scoppiettanti (che ora si sono fermati dopo aver apportato alcune modifiche anche se sono tornato indietro)

L'attività per inviare la voce.

public class VoiceSenderActivity extends Activity { 

private EditText target; 
private TextView streamingLabel; 
private Button startButton,stopButton; 

public byte[] buffer; 
public static DatagramSocket socket; 
private int port=50005;   //which port?? 
AudioRecord recorder; 

//Audio Configuration. 
private int sampleRate = 8000;  //How much will be ideal? 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  

private boolean status = true; 




@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    target = (EditText) findViewById (R.id.target_IP); 
    streamingLabel = (TextView) findViewById(R.id.streaming_label); 
    startButton = (Button) findViewById (R.id.start_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 

    streamingLabel.setText("Press Start! to begin"); 

    startButton.setOnClickListener (startListener); 
    stopButton.setOnClickListener (stopListener); 
} 

private final OnClickListener stopListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
       status = false; 
       recorder.release(); 
       Log.d("VS","Recorder released"); 
    } 

}; 

private final OnClickListener startListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
       status = true; 
       startStreaming();   
    } 

}; 

public void startStreaming() { 


    Thread streamThread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      try { 


       int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 
       DatagramSocket socket = new DatagramSocket(); 
       Log.d("VS", "Socket Created"); 

       byte[] buffer = new byte[minBufSize]; 

       Log.d("VS","Buffer created of size " + minBufSize); 
       DatagramPacket packet; 

       final InetAddress destination = InetAddress.getByName(target.getText().toString()); 
       Log.d("VS", "Address retrieved"); 


       recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize); 
       Log.d("VS", "Recorder initialized"); 

       recorder.startRecording(); 


       while(status == true) { 


        //reading data from MIC into buffer 
        minBufSize = recorder.read(buffer, 0, buffer.length); 

        //putting buffer in the packet 
        packet = new DatagramPacket (buffer,buffer.length,destination,port); 

        socket.send(packet); 


       } 



      } catch(UnknownHostException e) { 
       Log.e("VS", "UnknownHostException"); 
      } catch (IOException e) { 
       Log.e("VS", "IOException"); 
      } 


     } 

    }); 
    streamThread.start(); 
} 
} 

L'attività di ricevere voce

public class VoiceReceiverActivity extends Activity { 


private Button receiveButton,stopButton; 

public static DatagramSocket socket; 
private AudioTrack speaker; 

//Audio Configuration. 
private int sampleRate = 8000;  //How much will be ideal? 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  

private boolean status = true; 


@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    receiveButton = (Button) findViewById (R.id.receive_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 
    findViewById(R.id.receive_label); 

    receiveButton.setOnClickListener(receiveListener); 
    stopButton.setOnClickListener(stopListener); 

} 


private final OnClickListener stopListener = new OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     status = false; 
     speaker.release(); 
     Log.d("VR","Speaker released"); 

    } 

}; 


private final OnClickListener receiveListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
     status = true; 
     startReceiving(); 

    } 

}; 

public void startReceiving() { 

    Thread receiveThread = new Thread (new Runnable() { 

     @Override 
     public void run() { 

      try { 

       DatagramSocket socket = new DatagramSocket(50005); 
       Log.d("VR", "Socket Created"); 


       byte[] buffer = new byte[256]; 


       //minimum buffer size. need to be careful. might cause problems. try setting manually if any problems faced 
       int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 

       speaker = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate,channelConfig,audioFormat,minBufSize,AudioTrack.MODE_STREAM); 

       speaker.play(); 

       while(status == true) { 
        try { 


         DatagramPacket packet = new DatagramPacket(buffer,buffer.length); 
         socket.receive(packet); 
         Log.d("VR", "Packet Received"); 

         //reading content from packet 
         buffer=packet.getData(); 
         Log.d("VR", "Packet data read into buffer"); 

         //sending data to the Audiotrack obj i.e. speaker 
         speaker.write(buffer, 0, minBufSize); 
         Log.d("VR", "Writing buffer content to speaker"); 

        } catch(IOException e) { 
         Log.e("VR","IOException"); 
        } 
       } 


      } catch (SocketException e) { 
       Log.e("VR", "SocketException"); 
      } 


     } 

    }); 
    receiveThread.start(); 
} 

} 

ho usato Wireshark per verificare se i pacchetti vengono inviati e posso vedere i pacchetti. Tuttavia, la fonte è l'indirizzo MAC del dispositivo mittente e anche la destinazione è qualcosa come un indirizzo fisico. Non sono sicuro se questo è rilevante però.

Quindi qual è il problema?

+1

Ci sono almeno tre problemi che devi affrontare: dati ritardati (o mancanti), throughput di dati complessivo e possibilità di frequenze di campionamento leggermente disadattate. La telefonia IP pratica deve avere un mezzo per gestire tutte e tre le cose. Gli orologi non corrispondenti sono sorprendentemente complessi: inizialmente è possibile introdurre un ritardo per fornire una tolleranza di bufferizzazione, ma se il mittente è più lento si utilizzerà il buffer e il ricevitore sarà affamato di dati; mentre se il mittente è più veloce il buffer finirà per traboccare con dati non riprodotti. –

+0

Sono riuscito a farlo funzionare davvero. Non ha avuto un problema di frequenze non corrispondenti. Ritardo nei dati, sì. Aveva una specie di protocollo per abbinare gli orologi ricevitore/mittente. Alla fine ha funzionato, ma solo con un certo ritardo (che è aumentato con la distanza dal router wireless) – Alabhya

+0

Ehi lì, ho implementato un'applicazione di test per il codice che hai sopra, facendo tutte le modifiche necessarie suggerite di seguito, ma ho ancora un problema . Non sto ottenendo comunicazioni tra i due telefoni senza problemi, ma non credo che il microfono stia registrando correttamente perché non sento alcun suono dall'altra parte. Hai forse un link ad una soluzione campione che potrei dare un'occhiata? – chuckliddell0

risposta

3

Vorrei provare a dividere il problema in Tre parti.

Parte 1

assicurarsi che la connessione Socket funziona bene commentando tutto ciò che riguarda l'audio

Parte 2

Invia semplicemente un testo arbitrario messaggio [Inferno o WiFi] dal mittente, quindi ricevendolo e stampandolo nell'applicazione lato ricevitore.

Parte 3

Se il registratore è in realtà di lavoro? prova a testare il tuo modo di registrazione in un progetto separato per vedere se funziona correttamente o no.

Utilizzare il codice this per acquisire il microfono e riprodurlo.

La mia esperienza

una volta ho lavorato su un progetto simile e per testarlo, quello che ho fatto è stato dopo la registrazione che ho scritto i dati audio registrati in un file sul sdcard

(si sarebbe raw audio, quindi molti lettori musicali non saranno in grado di riprodurlo ... mPlayer dovrebbe riprodurlo suppongo)

+0

Ok ho capito. La voce si rompe troppo e non c'è lag. È necessario trovare la frequenza di campionamento e la dimensione del buffer corrette per questo. Sarebbe bello se ci fossero degli input su questo. Comunque, grazie mille. quello che hai detto ha aiutato. – Alabhya

+0

Nell'attività del ricevitore, nel metodo startReceiving() non utilizzare 256 come dimensione del buffer, ma utilizzare il minBufSize che si ottiene nella riga successiva. Oltre a questo, potrebbe voler giocare un po 'con diverse frequenze di campionamento, ma anche 8k dovrebbe essere buono. –

+1

Ok ho capito. Apparentemente il minBufSize era troppo e quindi il ritardo e la rottura. Impostare minBufSize su 256 e mentre inizializzando gli oggetti AudioRecord e AudioTrack impostare la dimensione del buffer su minBufSize * 10. Ho provato diverse combinazioni di frequenze di campionamento e questo e ne ho ottenuto uno soddisfacente ora. Grazie mille! – Alabhya

2

È necessario considerare attentamente l'utilizzo di UDP (classe DatagramSocket) come protocollo di rete.

UDP è un protocollo leggero che non garantisce il mantenimento dell'ordine dei pacchetti ricevuti. Questo potrebbe essere parte del motivo per cui l'audio è confuso.Un pacchetto ricevuto fuori ordine comporterà la riproduzione di pacchetti audio degni di un ordine. Al confine di questi pacchetti fuori sequenza sentirai clic/pop in cui il campione audio è effettivamente corrotto. Inoltre, non è garantito che i pacchetti UDP vengano consegnati correttamente. Eventuali pacchetti rilasciati si aggiungeranno ovviamente a qualsiasi alterazione o distorsione udibile.

TCP (classe Socket) sarebbe un'opzione migliore per una qualità audio ottimale. TCP è un protocollo più robusto che manterrà l'ordine di ricezione dei pacchetti. Ha anche un controllo degli errori integrato e rinvierà ogni pacchetto scartato. Tuttavia, a causa di questa funzionalità attenzionale, TCP ha un overhead di rete più elevato.

Ho iniziato questa risposta dicendo che è necessario considerare attentamente quale protocollo si utilizza. Ciò è dovuto all'utilizzo di entrambi in base a ciò che è importante per te.

Se desideri una riproduzione a latenza ultra bassa ma sei felice di sacrificare la qualità dell'audio, allora UDP funzionerà. Tuttavia, saranno necessari alcuni esperimenti per trovare il miglior buffer e la dimensione del campione.

Se si desidera la migliore riproduzione audio possibile con distorsione zero, ma sono lieti di introdurre un po 'più di latenza, TCP è la strada da percorrere.

Non riesco a dire quanta più latenza aggiungerebbe. Ma è possibile che possa essere implementato senza influire sull'esperienza dell'utente. L'unico modo per scoprirlo è provarlo e vedere.

7

Hey c'è una libreria Open Source chiamata "Libstreaming" che viene utilizzata per lo streaming di voce/video sulla rete tramite WIFI. Basta dare un'occhiata a questo:

https://github.com/fyhertz/libstreaming

ci sono anche alcuni esempi forniti, hanno gentilmente un'occhiata a questo:

https://github.com/fyhertz/libstreaming-examples

ho usato la biblioteca di flusso RTSP audio sopra la rete, spero che possa essere utile.

+0

Puoi guidare, come hai fatto solo lo streaming audio senza lo streaming video? – kAmol

Problemi correlati