capacitor-plugin-playlist 0.4.0 → 0.4.1

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 (106) hide show
  1. package/android/.gradle/8.0.2/checksums/checksums.lock +0 -0
  2. package/android/.gradle/8.0.2/checksums/md5-checksums.bin +0 -0
  3. package/android/.gradle/8.0.2/checksums/sha1-checksums.bin +0 -0
  4. package/android/.gradle/8.0.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  5. package/android/.gradle/8.0.2/executionHistory/executionHistory.bin +0 -0
  6. package/android/.gradle/8.0.2/executionHistory/executionHistory.lock +0 -0
  7. package/android/.gradle/8.0.2/fileHashes/fileHashes.bin +0 -0
  8. package/android/.gradle/8.0.2/fileHashes/fileHashes.lock +0 -0
  9. package/android/.gradle/8.0.2/fileHashes/resourceHashesCache.bin +0 -0
  10. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  11. package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
  12. package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  13. package/android/.gradle/config.properties +2 -0
  14. package/android/.gradle/file-system.probe +0 -0
  15. package/android/.idea/compiler.xml +6 -0
  16. package/android/.idea/gradle.xml +8 -3
  17. package/android/.idea/kotlinc.xml +6 -0
  18. package/android/.idea/migrations.xml +10 -0
  19. package/android/.idea/misc.xml +2 -2
  20. package/android/.project +34 -0
  21. package/android/bin/.gradle/8.0.2/checksums/checksums.lock +0 -0
  22. package/android/bin/.gradle/8.0.2/checksums/md5-checksums.bin +0 -0
  23. package/android/bin/.gradle/8.0.2/checksums/sha1-checksums.bin +0 -0
  24. package/android/bin/.gradle/8.0.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  25. package/android/bin/.gradle/8.0.2/executionHistory/executionHistory.bin +0 -0
  26. package/android/bin/.gradle/8.0.2/executionHistory/executionHistory.lock +0 -0
  27. package/android/bin/.gradle/8.0.2/fileChanges/last-build.bin +0 -0
  28. package/android/bin/.gradle/8.0.2/fileHashes/fileHashes.bin +0 -0
  29. package/android/bin/.gradle/8.0.2/fileHashes/fileHashes.lock +0 -0
  30. package/android/bin/.gradle/8.0.2/fileHashes/resourceHashesCache.bin +0 -0
  31. package/android/bin/.gradle/8.0.2/gc.properties +0 -0
  32. package/android/bin/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  33. package/android/bin/.gradle/buildOutputCleanup/cache.properties +2 -0
  34. package/android/bin/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  35. package/android/bin/.gradle/config.properties +2 -0
  36. package/android/bin/.gradle/file-system.probe +0 -0
  37. package/android/bin/.gradle/vcs-1/gc.properties +0 -0
  38. package/android/bin/.idea/compiler.xml +6 -0
  39. package/android/bin/.idea/gradle.xml +19 -0
  40. package/android/bin/.idea/kotlinc.xml +6 -0
  41. package/android/bin/.idea/migrations.xml +10 -0
  42. package/android/bin/.idea/misc.xml +9 -0
  43. package/android/bin/.idea/vcs.xml +6 -0
  44. package/android/bin/.project +34 -0
  45. package/android/bin/.settings/org.eclipse.buildship.core.prefs +13 -0
  46. package/android/bin/build.gradle +79 -0
  47. package/android/bin/gradle/wrapper/gradle-wrapper.jar +0 -0
  48. package/android/bin/gradle/wrapper/gradle-wrapper.properties +6 -0
  49. package/android/bin/gradle.properties +22 -0
  50. package/android/bin/gradlew +244 -0
  51. package/android/bin/gradlew.bat +92 -0
  52. package/android/bin/local.properties +8 -0
  53. package/android/bin/proguard-rules.pro +21 -0
  54. package/android/bin/settings.gradle +2 -0
  55. package/android/bin/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.class +0 -0
  56. package/android/bin/src/main/AndroidManifest.xml +4 -0
  57. package/android/bin/src/main/java/org/dwbn/plugins/playlist/App.kt +62 -0
  58. package/android/bin/src/main/java/org/dwbn/plugins/playlist/FakeR.kt +39 -0
  59. package/android/bin/src/main/java/org/dwbn/plugins/playlist/OnStatusCallback.kt +34 -0
  60. package/android/bin/src/main/java/org/dwbn/plugins/playlist/OnStatusReportListener.class +0 -0
  61. package/android/bin/src/main/java/org/dwbn/plugins/playlist/PlaylistItemOptions.class +0 -0
  62. package/android/bin/src/main/java/org/dwbn/plugins/playlist/PlaylistPlugin.kt +356 -0
  63. package/android/bin/src/main/java/org/dwbn/plugins/playlist/RmxAudioErrorType.class +0 -0
  64. package/android/bin/src/main/java/org/dwbn/plugins/playlist/RmxAudioPlayer.class +0 -0
  65. package/android/bin/src/main/java/org/dwbn/plugins/playlist/RmxAudioStatusMessage.class +0 -0
  66. package/android/bin/src/main/java/org/dwbn/plugins/playlist/RmxConstants.class +0 -0
  67. package/android/bin/src/main/java/org/dwbn/plugins/playlist/TrackRemovalItem.class +0 -0
  68. package/android/bin/src/main/java/org/dwbn/plugins/playlist/data/AudioTrack.kt +94 -0
  69. package/android/bin/src/main/java/org/dwbn/plugins/playlist/manager/MediaControlsListener.kt +13 -0
  70. package/android/bin/src/main/java/org/dwbn/plugins/playlist/manager/Options.kt +77 -0
  71. package/android/bin/src/main/java/org/dwbn/plugins/playlist/manager/PlaylistManager.kt +286 -0
  72. package/android/bin/src/main/java/org/dwbn/plugins/playlist/notification/PlaylistNotificationProvider.kt +26 -0
  73. package/android/bin/src/main/java/org/dwbn/plugins/playlist/playlist/AudioApi.kt +101 -0
  74. package/android/bin/src/main/java/org/dwbn/plugins/playlist/playlist/AudioPlaylistHandler$Builder.class +0 -0
  75. package/android/bin/src/main/java/org/dwbn/plugins/playlist/playlist/AudioPlaylistHandler.class +0 -0
  76. package/android/bin/src/main/java/org/dwbn/plugins/playlist/playlist/BaseMediaApi.kt +40 -0
  77. package/android/bin/src/main/java/org/dwbn/plugins/playlist/service/MediaImageProvider.kt +79 -0
  78. package/android/bin/src/main/java/org/dwbn/plugins/playlist/service/MediaService.kt +53 -0
  79. package/android/bin/src/main/res/.gitkeep +0 -0
  80. package/android/bin/src/main/res/drawable/ic_closed_caption_white_24dp.xml +9 -0
  81. package/android/bin/src/main/res/drawable/ic_demo_icon_adaptive.xml +15 -0
  82. package/android/bin/src/main/res/drawable/ic_launcher_background.xml +48 -0
  83. package/android/bin/src/main/res/drawable/ic_launcher_foreground.xml +22 -0
  84. package/android/bin/src/main/res/drawable/ic_notification_icon.png +0 -0
  85. package/android/bin/src/main/res/layout/bridge_layout_main.xml +15 -0
  86. package/android/bin/src/main/res/values/colors.xml +3 -0
  87. package/android/bin/src/main/res/values/strings.xml +3 -0
  88. package/android/bin/src/main/res/values/styles.xml +3 -0
  89. package/android/bin/src/test/java/com/getcapacitor/ExampleUnitTest.class +0 -0
  90. package/android/build.gradle +0 -4
  91. package/android/local.properties +1 -1
  92. package/android/src/main/java/org/dwbn/plugins/playlist/manager/PlaylistManager.kt +2 -1
  93. package/dist/docs.json +1357 -3
  94. package/dist/esm/web.js +1 -6
  95. package/dist/esm/web.js.map +1 -1
  96. package/dist/plugin.cjs.js +1 -6
  97. package/dist/plugin.cjs.js.map +1 -1
  98. package/dist/plugin.js +1 -6
  99. package/dist/plugin.js.map +1 -1
  100. package/package.json +1 -1
  101. package/android/.gradle/checksums/checksums.lock +0 -0
  102. package/android/.gradle/checksums/md5-checksums.bin +0 -0
  103. package/android/.gradle/checksums/sha1-checksums.bin +0 -0
  104. package/android/.idea/modules/android.iml +0 -18
  105. package/android/.idea/modules.xml +0 -8
  106. /package/android/{.gradle/configuration-cache → bin/.gradle/8.0.2/dependencies-accessors}/gc.properties +0 -0
