Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - AudioTrack setStereoVolume() not working

I have a class that uses AudioTrack to generate a sound per specific frequency. Everything works fine, but now I want to customize it so that I can play the sound only on right side of headphones, or only on left side of headphones. (right, or left ear)

So I found that AudioTrack has a such method: setStereoVolume(), however, when I configure it, for example like this: audioTrack.setStereoVolume(1.0f, 0.0f), I'm expecting that only my left side of headphones should sound, and the right side should be mute, but it has not efect. I can hear the sound at the same volume on both right and left side of headphones.

I check the return value of setStreamVolume() and it's 0, which is equal with SUCCESS, but I still don't hear the difference.

Do you know why it isn't working, or an alternative way how I can specify to play the sound only on left or right side of headphones?

Here's the code that generates the sound:

public class SoundGenerator extends AsyncTask<Float, Void, Void> {
    final int SAMPLE_RATE = 11025;
    boolean playing=false;

    @Override
    protected Void doInBackground(Float... params) {

        float frequency=params[0];

        int minSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
                AudioFormat.CHANNEL_CONFIGURATION_STEREO,
                AudioFormat.ENCODING_PCM_16BIT);

        AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
                AudioFormat.ENCODING_PCM_16BIT, minSize,
                AudioTrack.MODE_STREAM);

        short[] buffer = new short[minSize];

        float angular_frequency = (float) (2 * Math.PI) * frequency / SAMPLE_RATE;
        float angle = 0;

        audioTrack.play();
        int stereo=audioTrack.setStereoVolume(1.0f, 0.0f); 

                Log.d("GREC", "Stereo vol: "+stereo);


        while (playing) {

            for (int i = 0; i < buffer.length; i++) {
                buffer[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(angle)));
                angle += angular_frequency;
            }
            audioTrack.write(buffer, 0, buffer.length);
        }
        Log.d(Globals.TAG, "Stopping the tone generator...");
        audioTrack.stop();
        audioTrack.release();

        return null;
    }

    public void keepPlaying(boolean flag){
        playing=flag;
    }
}
like image 912
VCODE Avatar asked Nov 14 '22 05:11

VCODE


1 Answers

I've noticed same issue. setStereoVolume was working on Android 4.3 emulator but was not working on Android 4.0.3 device.

I've investigated Android 4.0.3 AudioTrack.java source and found that if i call setStereoVolume before the write is called for AudioTrack it doesn't work returning ERROR_INVALID_OPERATION because of invalid mState value.

public int setStereoVolume(float leftVolume, float rightVolume) {
        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }
...
}

Then i've changed sequence of calls and added setStereoVolume after the audioTrack.write call and it began to work fine. Looks like write method modifies mState value

public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
     if ((mDataLoadMode == MODE_STATIC)
          && (mState == STATE_NO_STATIC_DATA)
          && (sizeInBytes > 0)) {
          mState = STATE_INITIALIZED;
     }
     ...
}
like image 63
Eugene Popovich Avatar answered Nov 16 '22 02:11

Eugene Popovich