Search code examples
androidandroid-mediarecorder

Show current audio amplitude in textview


I think I am fairly close to achieving what I need to, but I'm getting an error when trying to convert my current amplitude integer into a string in a textview.

So my aim is this: Display a camera preview (working), detect sound (possibly working) and display the current amplitude level of that sound in a textview (textPowerUp). Later I want to replace the textview with a counter that counts up when sound is detected, and slowly counts back down when it's not, but baby steps...

So no errors if I comment out the line:

txtPowerLevel.setText(Integer.toString(currentAmplitude));

But that's the line I'm -trying- to use to convert the amplitude integer into a string and insert it into my textview. And this line gives a null reference error.

I even tried to force the currentAmplitude to have a value of at least 0 with:

if (mRecorder.getMaxAmplitude() > 0) {
    currentAmplitude = mRecorder.getMaxAmplitude();
} else {
    currentAmplitude = 0;
}

But that doesn't seem to help. I still get a null reference error. I even tried setting the else to a value of '1' incase '0' was being seen as 'null' but no luck there either.

Here's the entire class... please let me know if you can spot the problem!

public class DBZPowerUp extends AppCompatActivity implements TextureView.SurfaceTextureListener {

    MediaRecorder mRecorder = new MediaRecorder();
    private Handler mHandler = new Handler();
    private Camera mCamera;
    private TextureView mTextureView;
    private int currentAmplitude;


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

        // Variables for textureview
        mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);

        // Build the camera preview onto textureview
        setContentView(mTextureView);

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

        // Repeat audio methods constantly
        mHandler.postDelayed(runnable, 100);

        // Input the current amplitude level into the power level textview
        setCurrentAmplitude();
        TextView txtPowerLevel = (TextView) findViewById(R.id.txtPowerLevel);
        txtPowerLevel.setText(Integer.toString(currentAmplitude));

    }

    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) {
        stopAudioCapture();
        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() {
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
        mRecorder.setOutputFile("/dev/null");
        try {
            mRecorder.prepare();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            mRecorder.start();
        }
        catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }

    public void stopAudioCapture() {
        mRecorder.stop();
        mRecorder.release();
    }

    public double getAmplitude() {
        if (mRecorder != null)
            return  mRecorder.getMaxAmplitude();
        else
            return 0;

    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
      /* do what you need to do */
            getAmplitude();
      /* and here comes the "trick" */
            mHandler.postDelayed(this, 100);
        }
    };

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

And thanks so much in advanced!

Lee.

ANSWER (Thanks to Blackbelt):

I changed:

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

        // Variables for textureview
        mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);

        // Build the camera preview onto textureview
        setContentView(mTextureView);

To:

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

Solution

  • The problem of your NPE is due to

    // Build the camera preview onto textureview
    setContentView(mTextureView);
    

    this way you are overriding he previous call to setContentView which probably contains your TextView. You could add the TextureView to dbzpowerup.xml and use findViewById to grab a reference to it