@@ -0,0 +1,94 @@
1
+ package org.dwbn.plugins.playlist.data
2
+
3
+ import com.devbrackets.android.playlistcore.annotation.SupportedMediaType
4
+ import com.devbrackets.android.playlistcore.api.PlaylistItem
5
+ import com.devbrackets.android.playlistcore.manager.BasePlaylistManager
6
+ import org.json.JSONException
7
+ import org.json.JSONObject
8
+
9
+ class AudioTrack (private val config: JSONObject) : PlaylistItem {
10
+ var bufferPercentFloat = 0f
11
+ set(buff) {
12
+ // There is a bug in MediaProgress where if bufferPercent == 100 it sets bufferPercentFloat
13
+ // to 100 instead of to 1.
14
+ field = Math.min(Math.max(bufferPercentFloat, buff), 1f)
15
+ }
16
+ var bufferPercent = 0
17
+ set(buff) {
18
+ field = Math.max(bufferPercent, buff)
19
+ }
20
+ var duration: Long = 0
21
+ set(dur) {
22
+ field = Math.max(0, dur)
23
+ }
24
+
25
+ fun toDict(): JSONObject {
26
+ val info = JSONObject()
27
+ try {
28
+ info.put("trackId", trackId)
29
+ info.put("isStream", isStream)
30
+ info.put("assetUrl", mediaUrl)
31
+ info.put("albumArt", thumbnailUrl)
32
+ info.put("artist", artist)
33
+ info.put("album", album)
34
+ info.put("title", title)
35
+ } catch (e: JSONException) {
36
+ // I can think of no reason this would ever fail
37
+ }
38
+ return info
39
+ }
40
+
41
+ override val id: Long
42
+ get() =
43
+ if (trackId == null) {
44
+ 0
45
+ } else trackId.hashCode().toLong()
46
+
47
+ val isStream: Boolean
48
+ get() = config.optBoolean("isStream", false)
49
+
50
+ val trackId: String?
51
+ get() {
52
+ val trackId = config.optString("trackId")
53
+ return if (trackId == "") {
54
+ null
55
+ } else trackId
56
+ }
57
+
58
+ // Would really like to set this to true once the cache has it...
59
+ override val downloaded: Boolean
60
+ get() = false // Would really like to set this to true once the cache has it...
61
+
62
+ // ... at which point we can return a value here.
63
+ override val downloadedMediaUri: String?
64
+ get() = null // ... at which point we can return a value here.
65
+
66
+ @get:SupportedMediaType
67
+ override val mediaType: Int
68
+ get() = BasePlaylistManager.AUDIO
69
+
70
+ override val mediaUrl: String
71
+ get() = config.optString("assetUrl", "")
72
+
73
+ // we should have a good default here.
74
+ override val thumbnailUrl: String?
75
+ get() {
76
+ val albumArt = config.optString("albumArt")
77
+ return if (albumArt == "") {
78
+ null
79
+ } else albumArt // we should have a good default here.
80
+ }
81
+
82
+ override val artworkUrl: String?
83
+ get() = thumbnailUrl
84
+
85
+ override val title: String
86
+ get() = config.optString("title")
87
+
88
+ override val album: String
89
+ get() = config.optString("album")
90
+
91
+ override val artist: String
92
+ get() = config.optString("artist")
93
+
94
+ }
@@ -0,0 +1,13 @@
1
+ package org.dwbn.plugins.playlist.manager
2
+
3
+ import org.dwbn.plugins.playlist.data.AudioTrack
4
+
5
+ /*
6
+ * Interface to enable the PlaylistManager to send these events out.
7
+ * We could add more like play/pause/toggle/stop, but right now there
8
+ * are other ways to get all the other information.
9
+ */
10
+ interface MediaControlsListener {
11
+ fun onNext(currentItem: AudioTrack?, currentIndex: Int)
12
+ fun onPrevious(currentItem: AudioTrack?, currentIndex: Int)
13
+ }
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Apache 2.0 License
3
+ *
4
+ * Copyright (c) Sebastian Katzer 2017
5
+ *
6
+ * This file contains Original Code and/or Modifications of Original Code
7
+ * as defined in and that are subject to the Apache License
8
+ * Version 2.0 (the 'License'). You may not use this file except in
9
+ * compliance with the License. Please obtain a copy of the License at
10
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
11
+ * file.
12
+ *
13
+ * The Original Code and all software distributed under the License are
14
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18
+ * Please see the License for the specific language governing rights and
19
+ * limitations under the License.
20
+ */
21
+ package org.dwbn.plugins.playlist.manager
22
+
23
+ import android.content.Context
24
+ import org.json.JSONObject
25
+
26
+ class Options {
27
+ /**
28
+ * Wrapped JSON object.
29
+ */
30
+ // The original JSON object
31
+ val dict: JSONObject
32
+
33
+ /**
34
+ * Application context.
35
+ */
36
+ // The application context
37
+ val context: Context
38
+
39
+ /**
40
+ * Constructor
41
+ *
42
+ * @param context The application context.
43
+ */
44
+ constructor(context: Context) {
45
+ this.context = context
46
+ dict = JSONObject()
47
+ }
48
+
49
+ /**
50
+ * Constructor
51
+ *
52
+ * @param context The application context.
53
+ * @param options The options dict map.
54
+ */
55
+ constructor(context: Context, options: JSONObject) {
56
+ this.context = context
57
+ dict = options
58
+ }
59
+
60
+ /**
61
+ * JSON object as string.
62
+ */
63
+ override fun toString(): String {
64
+ return dict.toString()
65
+ }
66
+
67
+ /**
68
+ * icon resource ID for the local notification.
69
+ */
70
+ val icon: String
71
+ get() = dict.optString("icon", DEFAULT_ICON)
72
+
73
+ companion object {
74
+ // Default icon path
75
+ private const val DEFAULT_ICON = "icon"
76
+ }
77
+ }
@@ -0,0 +1,286 @@
1
+ package org.dwbn.plugins.playlist.manager
2
+
3
+ import android.app.Application
4
+ import android.util.Log
5
+ import androidx.annotation.FloatRange
6
+ import androidx.annotation.IntRange
7
+ import com.devbrackets.android.exomedia.listener.OnErrorListener
8
+ import com.devbrackets.android.playlistcore.api.MediaPlayerApi
9
+ import com.devbrackets.android.playlistcore.manager.ListPlaylistManager
10
+ import org.dwbn.plugins.playlist.PlaylistItemOptions
11
+ import org.dwbn.plugins.playlist.TrackRemovalItem
12
+ import org.dwbn.plugins.playlist.data.AudioTrack
13
+ import org.dwbn.plugins.playlist.playlist.AudioApi
14
+ import org.dwbn.plugins.playlist.service.MediaService
15
+ import java.lang.ref.WeakReference
16
+ import java.util.*
17
+
18
+ /**
19
+ * A PlaylistManager that extends the [ListPlaylistManager] for use with the
20
+ * [MediaService] which extends [com.devbrackets.android.playlistcore.service.BasePlaylistService].
21
+ */
22
+ class PlaylistManager(application: Application) :
23
+ ListPlaylistManager<AudioTrack>(application, MediaService::class.java), OnErrorListener {
24
+ private val audioTracks: MutableList<AudioTrack> = ArrayList()
25
+ private var volumeLeft = 1.0f
26
+ private var volumeRight = 1.0f
27
+ private var playbackSpeed = 1.0f
28
+ var loop = false
29
+ var isShouldStopPlaylist = false
30
+ var currentErrorTrack: AudioTrack? = null
31
+
32
+ // Really need a way to propagate the settings through the app
33
+ var resetStreamOnPause = true
34
+ var options: Options
35
+ private var mediaControlsListener = WeakReference<MediaControlsListener?>(null)
36
+ private var errorListener = WeakReference<OnErrorListener?>(null)
37
+ private var currentMediaPlayer: WeakReference<MediaPlayerApi<AudioTrack>?>? =
38
+ WeakReference(null)
39
+
40
+ fun setOnErrorListener(listener: OnErrorListener?) {
41
+ errorListener = WeakReference(listener)
42
+ }
43
+
44
+ fun setMediaControlsListener(listener: MediaControlsListener?) {
45
+ mediaControlsListener = WeakReference(listener)
46
+ }
47
+
48
+ val isPlaying: Boolean
49
+ get() = playlistHandler != null && playlistHandler!!.currentMediaPlayer != null && playlistHandler!!.currentMediaPlayer!!.isPlaying
50
+
51
+ override fun onError(e: Exception): Boolean {
52
+ Log.i(TAG, "onError: $e")
53
+ if (errorListener.get() != null) {
54
+ errorListener.get()!!.onError(e)
55
+ }
56
+ return true
57
+ }
58
+
59
+ /*
60
+ * isNextAvailable, getCurrentItem, and next() are overridden because there is
61
+ * a glaring bug in playlist core where when an item completes, isNextAvailable and
62
+ * getCurrentItem return wildly contradictory things, resulting in endless repeat
63
+ * of the last item in the playlist.
64
+ */
65
+ override val isNextAvailable: Boolean
66
+ get() {
67
+ if (itemCount == 1) {
68
+ return false;
69
+ }
70
+ val isAtEnd = currentPosition + 1 >= itemCount
71
+ val isConstrained = currentPosition + 1 in 0 until itemCount
72
+ return if (isAtEnd) {
73
+ loop
74
+ } else isConstrained
75
+ }
76
+
77
+ override operator fun next(): AudioTrack? {
78
+ if (isNextAvailable) {
79
+ val isAtEnd = currentPosition + 1 >= itemCount
80
+ if (isAtEnd && loop) {
81
+ currentPosition = 0
82
+ } else {
83
+ currentPosition = (currentPosition + 1).coerceAtMost(itemCount)
84
+ }
85
+ } else {
86
+ if (loop) {
87
+ currentPosition = INVALID_POSITION
88
+ } else {
89
+ isShouldStopPlaylist = true
90
+ return null
91
+ }
92
+ }
93
+
94
+ return currentItem
95
+ }
96
+
97
+
98
+ /*
99
+ * List management
100
+ */
101
+ fun setAllItems(items: List<AudioTrack>?, options: PlaylistItemOptions) {
102
+ clearItems()
103
+ addAllItems(items)
104
+ currentPosition = 0
105
+ // If the options said to start from a specific position, do so.
106
+ var seekStart: Long = 0
107
+ if (options.playFromPosition > 0) {
108
+ seekStart = options.playFromPosition
109
+ } else if (options.retainPosition) {
110
+ val progress = currentProgress
111
+ if (progress != null) {
112
+ seekStart = progress.position
113
+ }
114
+ }
115
+
116
+ // If the options said to start from a specific id, do so.
117
+ var idStart: String? = null
118
+ if (options.playFromId != null) {
119
+ idStart = options.playFromId
120
+ }
121
+ if (idStart != null && "" != idStart) {
122
+ val code = idStart.hashCode()
123
+ setCurrentItem(code.toLong())
124
+ }
125
+
126
+ // We assume that if the playlist is fully loaded in one go,
127
+ // that the next thing to happen will be to play. So let's start
128
+ // paused, which will allow the player to pre-buffer until the
129
+ // user says Go.
130
+ beginPlayback(seekStart, options.startPaused)
131
+ }
132
+
133
+ fun addItem(item: AudioTrack?) {
134
+ if (item == null) {
135
+ return
136
+ }
137
+ val countBefore = audioTracks.size;
138
+ audioTracks.add(item)
139
+ items = audioTracks
140
+ if (countBefore == 0) {
141
+ currentPosition = 0
142
+ beginPlayback(1, true)
143
+ }
144
+ if (this.playlistHandler != null) {
145
+ this.playlistHandler!!.updateMediaControls()
146
+ }
147
+ }
148
+
149
+ fun addAllItems(its: List<AudioTrack>?) {
150
+ val currentItem = currentItem // may be null
151
+ audioTracks.addAll(its!!)
152
+ items =
153
+ audioTracks // not *strictly* needed since they share the reference, but for good measure..
154
+ currentPosition = audioTracks.indexOf(currentItem)
155
+ }
156
+
157
+ fun removeItem(index: Int, itemId: String): AudioTrack? {
158
+ val wasPlaying = isPlaying
159
+ if (playlistHandler != null) {
160
+ playlistHandler!!.pause(true)
161
+ }
162
+ var currentPosition = currentPosition
163
+ var foundItem: AudioTrack? = null
164
+ var removingCurrent = false
165
+
166
+ // If isPlaying is true, and currentItem is not null,
167
+ // that implies that currentItem is the currently playing item.
168
+ // If removingCurrent gets set to true, we are removing the currently playing item,
169
+ // and we need to restart playback once we do.
170
+ val resolvedIndex = resolveItemPosition(index, itemId)
171
+ if (resolvedIndex >= 0) {
172
+ foundItem = audioTracks[resolvedIndex]
173
+ if (foundItem == currentItem) {
174
+ removingCurrent = true
175
+ }
176
+ audioTracks.removeAt(resolvedIndex)
177
+ }
178
+ items = audioTracks
179
+ currentPosition = if (removingCurrent) currentPosition else audioTracks.indexOf(currentItem)
180
+ beginPlayback(currentPosition.toLong(), !wasPlaying)
181
+ if (this.playlistHandler != null) {
182
+ this.playlistHandler!!.updateMediaControls()
183
+ }
184
+ return foundItem
185
+ }
186
+
187
+ fun removeAllItems(its: ArrayList<TrackRemovalItem>): ArrayList<AudioTrack> {
188
+ val removedTracks = ArrayList<AudioTrack>()
189
+ val wasPlaying = isPlaying
190
+ if (playlistHandler != null) {
191
+ playlistHandler!!.pause(true)
192
+ }
193
+ var currentPosition = currentPosition
194
+ val currentItem = currentItem // may be null
195
+ var removingCurrent = false
196
+ for (item in its) {
197
+ val resolvedIndex = resolveItemPosition(item.trackIndex, item.trackId)
198
+ if (resolvedIndex >= 0) {
199
+ val foundItem = audioTracks[resolvedIndex]
200
+ if (foundItem == currentItem) {
201
+ removingCurrent = true
202
+ }
203
+ removedTracks.add(foundItem)
204
+ audioTracks.removeAt(resolvedIndex)
205
+ }
206
+ }
207
+ items = audioTracks
208
+ currentPosition = if (removingCurrent) currentPosition else audioTracks.indexOf(currentItem)
209
+ beginPlayback(currentPosition.toLong(), !wasPlaying)
210
+ return removedTracks
211
+ }
212
+
213
+ fun clearItems() {
214
+ if (playlistHandler != null) {
215
+ playlistHandler!!.stop()
216
+ }
217
+ audioTracks.clear()
218
+ items = audioTracks
219
+ currentPosition = INVALID_POSITION
220
+ }
221
+
222
+ private fun resolveItemPosition(trackIndex: Int, trackId: String): Int {
223
+ var resolvedPosition = -1
224
+ if (trackIndex >= 0 && trackIndex < audioTracks.size) {
225
+ resolvedPosition = trackIndex
226
+ } else if ("" != trackId) {
227
+ val itemPos = getPositionForItem(trackId.hashCode().toLong())
228
+ if (itemPos != INVALID_POSITION) {
229
+ resolvedPosition = itemPos
230
+ }
231
+ }
232
+ return resolvedPosition
233
+ }
234
+
235
+ fun getVolumeLeft(): Float {
236
+ return volumeLeft
237
+ }
238
+
239
+ fun getVolumeRight(): Float {
240
+ return volumeRight
241
+ }
242
+
243
+ fun setVolume(
244
+ @FloatRange(from = 0.0, to = 1.0) left: Float,
245
+ @FloatRange(from = 0.0, to = 1.0) right: Float
246
+ ) {
247
+ volumeLeft = left
248
+ volumeRight = right
249
+ if (currentMediaPlayer != null && currentMediaPlayer!!.get() != null) {
250
+ Log.i("PlaylistManager", "setVolume completing with volume = $left")
251
+ currentMediaPlayer!!.get()!!.setVolume(volumeLeft, volumeRight)
252
+ }
253
+ }
254
+
255
+ fun getPlaybackSpeed(): Float {
256
+ return playbackSpeed
257
+ }
258
+
259
+ fun setPlaybackSpeed(@FloatRange(from = 0.0, to = 1.0) speed: Float) {
260
+ playbackSpeed = speed
261
+ if (playlistHandler!!.currentMediaPlayer != null && playlistHandler!!.currentMediaPlayer!! is AudioApi) {
262
+ Log.i(TAG, "setPlaybackSpeed completing with speed = $speed")
263
+ (playlistHandler!!.currentMediaPlayer as AudioApi?)!!.setPlaybackSpeed(playbackSpeed)
264
+ }
265
+ }
266
+
267
+ fun beginPlayback(@IntRange(from = 0) seekPosition: Long, startPaused: Boolean) {
268
+ currentItem ?: return
269
+ super.play(seekPosition, startPaused)
270
+ try {
271
+ setVolume(volumeLeft, volumeRight)
272
+ setPlaybackSpeed(playbackSpeed)
273
+ } catch (e: Exception) {
274
+ Log.w(TAG, "beginPlayback: Error setting volume or playback speed: " + e.message)
275
+ }
276
+ }
277
+
278
+ companion object {
279
+ private const val TAG = "PlaylistManager"
280
+ }
281
+
282
+ init {
283
+ setParameters(audioTracks, 0)
284
+ options = Options(application.baseContext)
285
+ }
286
+ }
@@ -0,0 +1,26 @@
1
+ package org.dwbn.plugins.playlist.notification
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.app.PendingIntent
5
+ import android.app.PendingIntent.FLAG_UPDATE_CURRENT
6
+ import android.app.PendingIntent.FLAG_IMMUTABLE
7
+ import android.content.Context
8
+ import android.content.Intent
9
+ import com.devbrackets.android.playlistcore.components.notification.DefaultPlaylistNotificationProvider
10
+
11
+ class PlaylistNotificationProvider(context: Context?) : DefaultPlaylistNotificationProvider(context!!) {
12
+ override val clickPendingIntent: PendingIntent?
13
+ @SuppressLint("UnspecifiedImmutableFlag")
14
+ get() {
15
+ val context = context
16
+ val pkgName = context.packageName
17
+ val intent = context
18
+ .packageManager
19
+ .getLaunchIntentForPackage(pkgName)
20
+ intent!!.addFlags(
21
+ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP)
22
+ return PendingIntent.getActivity(this.context,
23
+ 0, intent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
24
+ )
25
+ }
26
+ }
@@ -0,0 +1,101 @@
1
+ package org.dwbn.plugins.playlist.playlist
2
+
3
+ import android.content.Context
4
+ import android.media.AudioManager
5
+ import android.net.Uri
6
+ import android.os.PowerManager
7
+ import androidx.annotation.FloatRange
8
+ import androidx.annotation.IntRange
9
+ import com.devbrackets.android.exomedia.AudioPlayer
10
+ import com.devbrackets.android.exomedia.listener.OnErrorListener
11
+ import com.devbrackets.android.playlistcore.manager.BasePlaylistManager
12
+ import com.google.android.exoplayer2.util.EventLogger
13
+ import org.dwbn.plugins.playlist.data.AudioTrack
14
+ import java.lang.ref.WeakReference
15
+ import java.util.concurrent.locks.ReentrantLock
16
+
17
+ class AudioApi(context: Context) : BaseMediaApi() {
18
+ private val audioPlayer: AudioPlayer = AudioPlayer(context.applicationContext)
19
+
20
+ private val errorListenersLock = ReentrantLock(true)
21
+ private val errorListeners = ArrayList<WeakReference<OnErrorListener>>()
22
+
23
+ override val isPlaying: Boolean
24
+ get() = audioPlayer.isPlaying
25
+
26
+ override val handlesOwnAudioFocus: Boolean
27
+ get() = false
28
+
29
+ override val currentPosition: Long
30
+ get() = if (prepared) audioPlayer.currentPosition else 0
31
+
32
+ override val duration: Long
33
+ get() = if (prepared) audioPlayer.duration else 0
34
+
35
+ override val bufferedPercent: Int
36
+ get() = bufferPercent
37
+
38
+ init {
39
+ audioPlayer.setOnErrorListener(this)
40
+ audioPlayer.setOnPreparedListener(this)
41
+ audioPlayer.setOnCompletionListener(this)
42
+ audioPlayer.setOnSeekCompletionListener(this)
43
+ audioPlayer.setOnBufferUpdateListener(this)
44
+
45
+ audioPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
46
+ audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
47
+ audioPlayer.setAnalyticsListener(EventLogger(null))
48
+ }
49
+
50
+ override fun play() {
51
+ audioPlayer.start()
52
+ }
53
+
54
+ override fun pause() {
55
+ audioPlayer.pause()
56
+ }
57
+
58
+ override fun stop() {
59
+ audioPlayer.stopPlayback()
60
+ }
61
+
62
+ override fun reset() {
63
+ audioPlayer.reset()
64
+ }
65
+
66
+ override fun release() {
67
+ audioPlayer.release()
68
+ }
69
+
70
+ override fun setVolume(@FloatRange(from = 0.0, to = 1.0) left: Float, @FloatRange(from = 0.0, to = 1.0) right: Float) {
71
+ audioPlayer.setVolume(left, right)
72
+ }
73
+
74
+ override fun seekTo(@IntRange(from = 0L) milliseconds: Long) {
75
+ audioPlayer.seekTo(milliseconds.toInt().toLong())
76
+ }
77
+
78
+ override fun handlesItem(item: AudioTrack): Boolean {
79
+ return item.mediaType == BasePlaylistManager.AUDIO
80
+ }
81
+
82
+ fun setPlaybackSpeed(@FloatRange(from = 0.0, to = 1.0) speed: Float) {
83
+ audioPlayer.playbackSpeed = speed
84
+ }
85
+ override fun playItem(item: AudioTrack) {
86
+ try {
87
+ prepared = false
88
+ bufferPercent = 0
89
+ audioPlayer.setDataSource(Uri.parse(if (item.downloaded) item.downloadedMediaUri else item.mediaUrl))
90
+ audioPlayer.prepareAsync()
91
+ } catch (e: Exception) {
92
+ //Purposefully left blank
93
+ }
94
+ }
95
+
96
+ fun addErrorListener(listener: OnErrorListener) {
97
+ errorListenersLock.lock()
98
+ errorListeners.add(WeakReference<OnErrorListener>(listener))
99
+ errorListenersLock.unlock()
100
+ }
101
+ }
@@ -0,0 +1,40 @@
1
+ package org.dwbn.plugins.playlist.playlist
2
+
3
+ import com.devbrackets.android.exomedia.listener.*
4
+ import com.devbrackets.android.playlistcore.api.MediaPlayerApi
5
+ import com.devbrackets.android.playlistcore.listener.MediaStatusListener
6
+ import org.dwbn.plugins.playlist.data.AudioTrack
7
+
8
+ abstract class BaseMediaApi : MediaPlayerApi<AudioTrack>, OnPreparedListener, OnCompletionListener,
9
+ OnErrorListener, OnSeekCompletionListener, OnBufferUpdateListener {
10
+ protected var prepared: Boolean = false
11
+ protected var bufferPercent: Int = 0
12
+
13
+ protected var statusListener: MediaStatusListener<AudioTrack>? = null
14
+
15
+ override fun setMediaStatusListener(listener: MediaStatusListener<AudioTrack>) {
16
+ statusListener = listener
17
+ }
18
+
19
+ override fun onCompletion() {
20
+ statusListener?.onCompletion(this)
21
+ }
22
+
23
+ override fun onError(e: Exception): Boolean {
24
+ return statusListener?.onError(this) == true
25
+ }
26
+
27
+ override fun onPrepared() {
28
+ prepared = true
29
+ statusListener?.onPrepared(this)
30
+ }
31
+
32
+ override fun onSeekComplete() {
33
+ statusListener?.onSeekComplete(this)
34
+ }
35
+
36
+ override fun onBufferingUpdate(percent: Int) {
37
+ bufferPercent = percent
38
+ statusListener?.onBufferingUpdate(this, percent)
39
+ }
40
+ }