capacitor-plugin-playlist 0.1.19 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/android/src/main/java/org/dwbn/plugins/playlist/PlaylistPlugin.kt +4 -8
  2. package/android/src/main/java/org/dwbn/plugins/playlist/RmxAudioPlayer.java +397 -385
  3. package/android/src/main/java/org/dwbn/plugins/playlist/manager/PlaylistManager.kt +17 -12
  4. package/android/src/main/java/org/dwbn/plugins/playlist/notification/PlaylistNotificationProvider.kt +5 -1
  5. package/android/src/main/java/org/dwbn/plugins/playlist/service/MediaService.kt +1 -2
  6. package/dist/docs.json +3 -21
  7. package/dist/esm/Constants.js.map +1 -1
  8. package/dist/esm/RmxAudioPlayer.d.ts +4 -10
  9. package/dist/esm/RmxAudioPlayer.js +19 -22
  10. package/dist/esm/RmxAudioPlayer.js.map +1 -1
  11. package/dist/esm/definitions.d.ts +5 -4
  12. package/dist/esm/index.d.ts +1 -1
  13. package/dist/esm/index.js +1 -1
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/plugin.js +1 -0
  16. package/dist/esm/plugin.js.map +1 -1
  17. package/dist/esm/utils.d.ts +1 -1
  18. package/dist/esm/utils.js.map +1 -1
  19. package/dist/esm/web.d.ts +3 -3
  20. package/dist/esm/web.js +32 -27
  21. package/dist/esm/web.js.map +1 -1
  22. package/dist/plugin.cjs.js +47 -44
  23. package/dist/plugin.cjs.js.map +1 -1
  24. package/dist/plugin.js +48 -45
  25. package/dist/plugin.js.map +1 -1
  26. package/ios/Plugin/AVBidirectionalQueuePlayer.swift +18 -4
  27. package/ios/Plugin/AudioTrack.swift +0 -1
  28. package/ios/Plugin/DispatchQueue.swift +3 -3
  29. package/ios/Plugin/RmxAudioPlayer.swift +38 -39
  30. package/package.json +1 -1
  31. package/android/.gitignore +0 -1
  32. package/android/.npmignore +0 -1
  33. package/ios/.DS_Store +0 -0
@@ -5,433 +5,445 @@ import android.util.Log;
5
5
  import androidx.annotation.NonNull;
6
6
  import androidx.annotation.Nullable;
7
7
 
8
- import org.dwbn.plugins.playlist.data.AudioTrack;
9
- import org.dwbn.plugins.playlist.manager.MediaControlsListener;
10
- import org.dwbn.plugins.playlist.manager.Options;
11
- import org.dwbn.plugins.playlist.manager.PlaylistManager;
12
- import org.json.JSONException;
13
- import org.json.JSONObject;
14
-
8
+ import com.devbrackets.android.exomedia.listener.OnErrorListener;
15
9
  import com.devbrackets.android.playlistcore.data.MediaProgress;
16
10
  import com.devbrackets.android.playlistcore.data.PlaybackState;
17
11
  import com.devbrackets.android.playlistcore.data.PlaylistItemChange;
12
+ import com.devbrackets.android.playlistcore.listener.PlaybackStatusListener;
18
13
  import com.devbrackets.android.playlistcore.listener.PlaylistListener;
19
14
  import com.devbrackets.android.playlistcore.listener.ProgressListener;
20
- import com.devbrackets.android.playlistcore.listener.PlaybackStatusListener;
21
- import com.devbrackets.android.exomedia.listener.OnErrorListener;
22
15
  import com.google.android.exoplayer2.ExoPlaybackException;
23
16
 
17
+ import org.dwbn.plugins.playlist.data.AudioTrack;
18
+ import org.dwbn.plugins.playlist.manager.MediaControlsListener;
19
+ import org.dwbn.plugins.playlist.manager.Options;
20
+ import org.dwbn.plugins.playlist.manager.PlaylistManager;
21
+ import org.json.JSONException;
22
+ import org.json.JSONObject;
23
+
24
24
  /**
25
- *
26
- * The implementation of this player borrows from ExoMedia's demo example
27
- * and utilizes heavily those classes, basically because that is "the" way
28
- * to actually use ExoMedia.
29
- */
25
+ * The implementation of this player borrows from ExoMedia's demo example
26
+ * and utilizes heavily those classes, basically because that is "the" way
27
+ * to actually use ExoMedia.
28
+ */
30
29
  public class RmxAudioPlayer implements PlaybackStatusListener<AudioTrack>,
