Search code examples
androidandroid-mediarecorder

Android: Null reference on getMaxAmplitude();


I'm stuck on a new bug in my Android app, getting a null reference error when calling...

"currentAmplitude = mRecorder.getMaxAmplitude();" 

in the following code:

public void useHandler() {
        //setCurrentAmplitude();
        handler = new Handler();
        handler.postDelayed(runnable, 100);
    }

        private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            currentAmplitude = mRecorder.getMaxAmplitude();
            Toast.makeText(getApplicationContext(), "Testing handler",
                    Toast.LENGTH_LONG).show();
            TextView txtPowerLevel = (TextView) findViewById(R.id.txtPowerLevel);
            txtPowerLevel.setText(Integer.toString(currentAmplitude));
            handler.postDelayed(runnable, 100);
        }
    };

I have currentAmplitude declared at the top of my class as:

private int currentAmplitude;

I'm still new to Java and Android and have some trouble with understanding scope, and where things should be declared etc. So I can't help but think I've made a really obvious mistake but I spent hours trying to work this out already and am reaching out for help.

I've mostly tried commenting out lines here and there to see what happens. If I comment out the offending line, the program runs fine, just without the functionality I'm after.

What I'm trying to accomplish right now, is to have the current amplitude displayed in a textview. Mostly just to test audio is working, but I will later use that text view as a kind of counter. I have my camera preview displaying okay on my textureview, and no errors on preparing, starting or stopping my audio capture. I just can't seem to get it to show me the amplitude.

Here's the entire class (below). Please let me know if you can spot what I've done wrong. I'd also really appreciate any additional explanation of why it isn't working, to help me understand the code better to resolve it myself next time.

    public class DBZPowerUp extends AppCompatActivity implements TextureView.SurfaceTextureListener {

    private MediaRecorder mRecorder = null;
    private Handler handler = new Handler();
    private Camera mCamera;
    private int currentAmplitude;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dbzpowerup);

        // Define the textureview in XML and apply the surface listener for camera preview
        TextureView mTextureView = (TextureView) findViewById(R.id.textureView1);
        mTextureView.setSurfaceTextureListener(this);

        // Run methods to start audio capture
        startAudioCapture();
        // getAmplitude();

        // Input the current amplitude level into the power level textview
        //setCurrentAmplitude();
        useHandler();

    }

    public void useHandler() {
        //setCurrentAmplitude();
        handler = new Handler();
        handler.postDelayed(runnable, 100);
    }

        private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            currentAmplitude = mRecorder.getMaxAmplitude();
            Toast.makeText(getApplicationContext(), "Testing handler",
                    Toast.LENGTH_LONG).show();
            TextView txtPowerLevel = (TextView) findViewById(R.id.txtPowerLevel);
            txtPowerLevel.setText(Integer.toString(currentAmplitude));
            handler.postDelayed(runnable, 100);
        }
    };

    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        mCamera = Camera.open();

        try {
            mCamera.setPreviewTexture(surface);
            mCamera.startPreview();
        } catch(IOException e) {
            Log.e("DBZ_", "Camera broke");
        }
        mCamera.setDisplayOrientation(90);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // Ignored, Camera does all the work for us
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        mCamera.stopPreview();
        mCamera.release();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        // Invoked every time there's a new Camera preview frame
    }

    public void startAudioCapture() {
        if (mRecorder == null) {
            MediaRecorder mRecorder = new MediaRecorder();
            mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
            mRecorder.setOutputFile("/dev/null");
            try {
                mRecorder.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mRecorder.start();
        }
        }

    public void stopAudioCapture() {
        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
        }
    }

/*    private void setCurrentAmplitude() {
        if (mRecorder.getMaxAmplitude() > 0) {
            currentAmplitude = mRecorder.getMaxAmplitude();
        } else {
            currentAmplitude = 1;
        }
    }*/

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacks(runnable);
        stopAudioCapture();
    }
}

Solution

  • Your mRecorder object is null

    In this code, you are creating a new MediaRecorder object.

     public void startAudioCapture() {
            if (mRecorder == null) {
                MediaRecorder mRecorder = new MediaRecorder();
    }
    

    Instead create and assign the newly created MediaRecorder object to the globally declared mRecorder variable.

    Like this

         public void startAudioCapture() {
            if (mRecorder == null) {
                mRecorder = new MediaRecorder();
          }