2013-03-11 29 views
46

Attualmente sto cercando di trasmettere l'audio del microfono dal vivo da un dispositivo Android a un programma Java. Ho iniziato con l'invio dell'audio in tempo reale tra due dispositivi Android per confermare che il mio metodo era corretto. L'audio potrebbe essere ascoltato perfettamente con quasi nessun ritardo sul dispositivo ricevente. Successivamente invio lo stesso flusso audio a un piccolo programma Java e ho verificato che i dati siano stati inviati anche qui correttamente. Ora quello che voglio fare è codificare questi dati e in qualche modo riprodurli sul server che esegue il programma Java. Preferisco giocare su un browser web usando HTML5 o JavaScript, ma sono aperto a metodi alternativi come VLC.Stream live audio Android al server

ecco il codice per l'applicazione Android che invia l'audio live microfono

public class MainActivity extends Activity { 


private Button startButton,stopButton; 

public byte[] buffer; 
public static DatagramSocket socket; 
    AudioRecord recorder; 

private int sampleRate = 44100; 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 
    private boolean status = true; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    startButton = (Button) findViewById (R.id.start_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 

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

    minBufSize += 2048; 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.main, menu); 
    return true; 
} 

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{ 

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

       byte[] buffer = new byte[minBufSize]; 

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


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


       recorder.startRecording(); 


       InetAddress IPAddress = InetAddress.getByName("192.168.1.5"); 
       byte[] sendData = new byte[1024]; 
       byte[] receiveData = new byte[1024]; 


       while (status == true) 
       { 
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 50005); 
        socket.send(sendPacket); 
       } 

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


     } 

    }); 
    streamThread.start(); 
} 
} 

Ed ecco il codice per la lettura programma Java nei dati ..

class Server 
{ 
    public static void main(String args[]) throws Exception 
     { 
     DatagramSocket serverSocket = new DatagramSocket(50005); 
      byte[] receiveData = new byte[1024]; 
      byte[] sendData = new byte[1024]; 
      while(true) 
       { 
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); 



       serverSocket.receive(receivePacket); 
       String sentence = new String(receivePacket.getData().toString()); 

       System.out.println("RECEIVED: " + sentence); 
      } 
    } 
} 

So che Dovrei codificare l'audio sul lato app prima di inviarlo al programma Java, ma non sono sicuro di come procedere con la codifica durante l'utilizzo di AudioRecorder. Preferirei non utilizzare NDK perché non ho esperienza con esso e non ho davvero tempo per imparare come usarlo .... ancora :)

+0

Che cosa hai utilizzato per l'audio in streaming? Lo voglio solo per un modo. – Atieh

+0

Mi interessa scrivere un'app per Android che trasmetta l'audio del microfono dal vivo da un dispositivo Android a un'applicazione desktop. Potresti fornire alcuni suggerimenti utili su alcune risorse correlate ai contenuti che hai postato? Sarebbe immensamente utile! Grazie! :) – wayway

+0

Come hai fatto audio dal vivo tra due dispositivi Android? – pkBhati

risposta

47

Quindi ho risolto il problema. Il problema era principalmente dal lato ricevente. Il ricevitore acquisisce il flusso audio e lo invia agli altoparlanti del PC. La voce risultante è ancora abbastanza arretrata e rotta, ma funziona comunque. Giocare con la dimensione del buffer può migliorare questo.

Modifica: si utilizza un thread per leggere l'audio in modo da evitare il ritardo. Inoltre, è preferibile utilizzare una dimensione di campionamento di 16 000 come è ok per la voce.

Codice Android:

package com.example.mictest2; 

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 
import java.net.UnknownHostException; 

import android.app.Activity; 
import android.media.AudioFormat; 
import android.media.AudioRecord; 
import android.media.MediaRecorder; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 

public class Send extends Activity { 
private Button startButton,stopButton; 

public byte[] buffer; 
public static DatagramSocket socket; 
private int port=50005; 

AudioRecord recorder; 

private int sampleRate = 16000 ; // 44100 for music 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 
private boolean status = true; 


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

    startButton = (Button) findViewById (R.id.start_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 

    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 { 

       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("192.168.1.5"); 
       Log.d("VS", "Address retrieved"); 


       recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize*10); 
       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); 
        System.out.println("MinBufferSize: " +minBufSize); 


       } 



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

    }); 
    streamThread.start(); 
} 
} 

XML Android: codice

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:paddingBottom="@dimen/activity_vertical_margin" 
android:paddingLeft="@dimen/activity_horizontal_margin" 
android:paddingRight="@dimen/activity_horizontal_margin" 
android:paddingTop="@dimen/activity_vertical_margin" 
tools:context=".MainActivity" > 

<TextView 
    android:id="@+id/textView1" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="@string/hello_world" /> 

<Button 
    android:id="@+id/start_button" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_below="@+id/textView1" 
    android:layout_centerHorizontal="true" 
    android:layout_marginTop="130dp" 
    android:text="Start" /> 

