Use the pcm volume to add finer steps between every android stream volume step.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29573 a1c6a512-1295-4272-9138-f99709370657
diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java
index 252fcf6..5a8354a 100644
--- a/android/src/org/rockbox/RockboxPCM.java
+++ b/android/src/org/rockbox/RockboxPCM.java
@@ -23,6 +23,7 @@
 
 import java.util.Arrays;
 
+import android.content.Context;
 import android.content.Intent;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -38,6 +39,7 @@
     private PCMListener l;
     private HandlerThread ht;
     private Handler h = null;
+    private static final int streamtype = AudioManager.STREAM_MUSIC;
     private static final int samplerate = 44100;
     /* should be CHANNEL_OUT_STEREO in 2.0 and above */
     private static final int channels = 
@@ -48,6 +50,11 @@
     private static final int buf_len  = 
             Math.max(24<<10, getMinBufferSize(samplerate, channels, encoding));
 
+    private AudioManager audiomanager;
+    private int maxstreamvolume;
+    private float minpcmvolume;
+    private float pcmrange;
+
     private void LOG(CharSequence text)
     {
         Log.d("Rockbox", (String) text);
@@ -55,7 +62,7 @@
 
     public RockboxPCM()
     {
-        super(AudioManager.STREAM_MUSIC, samplerate,  channels, encoding,
+        super(streamtype, samplerate,  channels, encoding,
                 buf_len, AudioTrack.MODE_STREAM);
         ht = new HandlerThread("audio thread", 
                 Process.THREAD_PRIORITY_URGENT_AUDIO);
@@ -63,6 +70,15 @@
         raw_data = new byte[buf_len]; /* in shorts */
         Arrays.fill(raw_data, (byte) 0);
         l = new PCMListener(buf_len);
+
+        /* find cleaner way to get context? */
+        final RockboxService rb = RockboxService.get_instance();
+        audiomanager =
+            (AudioManager) rb.getSystemService(Context.AUDIO_SERVICE);
+        maxstreamvolume = audiomanager.getStreamMaxVolume(streamtype);
+
+        minpcmvolume = getMinVolume();
+        pcmrange = getMaxVolume() - minpcmvolume;
     }    
 
     private int bytes2frames(int bytes) 
@@ -130,19 +146,26 @@
 
     private void set_volume(int volume)
     {
-        /* volume comes from 0..-990 from Rockbox */
-        /* TODO:
-         * volume is in dB, but this code acts as if it were in %,  convert? */
-        float fvolume;
-        /* special case min and max volume to not suffer from 
-         * floating point accuracy */
-        if (volume == 0)
-            fvolume = 1.0f;
-        else if (volume == -990)
-            fvolume = 0.0f;
-        else
-            fvolume = (volume + 990)/990.0f;
-        setStereoVolume(fvolume, fvolume);
+        /* Rockbox 'volume' is 0..-990 deci-dB attenuation.
+           Android streams have rather low resolution volume control,
+           typically 8 or 15 steps.
+           Therefore we use the pcm volume to add finer steps between
+           every android stream volume step.
+           It's not "real" dB, but it gives us 100 volume steps.
+        */
+
+        float fraction = 1 - (volume / -990.0f);
+        int streamvolume = (int)Math.ceil(maxstreamvolume * fraction);
+        if (streamvolume > 0) {
+            float streamfraction = (float)streamvolume / maxstreamvolume;
+            float pcmvolume =
+                (fraction / streamfraction) * pcmrange + minpcmvolume;
+            setStereoVolume(pcmvolume, pcmvolume);
+        }
+
+        int oldstreamvolume = audiomanager.getStreamVolume(streamtype);
+        if (streamvolume != oldstreamvolume)
+            audiomanager.setStreamVolume(streamtype, streamvolume, 0);
     }
 
     public native void pcmSamplesToByteArray(byte[] dest);