31
- PlaylistListener<AudioTrack>, ProgressListener, OnErrorListener, MediaControlsListener {
32
-
33
- public static String TAG = "RmxAudioPlayer";
34
-
35
- // PlaylistCore requires this but we don't use it
36
- // It would be used to switch between playlists. I guess we could
37
- // support that in the future, might be cool.
38
- private static final int PLAYLIST_ID = 32;
39
- private PlaylistManager playlistManager;
40
- private OnStatusReportListener statusListener;
41
-
42
- private int lastBufferPercent = 0;
43
- private boolean trackDuration = false;
44
- private boolean trackLoaded = false;
45
- private boolean resetStreamOnPause = true;
46
- private Options options;
47
- private App app;
48
-
49
- public RmxAudioPlayer(@NonNull OnStatusReportListener statusListener, App context) {
50
- // AudioPlayerPlugin and RmxAudioPlayer are separate classes in order to increase
51
- // the portability of this code.
52
- // Because AudioPlayerPlugin itself holds a strong reference to this class,
53
- // we can hold a strong reference to this shared callback. Normally not a good idea
54
- // but these two objects will always live together (And the plugin couldn't function
55
- // at all if this one gets garbage collected).
56
- this.statusListener = statusListener;
57
- this.app = context;
58
-
59
- getPlaylistManager();
60
- playlistManager.setId(PLAYLIST_ID);
61
- playlistManager.setPlaybackStatusListener(this);
62
- playlistManager.setOnErrorListener(this);
63
- playlistManager.setMediaControlsListener(this);
64
- this.options = new Options(context);
65
- }
66
-
67
- public PlaylistManager getPlaylistManager() {
68
- playlistManager = app.getPlaylistManager();
69
- return playlistManager;
70
- }
71
-
72
- public boolean getResetStreamOnPause() {
73
- return resetStreamOnPause;
74
- }
75
-
76
- public void setResetStreamOnPause(boolean val) {
77
- resetStreamOnPause = val;
78
- getPlaylistManager().setResetStreamOnPause(getResetStreamOnPause());
79
- }
80
-
81
- public void setOptions(JSONObject val) {
82
- Options options = new Options(app, val);
83
- getPlaylistManager().setOptions(options);
84
- }
85
-
86
- public float getVolume() {
87
- return (getVolumeLeft() + getVolumeRight()) / 2f;
88
- }
89
-
90
- public float getVolumeLeft() {
91
- return playlistManager.getVolumeLeft();
92
- }
93
-
94
- public float getVolumeRight() {
95
- return playlistManager.getVolumeRight();
96
- }
97
-
98
- public void setVolume(float both) {
99
- setVolume(both, both);
100
- }
101
-
102
- public void setVolume(float left, float right) {
103
- playlistManager.setVolume(left, right);
104
- }
105
-
106
-
107
- @Override
108
- public void onPrevious(AudioTrack currentItem, int currentIndex) {
109
- JSONObject param = new JSONObject();
110
- String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
111
-
112
- try {
113
- param.put("currentIndex", currentIndex);
114
- param.put("currentItem", currentItem != null ? currentItem.toDict() : null);
115
- } catch (JSONException e) {
116
- Log.i(TAG, "Error generating onPrevious status message: " + e.toString());
30
+ PlaylistListener<AudioTrack>, ProgressListener, OnErrorListener, MediaControlsListener {
31
+
32
+ public static String TAG = "RmxAudioPlayer";
33
+
34
+ // PlaylistCore requires this but we don't use it
35
+ // It would be used to switch between playlists. I guess we could
36
+ // support that in the future, might be cool.
37
+ private static final int PLAYLIST_ID = 32;
38
+ private PlaylistManager playlistManager;
39
+ private final OnStatusReportListener statusListener;
40
+
41
+ private int lastBufferPercent = 0;
42
+ private boolean trackDuration = false;
43
+ private boolean trackLoaded = false;
44
+ private boolean resetStreamOnPause = true;
45
+ private final App app;
46
+
47
+ public RmxAudioPlayer(@NonNull OnStatusReportListener statusListener, App context) {
48
+ // AudioPlayerPlugin and RmxAudioPlayer are separate classes in order to increase
49
+ // the portability of this code.
50
+ // Because AudioPlayerPlugin itself holds a strong reference to this class,
51
+ // we can hold a strong reference to this shared callback. Normally not a good idea
52
+ // but these two objects will always live together (And the plugin couldn't function
53
+ // at all if this one gets garbage collected).
54
+ this.statusListener = statusListener;
55
+ this.app = context;
56
+
57
+ getPlaylistManager();
58
+ playlistManager.setId(PLAYLIST_ID);
59
+ playlistManager.setPlaybackStatusListener(this);
60
+ playlistManager.setOnErrorListener(this);
61
+ playlistManager.setMediaControlsListener(this);
62
+ }
63
+
64
+ public PlaylistManager getPlaylistManager() {
65
+ playlistManager = app.getPlaylistManager();
66
+ return playlistManager;
67
+ }
68
+
69
+ public boolean getResetStreamOnPause() {
70
+ return resetStreamOnPause;
71
+ }
72
+
73
+ public void setResetStreamOnPause(boolean val) {
74
+ resetStreamOnPause = val;
75
+ getPlaylistManager().setResetStreamOnPause(getResetStreamOnPause());
76
+ }
77
+
78
+ public void setOptions(JSONObject val) {
79
+ Options options = new Options(app, val);
80
+ getPlaylistManager().setOptions(options);
81
+ }
82
+
83
+ public float getVolume() {
84
+ return (getVolumeLeft() + getVolumeRight()) / 2f;
117
85
  }
118
86
 
119
- onStatus(RmxAudioStatusMessage.RMX_STATUS_SKIP_BACK, trackId, param);
120
- }
87
+ public float getVolumeLeft() {
88
+ return playlistManager.getVolumeLeft();
89
+ }
121
90
 
122
- @Override
123
- public void onNext(AudioTrack currentItem, int currentIndex) {
124
- JSONObject param = new JSONObject();
125
- String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
91
+ public float getVolumeRight() {
92
+ return playlistManager.getVolumeRight();
93
+ }
94
+
95
+ public void setVolume(float both) {
96
+ setVolume(both, both);
97
+ }
98
+
99
+ public void setVolume(float left, float right) {
100
+ playlistManager.setVolume(left, right);
101
+ }
102
+
103
+
104
+ @Override
105
+ public void onPrevious(AudioTrack currentItem, int currentIndex) {
106
+ JSONObject param = new JSONObject();
107
+ String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
108
+
109
+ try {
110
+ param.put("currentIndex", currentIndex);
111
+ param.put("currentItem", currentItem != null ? currentItem.toDict() : null);
112
+ } catch (JSONException e) {
113
+ Log.i(TAG, "Error generating onPrevious status message: " + e.toString());
114
+ }
126
115
 
127
- try {
128
- param.put("currentIndex", currentIndex);
129
- param.put("currentItem", currentItem != null ? currentItem.toDict() : null);
130
- } catch (JSONException e) {
131
- Log.i(TAG, "Error generating onNext status message: " + e.toString());
116
+ onStatus(RmxAudioStatusMessage.RMX_STATUS_SKIP_BACK, trackId, param);
132
117
  }
133
- onStatus(RmxAudioStatusMessage.RMX_STATUS_SKIP_FORWARD, trackId, param);
134
- }
135
-
136
- @Override
137
- public boolean onError(Exception e) {
138
- String errorMsg = e.toString();
139
- RmxAudioErrorType errorType = RmxAudioErrorType.RMXERR_NONE_SUPPORTED;
140
-
141
- if (e instanceof ExoPlaybackException) {
142
- switch (((ExoPlaybackException) e).type) {
143
- case ExoPlaybackException.TYPE_SOURCE:
144
- errorMsg = "ExoPlaybackException.TYPE_SOURCE: " + ((ExoPlaybackException) e).getSourceException().getMessage();
145
- break;
146
- case ExoPlaybackException.TYPE_RENDERER:
147
- errorType = RmxAudioErrorType.RMXERR_DECODE;
148
- errorMsg = "ExoPlaybackException.TYPE_RENDERER: " + ((ExoPlaybackException) e).getRendererException().getMessage();
149
- break;
150
- case ExoPlaybackException.TYPE_UNEXPECTED:
151
- errorType = RmxAudioErrorType.RMXERR_DECODE;
152
- errorMsg = "ExoPlaybackException.TYPE_UNEXPECTED: " + ((ExoPlaybackException) e).getUnexpectedException().getMessage();
153
- break;
154
- }
155
- }
156
-
157
- AudioTrack errorItem = playlistManager.getCurrentErrorTrack();
158
- String trackId = errorItem != null ? errorItem.getTrackId() : "INVALID";
159
-
160
- Log.i(TAG, "Error playing audio track: [" + trackId + "]: " + errorMsg);
161
- onError(errorType, trackId, errorMsg);
162
- playlistManager.setCurrentErrorTrack(null);
163
- return true;
164
- }
165
-
166
- @Override
167
- public void onMediaPlaybackStarted(AudioTrack item, long currentPosition, long duration) {
168
- Log.i(TAG, "onMediaPlaybackStarted: ==> " + item.getTitle() + ": " + currentPosition + "," + duration);
169
- // this is the first place that valid duration is seen. Immediately before, we get the PLAYING status change,
170
- // and before that, it announces PREPARING twice and all values are 0.
171
- // Problem is, this method is only called if playback is already in progress when the track changes,
172
- // which is useless in most cases. So, these values are actually handled in onProgressUpdated.
173
- }
174
-
175
- @Override
176
- public void onItemPlaybackEnded(AudioTrack item) {
177
- AudioTrack nextItem = playlistManager.getCurrentItem();
178
- // String title = item != null ? item.getTitle() : "(null)";
179
- // String currTitle = nextItem != null ? nextItem.getTitle() : "(null)";
180
- // String currTrackId = nextItem != null ? nextItem.getTrackId() : null;
181
- // Log.i(TAG, "onItemPlaybackEnded: ==> " + title + "," + trackId + " ==> next item: " + currTitle + "," + currTrackId);
182
-
183
- if (item != null) {
184
- String trackId = item.getTrackId();
185
- JSONObject trackStatus = getPlayerStatus(item);
186
- onStatus(RmxAudioStatusMessage.RMXSTATUS_COMPLETED, trackId, trackStatus);
187
- }
188
-
189
- if (nextItem == null) { // if (!playlistManager.isNextAvailable()) {
190
- onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYLIST_COMPLETED, "INVALID", null);
191
- }
192
- }
193
-
194
- @Override
195
- public void onPlaylistEnded() {
196
- Log.i(TAG, "onPlaylistEnded");
197
- playlistManager.setShouldStopPlaylist(false);
198
- }
199
-
200
- @Override
201
- public boolean onPlaylistItemChanged(@Nullable AudioTrack currentItem, boolean hasNext, boolean hasPrevious) {
202
- JSONObject info = new JSONObject();
203
- String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
204
- try {
205
- info.put("currentItem", currentItem != null ? currentItem.toDict() : null);
206
- info.put("currentIndex", playlistManager.getCurrentPosition());
207
- info.put("isAtEnd", !hasNext);
208
- info.put("isAtBeginning", !hasPrevious);
209
- info.put("hasNext", hasNext);
210
- info.put("hasPrevious", hasPrevious);
211
- } catch (JSONException e) {
212
- Log.e(TAG, "Error creating onPlaylistItemChanged message: " + e.toString());
213
- }
214
-
215
- lastBufferPercent = 0;
216
- trackDuration = false;
217
- trackLoaded = false;
218
-
219
- onStatus(RmxAudioStatusMessage.RMXSTATUS_TRACK_CHANGED, trackId, info);
220
- return true;
221
- }
222
-
223
- @Override
224
- public boolean onPlaybackStateChanged(@NonNull PlaybackState playbackState) {
225
- // in testing, I saw PREPARING, then PLAYING, and buffering happened
226
- // during PLAYING. Tapping play/pause toggles PLAYING and PAUSED
227
- // sending a seek command produces SEEKING here
228
- // RETRIEVING is never sent.
229
-
230
- AudioTrack currentItem = playlistManager.getCurrentItem();
231
- JSONObject trackStatus = getPlayerStatus(currentItem);
232
- Log.i("AudioPlayerActiv/opsc", playbackState.toString() + ", " + trackStatus.toString() + ", " + currentItem);
233
-
234
- switch (playbackState) {
235
- case STOPPED:
236
- onStatus(RmxAudioStatusMessage.RMXSTATUS_STOPPED, "INVALID", null);
237
- break;
238
-
239
- case RETRIEVING: // these are all loading states
240
- case PREPARING: {
241
- if (currentItem != null && currentItem.getTrackId() != null) {
242
- onStatus(RmxAudioStatusMessage.RMXSTATUS_LOADING, currentItem.getTrackId(), trackStatus);
118
+
119
+ @Override
120
+ public void onNext(AudioTrack currentItem, int currentIndex) {
121
+ JSONObject param = new JSONObject();
122
+ String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
123
+
124
+ try {
125
+ param.put("currentIndex", currentIndex);
126
+ param.put("currentItem", currentItem != null ? currentItem.toDict() : null);
127
+ } catch (JSONException e) {
128
+ Log.i(TAG, "Error generating onNext status message: " + e.toString());
129
+ }
130
+ onStatus(RmxAudioStatusMessage.RMX_STATUS_SKIP_FORWARD, trackId, param);
131
+ }
132
+
133
+ @Override
134
+ public boolean onError(Exception e) {
135
+ String errorMsg = e.toString();
136
+ RmxAudioErrorType errorType = RmxAudioErrorType.RMXERR_NONE_SUPPORTED;
137
+
138
+ if (e instanceof ExoPlaybackException) {
139
+ switch (((ExoPlaybackException) e).type) {
140
+ case ExoPlaybackException.TYPE_SOURCE:
141
+ errorMsg = "ExoPlaybackException.TYPE_SOURCE: " + ((ExoPlaybackException) e).getSourceException().getMessage();
142
+ break;
143
+ case ExoPlaybackException.TYPE_RENDERER:
144
+ errorType = RmxAudioErrorType.RMXERR_DECODE;
145
+ errorMsg = "ExoPlaybackException.TYPE_RENDERER: " + ((ExoPlaybackException) e).getRendererException().getMessage();
146
+ break;
147
+ case ExoPlaybackException.TYPE_UNEXPECTED:
148
+ errorType = RmxAudioErrorType.RMXERR_DECODE;
149
+ errorMsg = "ExoPlaybackException.TYPE_UNEXPECTED: " + ((ExoPlaybackException) e).getUnexpectedException().getMessage();
150
+ break;
243
151
  }
244
- break;
245
- }
246
- case SEEKING:{
247
- MediaProgress progress = playlistManager.getCurrentProgress();
248
- if (currentItem != null && currentItem.getTrackId() != null && progress != null) {
249
- JSONObject info = new JSONObject();
250
- try {
251
- info.put("position", progress.getPosition() / 1000f);
252
- onStatus(RmxAudioStatusMessage.RMXSTATUS_SEEK, currentItem.getTrackId(), info);
253
- } catch (JSONException e) {
254
- Log.e(TAG, "Error generating seeking status message: " + e.toString());
152
+ }
153
+
154
+ AudioTrack errorItem = playlistManager.getCurrentErrorTrack();
155
+ String trackId = errorItem != null ? errorItem.getTrackId() : "INVALID";
156
+
157
+ Log.i(TAG, "Error playing audio track: [" + trackId + "]: " + errorMsg);
158
+ onError(errorType, trackId, errorMsg);
159
+ playlistManager.setCurrentErrorTrack(null);
160
+ return true;
161
+ }
162
+
163
+ @Override
164
+ public void onMediaPlaybackStarted(AudioTrack item, long currentPosition, long duration) {
165
+ Log.i(TAG, "onMediaPlaybackStarted: ==> " + item.getTitle() + ": " + currentPosition + "," + duration);
166
+ // this is the first place that valid duration is seen. Immediately before, we get the PLAYING status change,
167
+ // and before that, it announces PREPARING twice and all values are 0.
168
+ // Problem is, this method is only called if playback is already in progress when the track changes,
169
+ // which is useless in most cases. So, these values are actually handled in onProgressUpdated.
170
+ }
171
+
172
+ @Override
173
+ public void onItemPlaybackEnded(AudioTrack item) {
174
+ AudioTrack nextItem = playlistManager.getCurrentItem();
175
+ // String title = item != null ? item.getTitle() : "(null)";
176
+ // String currTitle = nextItem != null ? nextItem.getTitle() : "(null)";
177
+ // String currTrackId = nextItem != null ? nextItem.getTrackId() : null;
178
+ // Log.i(TAG, "onItemPlaybackEnded: ==> " + title + "," + trackId + " ==> next item: " + currTitle + "," + currTrackId);
179
+
180
+ if (item != null) {
181
+ String trackId = item.getTrackId();
182
+ JSONObject trackStatus = getPlayerStatus(item);
183
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_COMPLETED, trackId, trackStatus);
184
+ }
185
+
186
+ if (nextItem == null) { // if (!playlistManager.isNextAvailable()) {
187
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYLIST_COMPLETED, "INVALID", null);
188
+ }
189
+ }
190
+
191
+ @Override
192
+ public void onPlaylistEnded() {
193
+ Log.i(TAG, "onPlaylistEnded");
194
+ playlistManager.setShouldStopPlaylist(false);
195
+ }
196
+
197
+ @Override
198
+ public boolean onPlaylistItemChanged(@Nullable AudioTrack currentItem, boolean hasNext, boolean hasPrevious) {
199
+ JSONObject info = new JSONObject();
200
+ String trackId = currentItem == null ? "NONE" : currentItem.getTrackId();
201
+ try {
202
+ info.put("currentItem", currentItem != null ? currentItem.toDict() : null);
203
+ info.put("currentIndex", playlistManager.getCurrentPosition());
204
+ info.put("isAtEnd", !hasNext);
205
+ info.put("isAtBeginning", !hasPrevious);
206
+ info.put("hasNext", hasNext);
207
+ info.put("hasPrevious", hasPrevious);
208
+ } catch (JSONException e) {
209
+ Log.e(TAG, "Error creating onPlaylistItemChanged message: " + e.toString());
210
+ }
211
+
212
+ lastBufferPercent = 0;
213
+ trackDuration = false;
214
+ trackLoaded = false;
215
+
216
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_TRACK_CHANGED, trackId, info);
217
+ return true;
218
+ }
219
+
220
+ @Override
221
+ public boolean onPlaybackStateChanged(@NonNull PlaybackState playbackState) {
222
+ // in testing, I saw PREPARING, then PLAYING, and buffering happened
223
+ // during PLAYING. Tapping play/pause toggles PLAYING and PAUSED
224
+ // sending a seek command produces SEEKING here
225
+ // RETRIEVING is never sent.
226
+
227
+ AudioTrack currentItem = playlistManager.getCurrentItem();
228
+ JSONObject trackStatus = getPlayerStatus(currentItem);
229
+ Log.i("onPlaybackStateChanged", playbackState.toString() + ", " + trackStatus.toString() + ", " + currentItem);
230
+
231
+ switch (playbackState) {
232
+ case STOPPED:
233
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_STOPPED, "INVALID", null);
234
+ break;
235
+
236
+ case RETRIEVING: // these are all loading states
237
+ case PREPARING: {
238
+ if (currentItem != null && currentItem.getTrackId() != null) {
239
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_LOADING, currentItem.getTrackId(), trackStatus);
255
240
  }
241
+ break;
256
242
  }
257
- break;
258
- }
259
- case PLAYING:
260
- if (currentItem != null && currentItem.getTrackId() != null) {
261
- // Can also check here that duration == 0, because that is what happens on the first PLAYING invokation.
262
- // We'll leave this for now.
263
- if (!trackLoaded) {
243
+ case SEEKING: {
244
+ MediaProgress progress = playlistManager.getCurrentProgress();
245
+ if (currentItem != null && currentItem.getTrackId() != null && progress != null) {
246
+ JSONObject info = new JSONObject();
247
+ try {
248
+ info.put("position", progress.getPosition() / 1000f);
249
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_SEEK, currentItem.getTrackId(), info);
250
+ } catch (JSONException e) {
251
+ Log.e(TAG, "Error generating seeking status message: " + e.toString());
252
+ }
253
+ }
254
+ break;
255
+ }
256
+ case PLAYING:
257
+ if (currentItem != null && currentItem.getTrackId() != null) {
258
+ // Can also check here that duration == 0, because that is what happens on the first PLAYING invokation.
259
+ // We'll leave this for now.
260
+ if (!trackLoaded) {
261
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_CANPLAY, currentItem.getTrackId(), trackStatus);
262
+ trackLoaded = true;
263
+ }
264
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYING, currentItem.getTrackId(), trackStatus);
265
+ }
266
+ break;
267
+ case PAUSED:
268
+ if (currentItem != null && currentItem.getTrackId() != null) {
269
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_PAUSE, currentItem.getTrackId(), trackStatus);
270
+ }
271
+ break;
272
+ // we'll handle error in the listener. ExoMedia only raises this in the case of catastrophic player failure.
273
+ case ERROR:
274
+ default:
275
+ break;
276
+ }
277
+
278
+ return true;
279
+ }
280
+
281
+ @Override
282
+ public boolean onProgressUpdated(@NonNull MediaProgress progress) {
283
+ // Order matters here. We must update the item's duration and buffer before pulling the track status,
284
+ // because those values are adjusted to account for the buffering-reset in ExoPlayer.
285
+ AudioTrack currentItem = playlistManager.getCurrentItem();
286
+ PlaybackState playbackState = playlistManager.getCurrentPlaybackState();
287
+
288
+ if (currentItem != null) { // I mean, this call makes no sense otherwise..
289
+ currentItem.setDuration(progress.getDuration());
290
+ currentItem.setBufferPercent(progress.getBufferPercent());
291
+ currentItem.setBufferPercentFloat(progress.getBufferPercentFloat());
292
+
293
+ JSONObject trackStatus = getPlayerStatus(currentItem);
294
+
295
+ if (progress.getBufferPercent() != lastBufferPercent) {
296
+ if (progress.getBufferPercent() >= 100f) {
297
+ // Unlike iOS this will get raised continuously.
298
+ // Extracting the source event from playlistcore would be really hard.
299
+ // The gate above should do the trick.
300
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_LOADED, currentItem.getTrackId(), trackStatus);
301
+ }
302
+
303
+ if (!trackLoaded) {
264
304
  onStatus(RmxAudioStatusMessage.RMXSTATUS_CANPLAY, currentItem.getTrackId(), trackStatus);
265
305
  trackLoaded = true;
266
- }
267
- onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYING, currentItem.getTrackId(), trackStatus);
268
- }
269
- break;
270
- case PAUSED:
271
- if (currentItem != null && currentItem.getTrackId() != null) {
272
- onStatus(RmxAudioStatusMessage.RMXSTATUS_PAUSE, currentItem.getTrackId(), trackStatus);
273
- }
274
- break;
275
- // we'll handle error in the listener. ExoMedia only raises this in the case of catastrophic player failure.
276
- case ERROR:
277
- default:
278
- break;
279
- }
280
-
281
- return true;
282
- }
283
-
284
- @Override
285
- public boolean onProgressUpdated(@NonNull MediaProgress progress) {
286
- // Order matters here. We must update the item's duration and buffer before pulling the track status,
287
- // because those values are adjusted to account for the buffering-reset in ExoPlayer.
288
- AudioTrack currentItem = playlistManager.getCurrentItem();
289
- PlaybackState playbackState = playlistManager.getCurrentPlaybackState();
290
-
291
- if (currentItem != null) { // I mean, this call makes no sense otherwise..
292
- currentItem.setDuration(progress.getDuration());
293
- currentItem.setBufferPercent(progress.getBufferPercent());
294
- currentItem.setBufferPercentFloat(progress.getBufferPercentFloat());
306
+ }
295
307
 
296
- JSONObject trackStatus = getPlayerStatus(currentItem);
308
+ if (!trackDuration && progress.getDuration() > 0) {
309
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_DURATION, currentItem.getTrackId(), trackStatus);
310
+ trackDuration = true;
311
+ }
297
312
 
