Stream Audio Android en direct vers le serveur

Je tente actuellement de diffuser de l'audio en direct du microphone depuis un appareil Android vers un programme Java. J'ai commencé à envoyer l'audio en direct entre deux périphériques Android pour confirmer que ma méthode était correcte. L'audio peut être entendu parfaitement avec peu de retard sur le périphérique récepteur. Ensuite, j'envoie le même flux audio à un petit programme Java et j'ai vérifié que les données étaient envoyées ici correctement. Maintenant, ce que je veux faire est d'encoder ces données et de les rejouer sur le serveur exécutant le programme Java. Je préfère le jouer dans un navigateur via HTML5 ou JavaScript, mais je suis ouvert à des méthodes alternatives telles que VLC.

Voici le code de l'application Android qui envoie l'audio en direct du microphone

  • Comment obtenir un Fragment à supprimer, c'est-à-dire son équivalent de finition ()?
  • PreferenceFragment.findPreference renvoie toujours NULL
  • Le texte de l'espace réservé pour un type de saisie = "numéro" ne s'affiche pas dans l'ICS Webkit
  • GCM par messagerie instantanée Google par proxy
  • Utilisez l'emplacement de la carte SIM comme lecteur de carte à puce dans les téléphones Android
  • Le graphique Android 9-patch ne mesure pas la vue d'image
  • 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(); } } 

    Et voici le code pour la lecture du programme Java dans les données ..

     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); } } } 

    Je sais que je devrais coder l'audio sur le côté de l'application avant d'envoyer cela au programme Java, mais je ne suis pas sûr de savoir comment procéder à l'encodage lors de l'utilisation d'AudioRecorder. Je préférerais ne pas utiliser NDK car je n'ai aucune expérience avec lui et je n'ai vraiment pas le temps d'apprendre à l'utiliser … encore 🙂

  • Mettez immédiatement en surbrillance sur Android
  • ADB ne reconnaît pas mon appareil
  • Comment basculer sur MTP plus facilement sur un périphérique Android 6.0 de Debug-Enabled?
  • Android obtient l'intention lors de la mise en œuvre RecognitionListener
  • Android: comment mettre un Enum dans un Bundle?
  • Bitmap renvoie null à partir de BitmapFactory.decodeFile (nom de fichier)
  • 3 Solutions collect form web for “Stream Audio Android en direct vers le serveur”

    J'ai donc réglé mon problème. Le problème était principalement du côté récepteur. Le récepteur reçoit le flux audio et le répète sur les haut-parleurs du PC. La voix qui en résulte est encore assez lâche et brisée, mais ça marche néanmoins. Jouer avec la taille du tampon peut améliorer cela.

    Edit: vous utilisez un thread pour lire l'audio afin d'éviter le décalage. En outre, il est préférable d'utiliser une taille d'échantillonnage de 16 000 car il est correct pour la voix.

    Code 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(); } } 

    Android XML:

     <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> 

    Code serveur:

     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(); } } } 

    J'espère que ça aide à sauver quelqu'un quelques heures de douleur 🙂

    Mes 2 cents à votre code pour améliorer l'efficacité. Bien essayé

     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(); } } 

    }

    La voix est cassée en raison de la ligne suivante dans votre code Android:

     minBufSize += 2048; 

    Vous n'ajoutez que des octets vides. Aussi, utilisez CHANNEL_IN_MONO au lieu de CHANNEL_CONFIGURATION_MONO

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.