From 3ce0a1578e4350e346f017445b217c1691fbaeb0 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Sun, 30 Jan 2011 19:28:07 +0100 Subject: [PATCH 08/10] Android: sync audio volume with Android system volume (WIP) --- android/src/org/rockbox/RockboxPCM.java | 57 ++++++++++++++++++------- apps/misc.c | 12 +++++ firmware/export/config.h | 1 + firmware/export/kernel.h | 1 + firmware/export/system.h | 4 ++ firmware/target/hosted/android/pcm-android.c | 25 +++++++++++ 6 files changed, 84 insertions(+), 16 deletions(-) diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java index c1fecbc..30337f5 100644 --- a/android/src/org/rockbox/RockboxPCM.java +++ b/android/src/org/rockbox/RockboxPCM.java @@ -23,7 +23,10 @@ package org.rockbox; import java.util.Arrays; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; @@ -39,6 +42,7 @@ public class RockboxPCM extends AudioTrack 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,7 +52,8 @@ public class RockboxPCM extends AudioTrack /* 24k is plenty, but some devices may have a higher minimum */ private static final int buf_len = Math.max(24<<10, getMinBufferSize(samplerate, channels, encoding)); - + private AudioManager audioManager; + private void LOG(CharSequence text) { Log.d("Rockbox", (String) text); @@ -56,16 +61,44 @@ public class RockboxPCM extends AudioTrack public RockboxPCM() { - super(AudioManager.STREAM_MUSIC, samplerate, channels, encoding, - buf_len, AudioTrack.MODE_STREAM); + super(streamType, samplerate, channels, encoding, buf_len, AudioTrack.MODE_STREAM); ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO); ht.start(); raw_data = new byte[buf_len]; /* in shorts */ Arrays.fill(raw_data, (byte) 0); l = new PCMListener(buf_len); + + setupVolumeHandler(); } + private native void postVolumeChangedEvent(int volume); + private void setupVolumeHandler() + { + final RockboxService rbService = RockboxService.get_instance(); /* find cleaner way to get context? */ + audioManager = (AudioManager) rbService.getSystemService(Context.AUDIO_SERVICE); + + /* We're relying on internal API's here, this can break in the future! */ + BroadcastReceiver broadcastReceiver = new BroadcastReceiver() + { + @Override + public void onReceive(Context context, Intent intent) + { + int streamType = intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_TYPE", -1); + int volume = intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_VALUE", -1); + + if (streamType == RockboxPCM.streamType && volume != -1 && rbService.isRockboxRunning()) + { + /* Rockbox volume ranges -99..0 */ + int maxVolume = audioManager.getStreamMaxVolume(streamType); + postVolumeChangedEvent(((maxVolume - volume) * -99) / maxVolume); + } + } + }; + + rbService.registerReceiver(broadcastReceiver, new IntentFilter("android.media.VOLUME_CHANGED_ACTION")); + } + private int bytes2frames(int bytes) { /* 1 sample is 2 bytes, 2 samples are 1 frame */ @@ -130,19 +163,11 @@ public class RockboxPCM extends AudioTrack @SuppressWarnings("unused") 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); + /* volume comes from -990..0 from Rockbox */ + /* TODO: volume is in dB, but this code acts as if it were in %, convert? */ + int maxVal = audioManager.getStreamMaxVolume(streamType); + volume = ((volume + 990) * maxVal) / 990; + audioManager.setStreamVolume(streamType, volume, 0); } public native void pcmSamplesToByteArray(byte[] dest); diff --git a/apps/misc.c b/apps/misc.c index 94b2de4..13da76c 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -635,6 +635,18 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame resume = false; return SYS_CALL_HUNG_UP; #endif +#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(PLATFORM_HAS_VOLUME_CHANGE) + case SYS_VOLUME_CHANGED: + { + int volume = hosted_get_volume(); + if (global_settings.volume != volume) + { + global_settings.volume = volume; + setvol(); + } + return 0; + } +#endif #ifdef HAVE_MULTIMEDIA_KEYS /* multimedia keys on keyboards, headsets */ case BUTTON_MULTIMEDIA_PLAYPAUSE: diff --git a/firmware/export/config.h b/firmware/export/config.h index d59b259..3269bee 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -711,6 +711,7 @@ Lyre prototype 1 */ #if (CONFIG_PLATFORM & PLATFORM_ANDROID) #define HAVE_PRIORITY_SCHEDULING +#define PLATFORM_HAS_VOLUME_CHANGE #endif #if (CONFIG_PLATFORM & PLATFORM_NATIVE) diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 20743c5..28b0a71 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h @@ -83,6 +83,7 @@ #define SYS_IAP_HANDLEPKT MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 2) #define SYS_CALL_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3) #define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4) +#define SYS_VOLUME_CHANGED MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 5) #define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT) diff --git a/firmware/export/system.h b/firmware/export/system.h index b246d15..e5c7f09 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -137,6 +137,10 @@ int get_cpu_boost_counter(void); #undef htobe32 #endif +#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(PLATFORM_HAS_VOLUME_CHANGE) +int hosted_get_volume(void); +#endif + /* Get the byte offset of a type's member */ #define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername) diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c index c8bc410..4b417f9 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c @@ -175,3 +175,28 @@ void pcm_set_mixer_volume(int volume) { (*env_ptr)->CallVoidMethod(env_ptr, RockboxPCM_instance, set_volume_method, volume); } + +/* Due to limitations of default_event_handler(), parameters gets swallowed when + * being posted with queue_broadcast(), so workaround this by caching the last + * value. + */ +static int lastPostedVolume; +int hosted_get_volume(void) +{ + return lastPostedVolume; +} + +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env, + jobject this, + jint volume) +{ + (void) env; + (void) this; + + if (volume != lastPostedVolume) + { + lastPostedVolume = volume; + queue_broadcast(SYS_VOLUME_CHANGED, 0); + } +} \ No newline at end of file -- 1.7.1