A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Thomas Martitz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22package org.rockbox.Helper;
23
24import org.rockbox.RockboxFramebuffer;
25import org.rockbox.RockboxService;
26import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.media.AudioManager;
32import android.view.KeyEvent;
33
34public class MediaButtonReceiver
35{
36 /* A note on the API being used. 2.2 introduces a new and sane API
37 * for handling multimedia button presses
38 * http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html
39 *
40 * the old API is flawed. It doesn't have management for
41 * concurrent media apps
42 *
43 * if multiple media apps are running
44 * probably all of them want to respond to media keys
45 *
46 * it's not clear which app wins, it depends on the
47 * priority set for the IntentFilter (see below)
48 *
49 * so this all might or might not work on < 2.2 */
50
51 IMultiMediaReceiver api;
52
53 public MediaButtonReceiver(Context c)
54 {
55 try {
56 api = new NewApi(c);
57 } catch (Throwable t) {
58 /* Throwable includes Exception and the expected
59 * NoClassDefFoundError */
60 api = new OldApi(c);
61 Logger.i("MediaButtonReceiver: Falling back to compatibility API");
62 }
63 }
64
65 public void register()
66 {
67 api.register();
68 }
69
70 public void unregister()
71 {
72 api.unregister();
73 }
74
75 /* helper class for the manifest */
76 public static class MediaReceiver extends BroadcastReceiver
77 {
78 private void startService(Context c, Intent baseIntent)
79 {
80 baseIntent.setClass(c, RockboxService.class);
81 c.startService(baseIntent);
82 }
83 @Override
84 public void onReceive(Context context, Intent intent)
85 {
86 if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()))
87 {
88 KeyEvent key = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
89 if (key.getAction() == KeyEvent.ACTION_UP)
90 { /* pass the pressed key to Rockbox, starting it if needed */
91 RockboxService s = RockboxService.getInstance();
92 if (s == null || !s.isRockboxRunning())
93 startService(context, intent);
94 else if (RockboxFramebuffer.buttonHandler(key.getKeyCode(), false))
95 abortBroadcast();
96 }
97 }
98 }
99 }
100
101 private interface IMultiMediaReceiver
102 {
103 void register();
104 void unregister();
105 }
106
107 private static class NewApi
108 implements IMultiMediaReceiver, AudioManager.OnAudioFocusChangeListener
109 {
110 private AudioManager audio_manager;
111 private ComponentName receiver_name;
112 private boolean running = false;
113
114 NewApi(Context c)
115 {
116 audio_manager = (AudioManager)c.getSystemService(Context.AUDIO_SERVICE);
117 receiver_name = new ComponentName(c, MediaReceiver.class);
118 }
119
120 public void register()
121 {
122 try {
123 audio_manager.registerMediaButtonEventReceiver(receiver_name);
124 audio_manager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
125 running = true;
126 } catch (Exception e) {
127 // Nothing
128 e.printStackTrace();
129 }
130 }
131
132 public void unregister()
133 {
134 try
135 {
136 audio_manager.unregisterMediaButtonEventReceiver(receiver_name);
137 audio_manager.abandonAudioFocus(this);
138 running = false;
139 } catch (Exception e) {
140 // Nothing
141 e.printStackTrace();
142 }
143 }
144
145 public void onAudioFocusChange(int focusChange)
146 {
147 Logger.d("Audio focus" + ((focusChange>0)?"gained":"lost")+
148 ": "+ focusChange);
149 if (running)
150 { /* Play nice and stop for the the other app */
151 if (focusChange == AudioManager.AUDIOFOCUS_LOSS)
152 RockboxFramebuffer.buttonHandler(KeyEvent.KEYCODE_MEDIA_STOP, false);
153 }
154 }
155
156 }
157
158 private static class OldApi implements IMultiMediaReceiver
159 {
160 private static final IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
161 private MediaReceiver receiver;
162 private Context context;
163 OldApi(Context c)
164 {
165 filter.setPriority(1); /* 1 higher than the built-in media player */
166 receiver = new MediaReceiver();
167 context = c;
168 }
169
170 public void register()
171 {
172 context.registerReceiver(receiver, filter);
173 }
174
175 public void unregister()
176 {
177 context.unregisterReceiver(receiver);
178 }
179
180 }
181}