Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream microphone to speakers android

I have been having troubles trying to figure out how to stream the microphone to the speakers with android.

I would like to have a button that turns it on and off.

I found some code, but getting it to work is the issue. If I run this code from a button, it crashes the app. It seems hard to just play the sound from the microphone to the speakers.

Thank you all for your help in advance!

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    // Variables
    private static final String TAG = "Aufnahme";
    private AudioRecord recorder = null;
    private boolean isRecording = false;
    private int SAMPLERATE = 8000;
    private int CHANNELS = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    private int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    private int bufferSize = AudioRecord.getMinBufferSize(SAMPLERATE,           CHANNELS, AUDIO_FORMAT);
private Thread recordingThread = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();

            SetupRecordButton();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

public void SetupRecordButton(){

    Button recordButton = (Button) findViewById(R.id.button);

    recordButton.setOnClickListener(new View.OnClickListener(){

        @Override
        public void onClick(View v) {
            startRecording();
        }
    });
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

public void startRecording() {
    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLERATE,
            CHANNELS, AUDIO_FORMAT, bufferSize);

    recorder.startRecording();
    isRecording = true;

    recordingThread = new Thread(new Runnable()

    {
        public void run() {
            writeAudioData();
        }

    });


    //Start recording thread
    recordingThread.start();

}

public void stopRecording() {
    isRecording = false;
    recorder.stop();
    recorder.release();
    recorder = null;
    recordingThread = null;
}

private void writeAudioData() {

    byte data[] = new byte[bufferSize];

    while (isRecording) {

        recorder.read(data, 0, bufferSize);
        send(data);

    }
}

private void send(byte[] data) {

    int minBufferSize = AudioTrack.getMinBufferSize(8000,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT);

    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
            AudioTrack.MODE_STREAM);

    at.play();
    at.write(data, 0, bufferSize);
    at.stop();
    at.release();

    }
}
like image 647
Shamblen Avatar asked Mar 23 '26 03:03

Shamblen


1 Answers

here is the version reviewed and running well :)

To create it I used the default AndroidStudio Hello World application with activity view (side menu and floating button, in order to imitate your example above). When it runs it has no errors you need some minor modifications in the files:

 

MainActivity.java

package al.tdb.daf;

//Extra import(s)
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    // Variables
    private static final String TAG = "Aufnahme";
    private AudioRecord recorder = null;
    private boolean isRecording = false;
    private int SAMPLERATE = 8000;
    private int CHANNELS = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    private int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    private int bufferSize = AudioRecord.getMinBufferSize(SAMPLERATE, CHANNELS, AUDIO_FORMAT);
    private Thread recordingThread = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        SetupRecordButtons();  //MOVE THIS OUTSIDE ;)

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            // Handle the camera action
        } else if (id == R.id.nav_gallery) {

        } else if (id == R.id.nav_slideshow) {

        } else if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }


    //CUSTOM FUNCTIONS
    //below are all the custom function to perform the operations

    public void SetupRecordButtons(){
        Button startButton = (Button) findViewById(R.id.btnStart);
        startButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                startRecording();
            }
        });

        Button stopButton = (Button) findViewById(R.id.btnStop);
        stopButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                stopRecording();
            }
        });
        stopButton.setEnabled(false);
    }

    public void startRecording() {
        recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLERATE,
                CHANNELS, AUDIO_FORMAT, bufferSize);

        recorder.startRecording();
        isRecording = true;

        recordingThread = new Thread(new Runnable() {
            public void run() {
                writeAudioData();
            }

        });


        //Start recording thread
        recordingThread.start();

        Button startButton = (Button) findViewById(R.id.btnStart);
        startButton.setEnabled(false);
        Button stopButton = (Button) findViewById(R.id.btnStop);
        stopButton.setEnabled(true);
        TextView indicatorLabel = (TextView) findViewById(R.id.indicatorLabel);
        indicatorLabel.setText("recording");
    }

    public void stopRecording() {
        isRecording = false;
        recorder.stop();
        recorder.release();
        recorder = null;
        recordingThread = null;

        Button startButton = (Button) findViewById(R.id.btnStart);
        startButton.setEnabled(true);
        Button stopButton = (Button) findViewById(R.id.btnStop);
        stopButton.setEnabled(false);
        TextView indicatorLabel = (TextView) findViewById(R.id.indicatorLabel);
        indicatorLabel.setText("halted");
    }

    private void writeAudioData() {
        byte data[] = new byte[bufferSize];

        while (isRecording) {
            recorder.read(data, 0, bufferSize);
            send(data);

        }
    }

    private void send(byte[] data) {

        int minBufferSize = AudioTrack.getMinBufferSize(
                8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT
        );

        AudioTrack at = new AudioTrack(
                AudioManager.STREAM_MUSIC,
                8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT,
                minBufferSize,
                AudioTrack.MODE_STREAM
        );

        at.play();
        at.write(data, 0, bufferSize);
        at.stop();
        at.release();

    }
}

 

and

content_main.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/app_bar_main">

    <Button
        android:id="@+id/btnStart"
        android:layout_width="159dp"
        android:layout_height="0dp"
        android:layout_marginStart="101dp"
        android:layout_marginTop="66dp"
        android:layout_marginBottom="186dp"
        android:text="Start"
        app:layout_constraintBottom_toTopOf="@+id/btnStop"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnStop"
        android:layout_width="154dp"
        android:layout_height="0dp"
        android:layout_marginStart="101dp"
        android:layout_marginBottom="94dp"
        android:text="Stop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnStart" />

    <TextView
        android:id="@+id/indicatorLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

with the final result with something like this:

enter image description here

like image 167
oetoni Avatar answered Mar 25 '26 18:03

oetoni