From e50cc0e3d760d4fdb99f971070a6943ee15a9a98 Mon Sep 17 00:00:00 2001 From: Björn Stenberg Date: Mon, 14 Mar 2011 12:25:48 +0000 Subject: Listen to and follow external Android volume changes. (Based on FS#11914 by Maurus Cuelenaere) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29586 a1c6a512-1295-4272-9138-f99709370657 --- android/src/org/rockbox/RockboxPCM.java | 52 ++++++++++++++++++++++++++-- apps/misc.c | 9 +++++ apps/playback.c | 2 ++ apps/settings.c | 2 ++ firmware/export/config/android.h | 3 ++ firmware/export/kernel.h | 1 + firmware/export/system.h | 4 +++ firmware/target/hosted/android/pcm-android.c | 25 +++++++++++++ 8 files changed, 95 insertions(+), 3 deletions(-) diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java index 5a8354abee..7d01da6150 100644 --- a/android/src/org/rockbox/RockboxPCM.java +++ b/android/src/org/rockbox/RockboxPCM.java @@ -23,8 +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; @@ -52,8 +54,10 @@ public class RockboxPCM extends AudioTrack private AudioManager audiomanager; private int maxstreamvolume; + private int setstreamvolume = -1; private float minpcmvolume; private float pcmrange; + private RockboxService rbservice; private void LOG(CharSequence text) { @@ -72,15 +76,55 @@ public class RockboxPCM extends AudioTrack l = new PCMListener(buf_len); /* find cleaner way to get context? */ - final RockboxService rb = RockboxService.get_instance(); + rbservice = RockboxService.get_instance(); audiomanager = - (AudioManager) rb.getSystemService(Context.AUDIO_SERVICE); + (AudioManager) rbservice.getSystemService(Context.AUDIO_SERVICE); maxstreamvolume = audiomanager.getStreamMaxVolume(streamtype); minpcmvolume = getMinVolume(); pcmrange = getMaxVolume() - minpcmvolume; + + setupVolumeHandler(); } + private native void postVolumeChangedEvent(int volume); + private void setupVolumeHandler() + { + 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 && + volume != setstreamvolume && + rbservice.isRockboxRunning()) + { + int rbvolume = ((maxstreamvolume - volume) * -99) / + maxstreamvolume; + postVolumeChangedEvent(rbvolume); + } + } + }; + + /* at startup, change the internal rockbox volume to what the global + android music stream volume is */ + int volume = audiomanager.getStreamVolume(streamtype); + int rbvolume = ((maxstreamvolume - volume) * -99) / maxstreamvolume; + postVolumeChangedEvent(rbvolume); + + /* We're relying on internal API's here, + this can break in the future! */ + 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 */ @@ -164,8 +208,10 @@ public class RockboxPCM extends AudioTrack } int oldstreamvolume = audiomanager.getStreamVolume(streamtype); - if (streamvolume != oldstreamvolume) + if (streamvolume != oldstreamvolume) { + setstreamvolume = streamvolume; audiomanager.setStreamVolume(streamtype, streamvolume, 0); + } } public native void pcmSamplesToByteArray(byte[] dest); diff --git a/apps/misc.c b/apps/misc.c index fa34c21f4e..995d65644e 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -636,6 +636,15 @@ 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; + return 0; + } +#endif #ifdef HAVE_MULTIMEDIA_KEYS /* multimedia keys on keyboards, headsets */ case BUTTON_MULTIMEDIA_PLAYPAUSE: diff --git a/apps/playback.c b/apps/playback.c index b72ed8a3b8..fb79c4d382 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -1834,7 +1834,9 @@ static void audio_play_start(size_t offset) ci.seek_time = 0; wps_offset = 0; +#ifndef PLAFORM_HAS_VOLUME_CHANGE sound_set_volume(global_settings.volume); +#endif track_widx = track_ridx = 0; buf_set_base_handle(-1); diff --git a/apps/settings.c b/apps/settings.c index e9458dc601..623bc5b2a0 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -726,7 +726,9 @@ void sound_settings_apply(void) sound_set(SOUND_TREBLE, global_settings.treble); #endif sound_set(SOUND_BALANCE, global_settings.balance); +#ifndef PLATFORM_HAS_VOLUME_CHANGE sound_set(SOUND_VOLUME, global_settings.volume); +#endif sound_set(SOUND_CHANNELS, global_settings.channel_config); sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width); #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) diff --git a/firmware/export/config/android.h b/firmware/export/config/android.h index ed1a283c7d..69a758d69b 100644 --- a/firmware/export/config/android.h +++ b/firmware/export/config/android.h @@ -79,6 +79,9 @@ /* define this if the target has volume keys which can be used in the lists */ #define HAVE_VOLUME_IN_LIST +/* define this if the host platform can change volume outside of rockbox */ +#define PLATFORM_HAS_VOLUME_CHANGE + #define HAVE_SW_TONE_CONTROLS /* Define current usage levels. */ diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 6aaf11ddb9..66efce33f6 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 78bddae387..3f626c3688 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 4c34e3cd91..24881bd3df 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c @@ -179,3 +179,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 = -1; +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); + } +} -- cgit v1.2.3