The PSLab Android App allows users to access functionality provided by the PSLab hardware device, but in the interest of appealing to a larger audience that may not have immediate access to the device, we’re working on implementing some additional functionalities to perform experiments using only the hardware and sensors that are available in most android phones. The mentors suggested that the audio jack (Microphone input) of phones can be hacked to make it function as an Oscilloscope. Similarly, the audio output can also be used as a 2-channel arbitrary waveform generator. So I did a little research and found some articles which described how it can be done. In this post, I will dive a bit into the following aspects –
- AudioJack specifications for android devices
- Android APIs that provide access to audio hardware of device
- Integrating both to achieve scope functionality
Audio Jack specification for android devices
In a general audio jack interface, the configuration CTIA(LRGM – Left, Right, Ground, Mic) is present as shown in the image below. Some interfaces also have OMTP(LRMG – Left, Right, Mic, Ground) configuration in which the common and mic inputs are interchanged. In the image, Common refers to ground.
If we simply cut open the wire of a cheap pair of earphones (stolen from an airplane? 😉 ) , we will gain access to all terminals (Left, Right, Common, Mic Input) illustrated in the image below
Android APIs that provide access to audio hardware of device
AudioRecord and AudioTrack are two classes in android that manage recording and playback respectively. We require only AudioRecord to implement scope functionality. We shall first create an object of the AudioRecord class, and use that object to read the audio buffer as and when required.
Creating an AudioRecord object: we need the following parameters to initialise an AudioRecord object.
SAMPLING_RATE: Almost all mobile devices support sampling rate of 44100 Hz. In this context, the definition is number of audio samples taken per second.
RECORDER_AUDIO_ENCODING: Audio encoding describes bit representation of audio data. Here we used PCM_16BIT encoding this means stream of bits generated from PCM are segregated in a set of 16 bits.
getMinimumBufferSize() returns minimum buffer size in byte units required to create an AudioRecord object successfully.
private static final int SAMPLING_RATE = 44100; private static final int RECORDING_CHANNEL = AudioFormat.CHANNEL_IN_MONO; private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; private AudioRecord audioRecord = null; private int minRecorderBufferSize; minRecorderBufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE, RECORDING_CHANNEL, RECORDER_AUDIO_ENCODING); audioRecord = new AudioRecord( MediaRecorder.AudioSource.MIC, SAMPLING_RATE, RECORDING_CHANNEL, RECORDER_AUDIO_ENCODING, minRecorderBufferSize);
audioRecord object can be used to read audio buffer from audio hardware using read() method.
minRecorderBuffer size is in byte units and 2 bytes constitute a short in JAVA. Thus size of short buffer needed is half the total number of bytes.
short[] audioBuffer = new short[minRecorderBufferSize / 2]; audioRecord.read(audioBuffer, 0, audioBuffer.length);
Now audioBuffer has the audio data as a signed 16 bit values. We need to process the buffer data and plot the processed data points on chart to completely implement scope functionality. I am still looking for relation between the signed 16-bit value of audio buffer and actual mic bias voltage. According to android headset specs, Mic bias voltage is between 1.8-2.9V.
Using AudioRecord class to create a scope in PSLab Android
In PSLab Android App, there is already an Oscilloscope made to capture and plot the data received from PSLab device. To make a cheap oscilloscope, cut open the wire of a cheap headset and expose terminals as illustrated in the image above and provide input signal at microphone input terminal.
Note: Don’t provide a voltage more than 2V at mic input terminal, it can damage your android device. To be sure check peak voltage from external voltmeter of the signal that you want to apply on scope and if it’s greater than 2V, I suggest you to first make a voltage divider to lower the voltage and then you are good to go.
To integrate plotting of audio buffer, we simply need to create another thread that captures audio data and updates the UI with the processed buffer data.
public class captureAudioBuffer extends AsyncTask<Void, Void, Void> { private AudioJack audioJack; private short[] buffer; public captureAudioBuffer(AudioJack audioJack) { this.audioJack = audioJack; } @Override protected Void doInBackground(Void... params) { buffer = audioJack.read(); Log.v("AudioBuffer", Arrays.toString(buffer)); audioJack.release(); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); // UPDATE UI ACCORDING TO READ BUFFER DATA Log.v("Execution Done", "Completed"); } }
For complete code of AudioJack class, please refer pslab-android-app.