tutorial example audiorecorder android audio streaming audiorecord

example - android audiorecorder tutorial



Problemas de reproducción de Android AudioRecord a Server sobre UDP (2)

Estoy tratando de hacer una aplicación simple de Android que transmita audio de micrófono en vivo a un servidor para su reproducción. La reproducción resultante suena extraña, con grandes espacios en el audio. ¿Alguien sabe lo que estoy haciendo mal?

EDITAR: Resuelto. Resulta que estaba asumiendo que cada búfer entrante estaría completamente lleno, una suposición defectuosa de mi parte.

Aquí está mi actividad:

public class MainActivity extends Activity { private static String TAG = "AudioClient"; // the server information private static final String SERVER = "xx.xx.xx.xx"; private static final int PORT = 50005; // the audio recording options private static final int RECORDING_RATE = 44100; private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO; private static final int FORMAT = AudioFormat.ENCODING_PCM_16BIT; // the button the user presses to send the audio stream to the server private Button sendAudioButton; // the audio recorder private AudioRecord recorder; // the minimum buffer size needed for audio recording private static int BUFFER_SIZE = AudioRecord.getMinBufferSize( RECORDING_RATE, CHANNEL, FORMAT); // are we currently sending audio data private boolean currentlySendingAudio = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "Creating the Audio Client with minimum buffer of " + BUFFER_SIZE + " bytes"); // set up the button sendAudioButton = (Button) findViewById(R.id.start_button); sendAudioButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startStreamingAudio(); break; case MotionEvent.ACTION_UP: stopStreamingAudio(); break; } return false; } }); } private void startStreamingAudio() { Log.i(TAG, "Starting the audio stream"); currentlySendingAudio = true; startStreaming(); } private void stopStreamingAudio() { Log.i(TAG, "Stopping the audio stream"); currentlySendingAudio = false; recorder.release(); } private void startStreaming() { Log.i(TAG, "Starting the background thread to stream the audio data"); Thread streamThread = new Thread(new Runnable() { @Override public void run() { try { Log.d(TAG, "Creating the datagram socket"); DatagramSocket socket = new DatagramSocket(); Log.d(TAG, "Creating the buffer of size " + BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; Log.d(TAG, "Connecting to " + SERVER + ":" + PORT); final InetAddress serverAddress = InetAddress .getByName(SERVER); Log.d(TAG, "Connected to " + SERVER + ":" + PORT); Log.d(TAG, "Creating the reuseable DatagramPacket"); DatagramPacket packet; Log.d(TAG, "Creating the AudioRecord"); recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDING_RATE, CHANNEL, FORMAT, BUFFER_SIZE * 10); Log.d(TAG, "AudioRecord recording..."); recorder.startRecording(); while (currentlySendingAudio == true) { // read the data into the buffer int read = recorder.read(buffer, 0, buffer.length); // place contents of buffer into the packet packet = new DatagramPacket(buffer, read, serverAddress, PORT); // send the packet socket.send(packet); } Log.d(TAG, "AudioRecord finished recording"); } catch (Exception e) { Log.e(TAG, "Exception: " + e); } } }); // start the thread streamThread.start(); } }

Aquí está mi código del lado del servidor:

class Server { AudioInputStream audioInputStream; static AudioInputStream ais; static AudioFormat format; static boolean status = true; static int port = 50005; static int sampleRate = 11025; static int bufferSize = 9728; static Long lastTime; static long totalBytesReceived = 0L; private static final int audioStreamBufferSize = bufferSize * 20; static byte[] audioStreamBuffer = new byte[audioStreamBufferSize]; private static int audioStreamBufferIndex = 0; public static void main(String args[]) throws Exception { Log("Starting the AudioServer..."); Log("Creating the datagram socket on port " + port + "..."); DatagramSocket serverSocket = new DatagramSocket(null); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(port)); Log("Creating the buffer to hold the received data of size " + bufferSize + "..."); byte[] receiveData = new byte[bufferSize]; Log("Setting the audio rate to " + sampleRate + "hz..."); format = new AudioFormat(sampleRate, 16, 1, true, false); Log("Ready to receive audio data"); while (status == true) { DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); bufferAudioForPlayback(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength()); } serverSocket.close(); } private static void bufferAudioForPlayback(byte[] buffer, int offset, int length) { byte[] actualBytes = new byte[length]; for (int i = 0; i < length; i++) { actualBytes[i] = buffer[i]; } for (byte sample : actualBytes) { int percentage = (int) (((double) audioStreamBufferIndex / (double) audioStreamBuffer.length) * 100.0); Log("buffer is " + percentage + "% full"); audioStreamBuffer[audioStreamBufferIndex] = sample; audioStreamBufferIndex++; Log("Buffer " + audioStreamBufferIndex + " / " + audioStreamBuffer.length + " " + percentage); if (audioStreamBufferIndex == audioStreamBuffer.length - 1) { toSpeaker(audioStreamBuffer); audioStreamBufferIndex = 0; System.exit(0); } } } private static void Log(String log) { System.out.println(log); } 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(); sourceDataLine.write(soundbytes, 0, soundbytes.length); sourceDataLine.drain(); sourceDataLine.close(); } catch (Exception e) { System.out.println("Error with audio playback: " + e); e.printStackTrace(); } } }

Finalmente, aquí está el archivo xml de recursos para la actividad principal:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="20dip"> <ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" android:scaleType="fitCenter"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/app_info" android:layout_weight="1.0" android:textSize="20dip"/> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnStart" android:text="@string/start_recording" android:layout_weight="1.0"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnStop" android:text="@string/stop_recording" android:layout_weight="1.0"/> </LinearLayout> </LinearLayout>

EDITAR: el audio de reproducción suh-suh-suh-suh-o-ou-ou-ou-nds-nds-ds como este.


Aquí hay algo que puedes probar, en lugar de:

// read the data into the buffer recorder.read(buffer, 0, buffer.length); // place contents of buffer into the packet packet = new DatagramPacket(buffer, buffer.length, serverAddress, PORT);

No espere que haya recibido el búfer de lectura completa de la recorder pero utilice el valor de lectura real en su lugar

// read the data into the buffer int read = recorder.read(buffer, 0, buffer.length); // place contents of buffer into the packet packet = new DatagramPacket(buffer, read, serverAddress, PORT);

O algo parecido.


Gracias por publicar Joshua .... gran ayuda para las nuevas abejas :)

volumeControl.setValue(volumeControl.getMaximum()); removes illegalStateException at Server

y permiso en el cliente de Android

<uses-permission android:name="android.permission.RECORD_AUDIO"/>