Stream Live Android Audio на сервер

В настоящее время я пытаюсь передать streamовое аудио с микрофона с Android-устройства на Java-программу. Я начал с отправки живого звука между двумя устройствами Android, чтобы подтвердить, что мой метод верен. Звук можно было слышать совершенно без всякой задержки на принимающем устройстве. Затем я отправляю один и тот же аудиоstream на небольшую программу Java, и я также подтвердил, что данные также отправляются сюда правильно. Теперь то, что я хочу сделать, это кодировать эти данные и как-то воспроизводить их на сервере, на котором запущена программа Java. Я предпочел бы играть его в веб-браузере, используя HTML5 или JavaScript, но я открыт для альтернативных методов, таких как VLC.

Вот код для Android-приложения, который отправляет аудио в реальном времени

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

И вот код для чтения программы Java в данных.

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

Я знаю, что я должен кодировать аудио на стороне приложения, прежде чем отправлять его в программу Java, но я не уверен, как обойти кодировку при использовании AudioRecorder. Я бы предпочел не использовать NDK, поскольку у меня нет опыта с ним, и у меня нет времени, чтобы узнать, как его использовать …. пока 🙂

Поэтому я решил проблему. Проблема была в основном на принимающей стороне. Приемник принимает аудиоstream и выталкивает его на динамики ПК. В результате голос все еще довольно отсталый и сломанный, но он работает, тем не менее. Игра с размером буфера может улучшить это.

Изменить: вы используете stream для чтения аудио, чтобы избежать лаг. Кроме того, лучше использовать размер выборки 16 000, так как это нормально для голоса.

Код 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:

      

Код сервера:

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

Надеюсь, это поможет спасти кого-то несколько часов боли 🙂

Мои 2 цента на ваш код для повышения эффективности. Хорошая попытка

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

Голос сломан из-за следующей строки в вашем коде Android:

 minBufSize += 2048; 

Вы просто добавляете пустые байты. Кроме того, используйте CHANNEL_IN_MONO вместо CHANNEL_CONFIGURATION_MONO

  • Отображение данных Firebase в ListView
  • Получите вложенный объект JSON с помощью GSON с помощью модифицированной
  • Электронная почта с внутреннего хранилища
  • Почему main () в java void?
  • Захват экрана GLSurfaceView для растрового изображения
  • Есть ли способ получить количество меток чисел, используемых в файле jar
  • Как один интерфейс может использоваться для различных фоновых задач андроида?
  • Как разбить строку, но также сохранить разделители?
  • Как установить задержку в Android?
  • Как я могу профилировать приложение для Android?
  • Изменение цвета фона отдельных элементов меню навигации
  • Давайте будем гением компьютера.