298
- if (progress.getBufferPercent() != lastBufferPercent) {
299
- if (progress.getBufferPercent() >= 100f) {
300
- // Unlike iOS this will get raised continuously.
301
- // Extracting the source event from playlistcore would be really hard.
302
- // The gate above should do the trick.
303
- onStatus(RmxAudioStatusMessage.RMXSTATUS_LOADED, currentItem.getTrackId(), trackStatus);
313
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_BUFFERING, currentItem.getTrackId(), trackStatus);
314
+ lastBufferPercent = progress.getBufferPercent();
304
315
  }
305
316
 
306
- if (!trackLoaded) {
307
- onStatus(RmxAudioStatusMessage.RMXSTATUS_CANPLAY, currentItem.getTrackId(), trackStatus);
308
- trackLoaded = true;
317
+ // dont send on prepare, if null
318
+ if (playbackState == PlaybackState.PLAYING || playbackState == PlaybackState.SEEKING
319
+ || (playbackState == PlaybackState.PREPARING && progress.getDuration() == 0)) {
320
+ onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION, currentItem.getTrackId(), trackStatus);
309
321
  }
322
+ }
323
+
324
+ return true;
325
+ }
310
326
 
311
- if (!trackDuration && progress.getDuration() > 0) {
312
- onStatus(RmxAudioStatusMessage.RMXSTATUS_DURATION, currentItem.getTrackId(), trackStatus);
313
- trackDuration = true;
327
+ public JSONObject getPlayerStatus(@Nullable AudioTrack statusItem) {
328
+ // TODO: Make this its own object.
329
+ AudioTrack currentItem = statusItem != null ? statusItem : playlistManager.getCurrentItem();
330
+ PlaybackState playbackState = playlistManager.getCurrentPlaybackState();
331
+ MediaProgress progress = playlistManager.getCurrentProgress();
332
+
333
+ String status = "unknown";
334
+ switch (playbackState) {
335
+ case STOPPED: {
336
+ status = "stopped";
337
+ break;
338
+ }
339
+ case ERROR: {
340
+ status = "error";
341
+ break;
342
+ }
343
+ case RETRIEVING:
344
+ case SEEKING: // { status = "seeking"; break; } // seeking === loading
345
+ case PREPARING: {
346
+ status = "loading";
347
+ break;
314
348
  }
349
+ case PLAYING: {
350
+ status = "playing";
351
+ break;
352
+ }
353
+ case PAUSED: {
354
+ status = "paused";
355
+ break;
356
+ }
357
+ default:
358
+ break;
359
+ }
315
360
 
316
- onStatus(RmxAudioStatusMessage.RMXSTATUS_BUFFERING, currentItem.getTrackId(), trackStatus);
317
- lastBufferPercent = progress.getBufferPercent();
361
+ String trackId = "";
362
+ boolean isStream = false;
363
+ float bufferPercentFloat = 0;
364
+ int bufferPercent = 0;
365
+ long duration = 0;
366
+ long position = 0;
367
+
368
+ // The media players hold onto their current playback position between songs,
369
+ // despite my efforts to reset it. So we will just filter out this state.
370
+ if (progress != null) { // && !status.equals("loading")) {
371
+ position = progress.getPosition();
318
372
  }
319
373
 
320
- // dont send on prepare, if null
321
- if (playbackState == PlaybackState.PLAYING || playbackState == PlaybackState.SEEKING
322
- || (playbackState == PlaybackState.PREPARING && progress.getDuration() == 0)) {
323
- onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION, currentItem.getTrackId(), trackStatus);
374
+ // the position and duration vals are in milliseconds.
375
+ if (currentItem != null) {
376
+ isStream = currentItem.isStream();
377
+ trackId = currentItem.getTrackId();
378
+ bufferPercentFloat = currentItem.getBufferPercentFloat(); // progress.
379
+ bufferPercent = currentItem.getBufferPercent(); // progress.
380
+ duration = currentItem.getDuration(); // progress.
324
381
  }
325
- }
326
-
327
- return true;
328
- }
329
-
330
- public JSONObject getPlayerStatus(@Nullable AudioTrack statusItem) {
331
- // TODO: Make this its own object.
332
- AudioTrack currentItem = statusItem != null ? statusItem : playlistManager.getCurrentItem();
333
- PlaybackState playbackState = playlistManager.getCurrentPlaybackState();
334
- MediaProgress progress = playlistManager.getCurrentProgress();
335
-
336
- String status = "unknown";
337
- switch (playbackState) {
338
- case STOPPED: { status = "stopped"; break; }
339
- case ERROR: { status = "error"; break; }
340
- case RETRIEVING:
341
- case SEEKING: // { status = "seeking"; break; } // seeking === loading
342
- case PREPARING: { status = "loading"; break; }
343
- case PLAYING: { status = "playing"; break; }
344
- case PAUSED: { status = "paused"; break; }
345
- default:
346
- break;
347
- }
348
382
 
349
- String trackId = "";
350
- boolean isStream = false;
351
- float bufferPercentFloat = 0;
352
- int bufferPercent = 0;
353
- long duration = 0;
354
- long position = 0;
355
-
356
- // The media players hold onto their current playback position between songs,
357
- // despite my efforts to reset it. So we will just filter out this state.
358
- if (progress != null) { // && !status.equals("loading")) {
359
- position = progress.getPosition();
360
- }
383
+ JSONObject trackStatus = new JSONObject();
384
+ try {
385
+ trackStatus.put("trackId", trackId);
386
+ trackStatus.put("isStream", isStream);
387
+ trackStatus.put("currentIndex", playlistManager.getCurrentPosition());
388
+ trackStatus.put("status", status);
389
+ trackStatus.put("currentPosition", position / 1000.0);
390
+ trackStatus.put("duration", duration / 1000.0);
391
+ trackStatus.put("playbackPercent", duration > 0 ? (((double) position / duration) * 100.0) : 0);
392
+ trackStatus.put("bufferPercent", bufferPercent);
393
+ trackStatus.put("bufferStart", 0.0);
394
+ trackStatus.put("bufferEnd", (bufferPercentFloat * duration) / 1000.0);
395
+ } catch (JSONException e) {
396
+ Log.e(TAG, "Error generating player status: " + e.toString());
397
+ }
361
398
 
362
- // the position and duration vals are in milliseconds.
363
- if (currentItem != null) {
364
- isStream = currentItem.isStream();
365
- trackId = currentItem.getTrackId();
366
- bufferPercentFloat = currentItem.getBufferPercentFloat(); // progress.
367
- bufferPercent = currentItem.getBufferPercent(); // progress.
368
- duration = currentItem.getDuration(); // progress.
399
+ return trackStatus;
369
400
  }
370
401
 
371
- JSONObject trackStatus = new JSONObject();
372
- try {
373
- trackStatus.put("trackId", trackId);
374
- trackStatus.put("isStream", isStream);
375
- trackStatus.put("currentIndex", playlistManager.getCurrentPosition());
376
- trackStatus.put("status", status);
377
- trackStatus.put("currentPosition", position / 1000.0);
378
- trackStatus.put("duration", duration / 1000.0);
379
- trackStatus.put("playbackPercent", duration > 0 ? (((double)position / duration) * 100.0) : 0);
380
- trackStatus.put("bufferPercent", bufferPercent);
381
- trackStatus.put("bufferStart", 0.0);
382
- trackStatus.put("bufferEnd", (bufferPercentFloat * duration) / 1000.0);
383
- } catch (JSONException e) {
384
- Log.e(TAG, "Error generating player status: " + e.toString());
402
+ public void pause() {
403
+ Log.i(TAG, "Pausing, removing event listeners");
404
+ removePlaylistListeners();
385
405
  }
386
406
 
387
- return trackStatus;
388
- }
389
-
390
- public void pause() {
391
- Log.i(TAG, "Pausing, removing event listeners");
392
- removePlaylistListeners();
393
- }
394
-
395
- public void resume() {
396
- Log.i(TAG, "Resumed, wiring up event listeners");
397
- getPlaylistManager();
398
- registerPlaylistListeners();
399
- //Makes sure to retrieve the current playback information
400
- updateCurrentPlaybackInformation();
401
- }
402
-
403
- private void updateCurrentPlaybackInformation() {
404
- PlaylistItemChange<AudioTrack> itemChange = playlistManager.getCurrentItemChange();
405
- if (itemChange != null) {
406
- onPlaylistItemChanged(itemChange.getCurrentItem(), itemChange.getHasNext(), itemChange.getHasPrevious());
407
+ public void resume() {
408
+ Log.i(TAG, "Resumed, wiring up event listeners");
409
+ getPlaylistManager();
410
+ registerPlaylistListeners();
411
+ //Makes sure to retrieve the current playback information
412
+ updateCurrentPlaybackInformation();
407
413
  }
408
414
 
409
- PlaybackState currentPlaybackState = playlistManager.getCurrentPlaybackState();
410
- if (currentPlaybackState != PlaybackState.STOPPED) {
411
- onPlaybackStateChanged(currentPlaybackState);
412
- }
415
+ private void updateCurrentPlaybackInformation() {
416
+ PlaylistItemChange<AudioTrack> itemChange = playlistManager.getCurrentItemChange();
417
+ if (itemChange != null) {
418
+ onPlaylistItemChanged(itemChange.getCurrentItem(), itemChange.getHasNext(), itemChange.getHasPrevious());
419
+ }
420
+
421
+ PlaybackState currentPlaybackState = playlistManager.getCurrentPlaybackState();
422
+ if (currentPlaybackState != PlaybackState.STOPPED) {
423
+ onPlaybackStateChanged(currentPlaybackState);
424
+ }
413
425
 
414
- MediaProgress mediaProgress = playlistManager.getCurrentProgress();
415
- if (mediaProgress != null) {
416
- onProgressUpdated(mediaProgress);
426
+ MediaProgress mediaProgress = playlistManager.getCurrentProgress();
427
+ if (mediaProgress != null) {
428
+ onProgressUpdated(mediaProgress);
429
+ }
417
430
  }
418
- }
419
431
 
420
- private void registerPlaylistListeners() {
421
- playlistManager.registerPlaylistListener(this);
422
- playlistManager.registerProgressListener(this);
423
- }
432
+ private void registerPlaylistListeners() {
433
+ playlistManager.registerPlaylistListener(this);
434
+ playlistManager.registerProgressListener(this);
435
+ }
424
436
 
425
- private void removePlaylistListeners() {
426
- playlistManager.unRegisterPlaylistListener(this);
427
- playlistManager.unRegisterProgressListener(this);
428
- }
437
+ private void removePlaylistListeners() {
438
+ playlistManager.unRegisterPlaylistListener(this);
439
+ playlistManager.unRegisterProgressListener(this);
440
+ }
429
441
 
430
- private void onError(RmxAudioErrorType errorCode, String trackId, String message) {
431
- statusListener.onError(errorCode, trackId, message);
432
- }
442
+ private void onError(RmxAudioErrorType errorCode, String trackId, String message) {
443
+ statusListener.onError(errorCode, trackId, message);
444
+ }
433
445
 
434
- private void onStatus(RmxAudioStatusMessage what, String trackId, JSONObject param) {
435
- statusListener.onStatus(what, trackId, param);
436
- }
446
+ private void onStatus(RmxAudioStatusMessage what, String trackId, JSONObject param) {
447
+ statusListener.onStatus(what, trackId, param);
448
+ }
437
449
  }