Audio

Audio Playback using an Intent

The easiest and most straightforward way to do many things on Android is to leverage an existing piece of software on the device by using an intent. An intent is a core component of Android that is described in the documentation as a “description of an action to be performed.” In practice, intents are used to trigger other applications to do something or to switch between activities in a single application.

To play audio back using an Intent, we can use the following code:

java.io.File audioFile = new File(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/blah/recording.3gp"); 
android.net.Uri audioFileUri = android.net.Uri.fromFile(audioFile);
  
android.content.Intent intent = new android.content.Intent(android.content.Intent.ACTION_VIEW); 
intent.setDataAndType(audioFileUri, "audio/mp3"); 
startActivity(intent);

This code assumes that an audio file called recording.3gp is available on the SD card of the device in a folder called “blah”. Unfortunately, we couldn’t use this code to play an audio file that we bundled with our application as the built in player wouldn’t be able to access the file (unless we moved it).

Also, as per a limitation in the current version of Processing for Android I am using entire package names for the classes I am using rather than normal “import” statements. Normally the imports would look like this:

import java.io.File;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;

and the code snippet would be:

File audioFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/blah/recording.3gp"); 
Uri audioFileUri = Uri.fromFile(audioFile);
  
Intent intent = new Intent(Intent.ACTION_VIEW); 
intent.setDataAndType(audioFileUri, "audio/mp3"); 
startActivity(intent);

As with any code on Android, we can learn a lot about the individual classes we are using by referencing the “javadocs” on the Android Developer site.

File
Uri
Environment
Intent

Audio Capture using an Intent

android.net.Uri audioFileUri;
int RECORD_REQUEST = 0;

void setup() {
}

void draw() {
}

void mousePressed() {
  android.content.Intent intent = new android.content.Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION); 
  startActivityForResult(intent, RECORD_REQUEST);
}

protected void onActivityResult (int requestCode, int resultCode, android.content.Intent data) { 
  if (resultCode == RESULT_OK && requestCode == RECORD_REQUEST) {
    audioFileUri = data.getData(); 
    println(audioFileUri);
  }
}

Audio Playback using MediaPlayer

Last week we looked at a class that leverages MediaPlayer to play audio back.

Here is an updated version of that class

class SoundPlayer extends Object  implements android.media.MediaPlayer.OnCompletionListener {

  android.media.MediaPlayer mediaPlayer;
  android.content.res.AssetFileDescriptor assetFileDescriptor;
  processing.core.PApplet theSketch;

  boolean ready = false;
 
  public SoundPlayer(PApplet _theSketch, String assetAudioFile) {
    theSketch = _theSketch;

    try {
      assetFileDescriptor = theSketch.getAssets().openFd(assetAudioFile);

      mediaPlayer = new android.media.MediaPlayer();
      mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
      mediaPlayer.setOnCompletionListener(this);
      mediaPlayer.prepare();
      ready = true;
    } catch (Exception e) {
      theSketch.println(e.toString());
    }
  }
 
  public SoundPlayer(PApplet _theSketch, java.io.File _audioFile) {
    this(_theSketch, android.net.Uri.fromFile(_audioFile));
  }
  
  public SoundPlayer(PApplet _theSketch, android.net.Uri _audioFileUri) {
    theSketch = _theSketch;
    theSketch.println("The Uri: " + _audioFileUri.toString());
    try {
      mediaPlayer = android.media.MediaPlayer.create(_theSketch, _audioFileUri);
      mediaPlayer.setOnCompletionListener(this);
      ready = true;
    } catch (Exception e) {
      theSketch.println(e.toString());
      e.printStackTrace();
      
    }
  }

  public void play() {
    if (ready) {
      try {
        theSketch.println("playSound");
        mediaPlayer.start();
        ready = false;
      } catch (Exception e) {
        theSketch.println(e.toString());
        e.printStackTrace();
      }
    }
  }

  public void onCompletion(android.media.MediaPlayer mp) {
    try {
      theSketch.println("Trying to prepare");
      mediaPlayer.stop();
      mediaPlayer.prepare();
      ready = true;
    }
    catch (Exception e) {
      theSketch.println(e.toString());
      e.printStackTrace();
    }
  }
}

Audio Capture using MediaRecorder

class SoundRecorder extends Object {

  android.media.MediaRecorder mediaRecorder;
  processing.core.PApplet theSketch;

  android.media.MediaRecorder recorder;
  boolean ready = false;
  java.io.File audioFile;

  public SoundRecorder(PApplet _theSketch, File _audioFile) {
    theSketch = _theSketch;

    recorder = new android.media.MediaRecorder();
    recorder.setAudioSource(android.media.MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(android.media.MediaRecorder.OutputFormat.THREE_GPP);
    recorder.setAudioEncoder(android.media.MediaRecorder.AudioEncoder.AMR_NB);

    audioFile = _audioFile;
    recorder.setOutputFile(audioFile.getAbsolutePath());

    try {
      recorder.prepare();
    } catch (IllegalStateException e) {
      throw new RuntimeException("IllegalStateException on MediaRecorder.prepare", e);
    } catch (IOException e) {
      throw new RuntimeException("IOException on MediaRecorder.prepare", e);
    }

    ready = true;
  }
  
  public SoundRecorder(PApplet _theSketch, String audioFilePath) {
    theSketch = _theSketch;

    recorder = new android.media.MediaRecorder();
    recorder.setAudioSource(android.media.MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(android.media.MediaRecorder.OutputFormat.THREE_GPP);
    recorder.setAudioEncoder(android.media.MediaRecorder.AudioEncoder.AMR_NB);

    java.io.File audioFile = new java.io.File(audioFilePath);    
    recorder.setOutputFile(audioFile.getAbsolutePath());

    try {
      recorder.prepare();
    } catch (IllegalStateException e) {
      throw new RuntimeException("IllegalStateException on MediaRecorder.prepare", e);
    } catch (IOException e) {
      throw new RuntimeException("IOException on MediaRecorder.prepare", e);
    }

    ready = true;
  }

  public void record() {
    if (ready) {
      recorder.start();    
    }
  }

  public void stop() {
     recorder.stop(); 
     recorder.release();
  }
}

Example:

int clickNumber = 0;

SoundPlayer sp;
SoundRecorder sr;

java.io.File recordingFile;

void setup() {
  java.io.File externalStorageDirectory = android.os.Environment.getExternalStorageDirectory();
  recordingFile = new java.io.File(externalStorageDirectory, "hi.3gp");
}

void draw() {
}

void mousePressed() {
  
  if (clickNumber == 0) {
    println("recording");      
    sr = new SoundRecorder(this, recordingFile);
    sr.record();
  } 
  else if (clickNumber == 1) {
    println("stop recording");

    sr.stop();
  } 
  else if (clickNumber == 2) {
    println("playback");

    sp = new SoundPlayer(this, recordingFile);
    sp.play();
  }

  clickNumber++;
}

Don’t forget the permissions: WRITE_EXTERNAL_STORAGE and RECORD_AUDIO