Question

I want to put a controllable DC voltage out the audio jack of an android device. My current solution is to create a 1 second array containing the PCM info for the waveform to be output (a flatline in this case).

The problem is that every second, there's a glitch where the output momentarily drops to zero volts. I believe this is happening at the point were the audio resource instance is created.

You can see that the audio is handled in its own thread. I will be changing the generatedSnd array in another thread.

Is there a smoother way of doing this? I have a feeling streaming is the wa to go, but I can't get my head round it.

private class OutDACrunnable
    implements Runnable {

    public void run() {
        while (! done) {

        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat. CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
                AudioTrack.MODE_STATIC);

        audioTrack.write(generatedSnd, 0, generatedSnd.length);

        if (audioManager.isWiredHeadsetOn()) { } // use this later

        audioTrack.play();

        // wait until playback is complete
        int x = 0;
        do {
            if (audioTrack == null) {
                x = numSamples;
            } else {
                x = audioTrack.getPlaybackHeadPosition(); 
            }
        } while (x < numSamples);

        if (audioTrack != null) audioTrack.release();

        }
    }

} // OutDACrunbable

Thanks.

Was it helpful?

Solution 2

After the tip from Bjorn about write blocking as required, I tweaked my code. So, basically, I throw 20ms of sample at it every 15ms. It discards once the buffer is full, so I made teh buffer 20ms as well. This way it stays up to date with my demands and no blips...

        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat. CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
                AudioTrack.MODE_STREAM);

        audioTrack.play();

    private class OutDACrunnable
        implements Runnable {

        public void run() {
            while (! done) {
                playTone();
                try {
                    Thread.sleep((int) (750 * duration));
                } catch (InterruptedException e) {
                    Log.e(MyTag, "OutDACrunnable: " + e.toString());
                }
            }
        }

    } // OutDACrunbable

    void playTone() {

    //      Log.d(MyTag, "playTone: start");

            audioTrack.write(generatedSnd, 0, generatedSnd.length);

            if (audioManager.isWiredHeadsetOn()) { } // use this later

    //      Log.d(MyTag, "playTone: done");

    } // playTone

    public static void genTone(double amp1, double amp2) {

//      Log.d(MyTag, "genTone: start");

        // convert to 16 bit pcm sound array
        // assumes the sample buffer is normalised.
        int idx = 0;
        for (int i = 0; i < numSamples; i++) {
            // scale to maximum amplitude
            // in 16 bit wav PCM, first byte is the low order byte, first short is left ch
            short val = (short) ((amp1 * 32767));
            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
            val = (short) ((amp2 * 32767));
            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

        }
//      Log.d(MyTag, "genTone: done");
    }

And I just call GenTone as and when I want, with the two DCs I want output...

OTHER TIPS

Unfortunately, you can't output DC from the audio jack. The audio I/o is designed to pass changing signals, generally speaking above 20 Hz. If you try to output DC, you will get something more like a pulse, which is what it sounds like you are getting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top