diff --git a/apps/codecs.c b/apps/codecs.c
index b4b8c9833a..d9bda6b0a6 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -218,6 +218,7 @@ struct codec_api ci = {
enc_wavbuf_near_empty,
enc_get_wav_data,
&enc_set_header_callback,
+ 44100,
#endif
/* new stuff at the end, sort into place next time
diff --git a/apps/codecs.h b/apps/codecs.h
index 96804a889b..7cd48f65e2 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -303,6 +303,7 @@ struct codec_api {
char* (*enc_get_wav_data)(int size);
void (**enc_set_header_callback)(void *head_buffer,
int head_size, int num_samples, bool is_file_header);
+ int sample_rate;
#endif
/* new stuff at the end, sort into place next time
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 9e6a809dac..4dfbff7ad5 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -9806,3 +9806,59 @@
*: ""
+
+ id: LANG_UNPLUG
+ desc: in settings_menu.
+ user:
+
+ *: "Pause on headphone unplug"
+
+
+ *: "Pause on headphone unplug"
+
+
+ *: "Pause on headphone unplug"
+
+
+
+ id: LANG_UNPLUG_RESUME
+ desc: in pause_phones_menu.
+ user:
+
+ *: "Pause and Resume"
+
+
+ *: "Pause and Resume"
+
+
+ *: "Pause and Resume"
+
+
+
+ id: LANG_UNPLUG_RW
+ desc: in pause_phones_menu.
+ user:
+
+ *: "Duration to rewind"
+
+
+ *: "Duration to rewind"
+
+
+ *: "Duration to rewind"
+
+
+
+ id: LANG_UNPLUG_DISABLE_AUTORESUME
+ desc: in pause_phones_menu.
+ user:
+
+ *: "Disable auto-resume if phones not present"
+
+
+ *: "Disable auto-resume if phones not present"
+
+
+ *: "Disable auto-resume if phones not present"
+
+
diff --git a/apps/misc.c b/apps/misc.c
index e95c5e5650..806f5ff63e 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -580,6 +580,33 @@ void car_adapter_mode_init(void)
}
#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+void unplug_change(bool inserted)
+{
+ if (global_settings.unplug_mode)
+ {
+ if (inserted)
+ {
+ if ( global_settings.unplug_mode > 1 )
+ audio_resume();
+ backlight_on();
+ } else {
+ audio_pause();
+
+ if (global_settings.unplug_rw)
+ {
+ if ( audio_current_track()->elapsed >
+ (unsigned long)(global_settings.unplug_rw*1000))
+ audio_ff_rewind(audio_current_track()->elapsed -
+ (global_settings.unplug_rw*1000));
+ else
+ audio_ff_rewind(0);
+ }
+ }
+ }
+}
+#endif
+
long default_event_handler_ex(long event, void (*callback)(void *), void *parameter)
{
switch(event)
@@ -608,6 +635,15 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
case SYS_CHARGER_DISCONNECTED:
car_adapter_mode_processing(false);
return SYS_CHARGER_DISCONNECTED;
+#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+ case SYS_PHONE_PLUGGED:
+ unplug_change(true);
+ return SYS_PHONE_PLUGGED;
+
+ case SYS_PHONE_UNPLUGGED:
+ unplug_change(false);
+ return SYS_PHONE_UNPLUGGED;
#endif
}
return 0;
diff --git a/apps/settings.c b/apps/settings.c
index 3dc4ee1530..4746c22c87 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -655,6 +655,12 @@ static const struct bit_entry hd_bits[] =
#endif
#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+ {2, S_O(unplug_mode), 0, "pause on headphone unplug", NULL},
+ {4, S_O(unplug_rw), 0, "rewind duration on pause", NULL},
+ {1, S_O(unplug_autoresume), 0, "disable autoresume if phones not present", off_on },
+#endif
+
/* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */
diff --git a/apps/settings.h b/apps/settings.h
index 561dc59375..9f8372415a 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -486,6 +486,12 @@ struct user_settings
#endif
bool hold_lr_for_scroll_in_list; /* hold L/R scrolls the list left/right */
int show_path_in_browser; /* 0=off, 1=current directory, 2=full path */
+
+#ifdef HAVE_HEADPHONE_DETECTION
+ int unplug_mode; /* pause on headphone unplug */
+ int unplug_rw; /* time in s to rewind when pausing */
+ bool unplug_autoresume; /* disable auto-resume if no phones */
+#endif
};
enum optiontype { INT, BOOL };
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 8f9fbe1c62..36615cfc6a 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1664,6 +1664,57 @@ static bool tagcache_settings_menu(void)
return result;
}
+#ifdef HAVE_HEADPHONE_DETECTION
+static bool unplug_mode(void)
+{
+ static const struct opt_items names[] = {
+ { STR(LANG_OFF) },
+ { STR(LANG_PAUSE) },
+ { STR(LANG_UNPLUG_RESUME) },
+ };
+ bool ret;
+ ret=set_option( str(LANG_UNPLUG),
+ &global_settings.unplug_mode, INT, names, 3, NULL);
+
+ return ret;
+}
+
+static bool unplug_rw(void)
+{
+ bool ret;
+
+ ret = set_int(str(LANG_UNPLUG_RW), "s", UNIT_SEC,
+ &global_settings.unplug_rw,
+ NULL, 1, 0, 15, NULL );
+ audio_set_crossfade(global_settings.unplug_rw);
+ return ret;
+}
+
+static bool unplug_autoresume(void)
+{
+ return set_bool( str(LANG_UNPLUG_DISABLE_AUTORESUME),
+ &global_settings.unplug_autoresume );
+}
+
+static bool unplug_menu(void)
+{
+ int m;
+ bool result;
+
+ static const struct menu_item items[] = {
+ { ID2P(LANG_UNPLUG), unplug_mode },
+ { ID2P(LANG_UNPLUG_RW), unplug_rw },
+ { ID2P(LANG_UNPLUG_DISABLE_AUTORESUME), unplug_autoresume },
+ };
+
+ m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
+ NULL, NULL, NULL);
+ result = menu_run(m);
+ menu_exit(m);
+ return result;
+}
+#endif
+
static bool playback_settings_menu(void)
{
int m;
@@ -1687,7 +1738,10 @@ static bool playback_settings_menu(void)
{ ID2P(LANG_SPDIF_ENABLE), spdif },
#endif
{ ID2P(LANG_ID3_ORDER), id3_order },
- { ID2P(LANG_NEXT_FOLDER), next_folder }
+ { ID2P(LANG_NEXT_FOLDER), next_folder },
+#ifdef HAVE_HEADPHONE_DETECTION
+ { ID2P(LANG_UNPLUG), unplug_menu }
+#endif
};
bool old_shuffle = global_settings.playlist_shuffle;
diff --git a/apps/tree.c b/apps/tree.c
index 3ee3061540..0e2dcb6c87 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -466,7 +466,20 @@ static void start_resume(bool just_powered_on)
/* always resume? */
if ( global_settings.resume || ! just_powered_on)
- do_resume = true;
+#ifdef HAVE_HEADPHONE_DETECTION
+ {
+ if ( just_powered_on )
+ {
+ if ( !global_settings.unplug_autoresume
+ || headphones_inserted() )
+ do_resume = true;
+ }
+ else
+ do_resume = true;
+ }
+#else
+ do_resume = true;
+#endif
if (! do_resume) return;
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 5add6cb817..0042d9b8eb 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -92,6 +92,10 @@ static bool remote_button_hold_only(void);
int int_btn = BUTTON_NONE;
#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+bool phones_present = false;
+#endif
+
#if (CONFIG_KEYPAD == IPOD_4G_PAD) && !defined(IPOD_MINI)
static void opto_i2c_init(void)
{
@@ -433,6 +437,23 @@ static void button_tick(void)
}
#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+ if ( headphones_inserted() )
+ {
+ if (! phones_present )
+ {
+ queue_post(&button_queue, SYS_PHONE_PLUGGED, NULL);
+ phones_present = true;
+ }
+ } else {
+ if ( phones_present )
+ {
+ queue_post(&button_queue, SYS_PHONE_UNPLUGGED, NULL);
+ phones_present = false;
+ }
+ }
+#endif
+
btn = button_read();
/* Find out if a key has been released */
@@ -1327,3 +1348,10 @@ void button_clear_queue(void)
queue_clear(&button_queue);
}
+#ifdef HAVE_HEADPHONE_DETECTION
+bool headphones_inserted(void)
+{
+ return (GPIOA_INPUT_VAL & 0x80)?true:false;
+}
+#endif
+
diff --git a/firmware/export/button.h b/firmware/export/button.h
index 0e11da9da5..39dfbff6fa 100644
--- a/firmware/export/button.h
+++ b/firmware/export/button.h
@@ -54,6 +54,9 @@ bool button_hold(void);
#ifdef HAS_REMOTE_BUTTON_HOLD
bool remote_button_hold(void);
#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+bool headphones_inserted(void);
+#endif
#define BUTTON_NONE 0x00000000
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index a5f186782f..2e8c4dcc33 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -109,6 +109,9 @@
/* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ
+/* Define this if you can detect headphones */
+#define HAVE_HEADPHONE_DETECTION
+
#define BOOTFILE_EXT "ipod"
#define BOOTFILE "rockbox." BOOTFILE_EXT
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index 3366baa8ea..964f103214 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -105,6 +105,9 @@
/* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ
+/* Define this if you can detect headphones */
+#define HAVE_HEADPHONE_DETECTION
+
#define BOOTFILE_EXT "ipod"
#define BOOTFILE "rockbox." BOOTFILE_EXT
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index c077c381f8..03f5b8c753 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -110,6 +110,9 @@
/* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ
+/* Define this if you can detect headphones */
+#define HAVE_HEADPHONE_DETECTION
+
#define BOOTFILE_EXT "ipod"
#define BOOTFILE "rockbox." BOOTFILE_EXT
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index 5cea64deb4..4781a2c887 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -110,6 +110,9 @@
/* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ
+/* Define this if you can detect headphones */
+#define HAVE_HEADPHONE_DETECTION
+
#define BOOTFILE_EXT "ipod"
#define BOOTFILE "rockbox." BOOTFILE_EXT
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index 482516b9dc..fcab2d923c 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -46,6 +46,8 @@
#define SYS_FS_CHANGED ((SYS_EVENT | ((long)9 << 27)))
#define SYS_CHARGER_CONNECTED ((SYS_EVENT | ((long)10 << 27)))
#define SYS_CHARGER_DISCONNECTED ((SYS_EVENT | ((long)11 << 27)))
+#define SYS_PHONE_PLUGGED ((SYS_EVENT | ((long)12 << 27)))
+#define SYS_PHONE_UNPLUGGED ((SYS_EVENT | ((long)13 << 27)))
struct event
{