<Button 
    android:id="@+id/stop_button" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignLeft="@+id/button1" 
    android:layout_below="@+id/button1" 
    android:layout_marginTop="64dp" 
    android:text="Stop" /> 

</RelativeLayout> 

Server:

package com.datagram; 

import java.io.ByteArrayInputStream; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.FloatControl; 
import javax.sound.sampled.SourceDataLine; 

class Server { 

AudioInputStream audioInputStream; 
static AudioInputStream ais; 
static AudioFormat format; 
static boolean status = true; 
static int port = 50005; 
static int sampleRate = 44100; 

public static void main(String args[]) throws Exception { 


    DatagramSocket serverSocket = new DatagramSocket(50005); 


    byte[] receiveData = new byte[1280]; 
    // (1280 for 16 000Hz and 3584 for 44 100Hz (use AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) to get the correct size) 

    format = new AudioFormat(sampleRate, 16, 1, true, false); 

    while (status == true) { 
     DatagramPacket receivePacket = new DatagramPacket(receiveData, 
       receiveData.length); 

     serverSocket.receive(receivePacket); 

     ByteArrayInputStream baiss = new ByteArrayInputStream(
       receivePacket.getData()); 

     ais = new AudioInputStream(baiss, format, receivePacket.getLength()); 

     // A thread solve the problem of chunky audio 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       toSpeaker(receivePacket.getData(), sourceDataLine); 
      } 
     }).start(); 
    } 
} 

public static void toSpeaker(byte soundbytes[]) { 
    try { 

     DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format); 
     SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo); 

     sourceDataLine.open(format); 

     FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN); 
     volumeControl.setValue(100.0f); 

     sourceDataLine.start(); 
     sourceDataLine.open(format); 

     sourceDataLine.start(); 

     System.out.println("format? :" + sourceDataLine.getFormat()); 

     sourceDataLine.write(soundbytes, 0, soundbytes.length); 
     System.out.println(soundbytes.toString()); 
     sourceDataLine.drain(); 
     sourceDataLine.close(); 
    } catch (Exception e) { 
     System.out.println("Not working in speakers..."); 
     e.printStackTrace(); 
    } 
} 
} 

Spero che questo aiuta a risparmiare qualcuno un paio d'ore di dolore :)

+0

Questo crea un jitter costante e le voci non sono chiare. Cosa si può fare? – kittu88

+0

hai inviato il tuo flusso vocale da un dispositivo Android a più dispositivi Android tramite server che è proprio come una conversazione di gruppo. Sto cercando di impararlo ma non ho trovato nulla. Mi aiuteresti? –

+0

posso contattare con voi ?? –

12

I miei 2 cent al codice per migliorare l'efficienza. Bel tentativo

package com.datagram; 

import java.io.ByteArrayInputStream; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.FloatControl; 
import javax.sound.sampled.SourceDataLine; 

class Server { 

AudioInputStream audioInputStream; 
static AudioInputStream ais; 
static AudioFormat format; 
static boolean status = true; 
static int port = 50005; 
static int sampleRate = 44100; 

static DataLine.Info dataLineInfo; 
static SourceDataLine sourceDataLine; 

public static void main(String args[]) throws Exception { 

    DatagramSocket serverSocket = new DatagramSocket(port); 

    /** 
    * Formula for lag = (byte_size/sample_rate)*2 
    * Byte size 9728 will produce ~ 0.45 seconds of lag. Voice slightly broken. 
    * Byte size 1400 will produce ~ 0.06 seconds of lag. Voice extremely broken. 
    * Byte size 4000 will produce ~ 0.18 seconds of lag. Voice slightly more broken then 9728. 
    */ 

    byte[] receiveData = new byte[4096]; 

    format = new AudioFormat(sampleRate, 16, 1, true, false); 
    dataLineInfo = new DataLine.Info(SourceDataLine.class, format); 
    sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo); 
    sourceDataLine.open(format); 
    sourceDataLine.start(); 

    FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN); 
    volumeControl.setValue(1.00f); 

    DatagramPacket receivePacket = new DatagramPacket(receiveData, 
      receiveData.length); 
    ByteArrayInputStream baiss = new ByteArrayInputStream(
      receivePacket.getData()); 
    while (status == true) { 
     serverSocket.receive(receivePacket); 
     ais = new AudioInputStream(baiss, format, receivePacket.getLength()); 
     toSpeaker(receivePacket.getData()); 
    } 
    sourceDataLine.drain(); 
    sourceDataLine.close(); 
} 

    public static void toSpeaker(byte soundbytes[]) { 
     try { 
      sourceDataLine.write(soundbytes, 0, soundbytes.length); 
     } catch (Exception e) { 
      System.out.println("Not working in speakers..."); 
      e.printStackTrace(); 
     } 
    } 
} 
+0

mi aiuta davvero a ridurre il rumore? –

3

La voce è rotta a causa del seguente riga nel codice Android:

minBufSize += 2048; 

Sei solo l'aggiunta di byte vuoti. Inoltre, utilizza CHANNEL_IN_MONO anziché CHANNEL_CONFIGURATION_MONO