0

I am making an app on Android studio, which records sound using the mic and simultaneously converts it to decibel values on another thread. I need to stop the process when the stopRecord function is called, and hence I want to stop the thread in the stopRecord function. I am using a static class variable for this, whose value I set to "1" when stopRecord is called. By default, the value of the variable is "0", in which case the thread must continue to run in a loop. However, the variable's value always sets to "1" unexpectedly even before the Run method of the runnable is called, which is evident if you run the file and see the Log.i . As a result, the loop in the run() of the runnable is not even entered, and the runnable runs only once. I seriously don't know why the value is changing, and any help would be greatly appreciated.

package com.example.rohanbs.soundtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.view.View;
import android.os.Handler;
import android.util.Log;
import android.media.MediaRecorder;

public class MainActivity extends AppCompatActivity {

    TextView mStatusView;

    private static double mEMA = 0.0;
    static final private double EMA_FILTER = 0.6;

    static String decider="0";
    private dbRunnable newdb = new dbRunnable();
    MediaRecorder recorder;

    class dbRunnable implements Runnable{

        @Override
        public void run(){
            Log.i("Runnable","called");  //Log to see if runnable is called successfully
            Log.i("decider",decider);   //decider is supposed to be "0" until stopRecord is called, but somehow becomes "1" before that 
            while(true){
                Log.i("Runnable","called");
                if(decider=="1"){
                    break;
                }
            }
        }

    }


    public void startRecord(View view) {
        Log.i("Inside", "start record");
        if (recorder == null) {
            recorder = new MediaRecorder();
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setOutputFile("/dev/null");
            try {
                recorder.prepare();
            } catch (java.io.IOException ioe) {
                android.util.Log.e("[Monkey]", "IOException: " +
                        android.util.Log.getStackTraceString(ioe));

            } catch (java.lang.SecurityException e) {
                android.util.Log.e("[Monkey]", "SecurityException: " +
                        android.util.Log.getStackTraceString(e));
            }
            try {
                recorder.start();
                Thread dec1 = new Thread(newdb);   //Creating new thread
                dec1.start();                      //Starting the runnable

            } catch (java.lang.SecurityException e) {
                android.util.Log.e("[Monkey]", "SecurityException: " +
                        android.util.Log.getStackTraceString(e));
            }
        }
    }
    public void stopRecord(View view){
        if (recorder != null) {
            recorder.stop();
            recorder.release();
            recorder = null;
        }

        decider="1";

        Log.i("Hello","record complete");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void updateTv(){
        mStatusView.setText(Double.toString((getAmplitudeEMA())) + " dB");
    }
    public double soundDb(double ampl){
        return  20 * Math.log10(getAmplitudeEMA() / ampl);
    }
    public double getAmplitude() {
        if (recorder != null)
            return  (recorder.getMaxAmplitude());
        else
            return 0;

    }
    public double getAmplitudeEMA() {
        double amp =  getAmplitude();
        mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
        return mEMA/100;
    }

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }
}
  • A) hint: study Java **basics** before going for such advanced stuff. You really should **know** that you should not use == to compare objects, but calling the `equals()` method! B) I would also advise to *not* use a string like that, but a boolean with a nice name, like `private volatile keepLooping` and C) read about `volatile` – GhostCat Sep 09 '17 at 05:31

2 Answers2

0

Try creating a boolean call "recording" instead of the string. Set it to false once called...etc. You only call stopRecord() on the button click? Where else do you set the decider value?

king_abu1918
  • 284
  • 2
  • 6
  • I've already tried using a boolean value, and also int; all of them give the same problem. I call stopRecord() only on button click, no where else. – Rohan B Sahu Sep 09 '17 at 02:56
  • If you start with the boolean at false, then when you start recording you set it to true, when you press stopRecord() the boolean doesn't change? I know it is not set to 1. Try removing the static in your declaration. – king_abu1918 Sep 09 '17 at 03:12
0

From what I can tell of your code, you set the variable once to "0" and never reset it. So if you were to start, stop, and start again, the value would never be "0" again. A simple fix is to ensure you are always resetting this variable before starting a new recording:

recorder.start();
decider = "0"; // Reset control variable before starting thread
Thread dec1 = new Thread(newdb);   //Creating new thread
dec1.start();   

Your logic to break the while loop is wrong, btw.

if (decider == "1") {
    break;
}

In Java == means reference equality, so this will almost certainly be false always. Do "1".equals(decider) instead (notice the order to avoid a NullPointerException).

Hope that helps!

dominicoder
  • 9,338
  • 1
  • 26
  • 32