@javascriptcommon/react-native-track-player 1.2.9 → 1.2.24
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.
- package/android/build.gradle +61 -4
- package/android/src/main/AndroidManifest.xml +2 -4
- package/android/src/main/ic_home-playstore.png +0 -0
- package/android/src/main/ic_repeat-playstore.png +0 -0
- package/android/src/main/ic_repeat_50-playstore.png +0 -0
- package/android/src/main/ic_shuffle-playstore.png +0 -0
- package/android/src/main/ic_shuffle_50-playstore.png +0 -0
- package/android/src/main/ic_shuffle_sm-playstore.png +0 -0
- package/android/src/main/ic_stop-playstore.png +0 -0
- package/android/src/main/ic_test-playstore.png +0 -0
- package/android/src/main/java/com/guichaguri/trackplayer/{service/HeadlessJsMediaService.java → HeadlessJsMediaService.java} +83 -32
- package/android/src/main/java/com/guichaguri/trackplayer/TrackPlayer.kt +25 -0
- package/android/src/main/java/com/guichaguri/trackplayer/extensions/AudioPlayerStateExt.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/EventHolder.kt +30 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/NotificationEventHolder.kt +20 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/event/PlayerEventHolder.kt +111 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AAMediaSessionCallback.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioContentType.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioItem.kt +66 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioItemTransitionReason.kt +33 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/AudioPlayerState.kt +30 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/BufferConfig.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/CacheConfig.kt +17 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/Capability.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/FocusChangeData.kt +3 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/MediaSessionCallback.kt +17 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationConfig.kt +43 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationMetadata.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/NotificationState.kt +8 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayWhenReadyChangeData.kt +5 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackEndedReason.kt +5 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackError.kt +6 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlaybackMetadata.kt +200 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayerConfig.kt +33 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PlayerOptions.kt +9 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/PositionChangedReason.kt +39 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/models/QueuedPlayerOptions.kt +49 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/notification/NotificationManager.kt +678 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/AudioPlayer.kt +10 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/BaseAudioPlayer.kt +864 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/QueuedAudioPlayer.kt +269 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/components/MediaSourceExt.kt +35 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/components/PlayerCache.kt +26 -0
- package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/utils/Utils.kt +12 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/MetadataAdapter.kt +224 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/State.kt +13 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/Track.kt +120 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/TrackAudioItem.kt +19 -0
- package/android/src/main/java/com/guichaguri/trackplayer/model/TrackType.kt +11 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/AutoConnectionDetector.kt +151 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicEvents.kt +66 -0
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicModule.kt +1192 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/BundleUtils.kt +117 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicBinder.kt +31 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicManager.kt +347 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicService.kt +1268 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/Utils.kt +228 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/ButtonEvents.kt +141 -0
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/MetadataManager.kt +396 -0
- package/android/src/main/res/drawable-hdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-mdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xhdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/ic_home.png +0 -0
- package/android/src/main/res/drawable-xxxhdpi/ic_home.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_arrow_down_circle_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_clock_now_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_close_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_heart_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_heart_outlined_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_repeat_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_repeat_on_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_shuffle_off_foreground.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_shuffle_on_foreground.png +0 -0
- package/android/src/main/res/raw/silent_5_seconds.mp3 +0 -0
- package/android/src/main/res/strings.xml +6 -0
- package/android/src/main/res/values/strings.xml +6 -0
- package/index.d.ts +62 -1
- package/lib/index.js +10 -9
- package/package.json +1 -1
- package/android/src/main/java/com/guichaguri/trackplayer/TrackPlayer.java +0 -28
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicEvents.java +0 -55
- package/android/src/main/java/com/guichaguri/trackplayer/module/MusicModule.java +0 -298
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicBinder.java +0 -47
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicManager.java +0 -383
- package/android/src/main/java/com/guichaguri/trackplayer/service/MusicService.java +0 -271
- package/android/src/main/java/com/guichaguri/trackplayer/service/Utils.java +0 -243
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/ButtonEvents.java +0 -148
- package/android/src/main/java/com/guichaguri/trackplayer/service/metadata/MetadataManager.java +0 -379
- package/android/src/main/java/com/guichaguri/trackplayer/service/models/Track.java +0 -141
- package/android/src/main/java/com/guichaguri/trackplayer/service/models/TrackType.java +0 -35
- package/android/src/main/res/drawable-hdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-mdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xhdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/ic_logo.png +0 -0
- package/android/src/main/res/drawable-xxxhdpi/ic_logo.png +0 -0
package/android/src/main/java/com/guichaguri/trackplayer/kotlinaudio/players/QueuedAudioPlayer.kt
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.players
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.doublesymmetry.kotlinaudio.players.BaseAudioPlayer
|
|
6
|
+
import com.google.android.exoplayer2.C
|
|
7
|
+
import com.google.android.exoplayer2.IllegalSeekPositionException
|
|
8
|
+
import com.google.android.exoplayer2.source.MediaSource
|
|
9
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.*
|
|
10
|
+
import java.util.*
|
|
11
|
+
import kotlin.math.max
|
|
12
|
+
import kotlin.math.min
|
|
13
|
+
|
|
14
|
+
class QueuedAudioPlayer(
|
|
15
|
+
context: Context,
|
|
16
|
+
playerConfig: PlayerConfig = PlayerConfig(),
|
|
17
|
+
bufferConfig: BufferConfig? = null,
|
|
18
|
+
cacheConfig: CacheConfig? = null,
|
|
19
|
+
mediaSessionCallback: AAMediaSessionCallBack
|
|
20
|
+
) : BaseAudioPlayer(context, playerConfig, bufferConfig, cacheConfig, mediaSessionCallback) {
|
|
21
|
+
private val queue = LinkedList<MediaSource>()
|
|
22
|
+
override val playerOptions = DefaultQueuedPlayerOptions(exoPlayer)
|
|
23
|
+
|
|
24
|
+
// val currentIndex
|
|
25
|
+
// get() = exoPlayer.currentMediaItemIndex
|
|
26
|
+
|
|
27
|
+
val currentIndex = 0
|
|
28
|
+
|
|
29
|
+
override val currentItem: AudioItem?
|
|
30
|
+
get() = (queue.getOrNull(currentIndex)?.mediaItem?.localConfiguration?.tag as AudioItemHolder?)?.audioItem
|
|
31
|
+
|
|
32
|
+
val nextIndex: Int?
|
|
33
|
+
get() {
|
|
34
|
+
return if (exoPlayer.nextMediaItemIndex == C.INDEX_UNSET) null
|
|
35
|
+
else exoPlayer.nextMediaItemIndex
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
val previousIndex: Int?
|
|
39
|
+
get() {
|
|
40
|
+
return if (exoPlayer.previousMediaItemIndex == C.INDEX_UNSET) null
|
|
41
|
+
else exoPlayer.previousMediaItemIndex
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
val items: List<AudioItem>
|
|
45
|
+
get() = queue.map { (it.mediaItem.localConfiguration?.tag as AudioItemHolder).audioItem }
|
|
46
|
+
|
|
47
|
+
fun getQueueHead(): MediaSource? {
|
|
48
|
+
return if (queue.isNotEmpty()) {
|
|
49
|
+
queue.peek()
|
|
50
|
+
} else {
|
|
51
|
+
null
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fun getQueueSize(): Int {
|
|
56
|
+
return queue.size
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
val previousItems: List<AudioItem>
|
|
60
|
+
get() {
|
|
61
|
+
return if (queue.isEmpty()) emptyList()
|
|
62
|
+
else queue
|
|
63
|
+
.subList(0, exoPlayer.currentMediaItemIndex)
|
|
64
|
+
.map { (it.mediaItem.localConfiguration?.tag as AudioItemHolder).audioItem }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
val nextItems: List<AudioItem>
|
|
68
|
+
get() {
|
|
69
|
+
return if (queue.isEmpty()) emptyList()
|
|
70
|
+
else queue
|
|
71
|
+
.subList(exoPlayer.currentMediaItemIndex, queue.lastIndex)
|
|
72
|
+
.map { (it.mediaItem.localConfiguration?.tag as AudioItemHolder).audioItem }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
val nextItem: AudioItem?
|
|
76
|
+
get() = items.getOrNull(currentIndex + 1)
|
|
77
|
+
|
|
78
|
+
val previousItem: AudioItem?
|
|
79
|
+
get() = items.getOrNull(currentIndex - 1)
|
|
80
|
+
|
|
81
|
+
override fun load(item: AudioItem, playWhenReady: Boolean) {
|
|
82
|
+
exoPlayer.playWhenReady = playWhenReady
|
|
83
|
+
load(item)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override fun load(item: AudioItem) {
|
|
87
|
+
if (queue.isEmpty()) {
|
|
88
|
+
add(item)
|
|
89
|
+
} else {
|
|
90
|
+
val mediaSource = getMediaSourceFromAudioItem(item)
|
|
91
|
+
queue[currentIndex] = mediaSource
|
|
92
|
+
exoPlayer.addMediaSource(currentIndex + 1, mediaSource)
|
|
93
|
+
exoPlayer.removeMediaItem(currentIndex)
|
|
94
|
+
exoPlayer.prepare()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Add a single item to the queue. If the AudioPlayer has no item loaded, it will load the `item`.
|
|
100
|
+
* @param item The [AudioItem] to add.
|
|
101
|
+
*/
|
|
102
|
+
fun add(item: AudioItem, playWhenReady: Boolean) {
|
|
103
|
+
exoPlayer.playWhenReady = playWhenReady
|
|
104
|
+
add(item)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Add a single item to the queue. If the AudioPlayer has no item loaded, it will load the `item`.
|
|
109
|
+
* @param item The [AudioItem] to add.
|
|
110
|
+
* @param playWhenReady Whether playback starts automatically.
|
|
111
|
+
*/
|
|
112
|
+
fun add(item: AudioItem) {
|
|
113
|
+
val mediaSource = getMediaSourceFromAudioItem(item)
|
|
114
|
+
queue.add(mediaSource)
|
|
115
|
+
exoPlayer.addMediaSource(mediaSource)
|
|
116
|
+
exoPlayer.prepare()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Add multiple items to the queue. If the AudioPlayer has no item loaded, it will load the first item in the list.
|
|
121
|
+
* @param items The [AudioItem]s to add.
|
|
122
|
+
* @param playWhenReady Whether playback starts automatically.
|
|
123
|
+
*/
|
|
124
|
+
fun add(items: List<AudioItem>, playWhenReady: Boolean) {
|
|
125
|
+
exoPlayer.playWhenReady = playWhenReady
|
|
126
|
+
add(items)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Add multiple items to the queue. If the AudioPlayer has no item loaded, it will load the first item in the list.
|
|
131
|
+
* @param items The [AudioItem]s to add.
|
|
132
|
+
*/
|
|
133
|
+
fun add(items: List<AudioItem>) {
|
|
134
|
+
val mediaSources = items.map { getMediaSourceFromAudioItem(it) }
|
|
135
|
+
queue.addAll(mediaSources)
|
|
136
|
+
exoPlayer.addMediaSources(mediaSources)
|
|
137
|
+
exoPlayer.prepare()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Add multiple items to the queue.
|
|
142
|
+
* @param items The [AudioItem]s to add.
|
|
143
|
+
* @param atIndex Index to insert items at, if no items loaded this will not automatically start playback.
|
|
144
|
+
*/
|
|
145
|
+
fun add(items: List<AudioItem>, atIndex: Int) {
|
|
146
|
+
val mediaSources = items.map { getMediaSourceFromAudioItem(it) }
|
|
147
|
+
queue.addAll(atIndex, mediaSources)
|
|
148
|
+
exoPlayer.addMediaSources(atIndex, mediaSources)
|
|
149
|
+
exoPlayer.prepare()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Remove an item from the queue.
|
|
154
|
+
* @param index The index of the item to remove.
|
|
155
|
+
*/
|
|
156
|
+
fun remove(index: Int) {
|
|
157
|
+
queue.removeAt(index)
|
|
158
|
+
exoPlayer.removeMediaItem(index)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Remove items from the queue.
|
|
163
|
+
* @param indexes The indexes of the items to remove.
|
|
164
|
+
*/
|
|
165
|
+
fun remove(indexes: List<Int>) {
|
|
166
|
+
var sorted = indexes.toList()
|
|
167
|
+
// Sort the indexes in descending order so we can safely remove them one by one
|
|
168
|
+
// without having the next index possibly newly pointing to another item than intended:
|
|
169
|
+
Collections.sort(sorted, Collections.reverseOrder());
|
|
170
|
+
sorted.forEach {
|
|
171
|
+
remove(it)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Skip to the next item in the queue, which may depend on the current repeat mode.
|
|
177
|
+
* Does nothing if there is no next item to skip to.
|
|
178
|
+
*/
|
|
179
|
+
fun next() {
|
|
180
|
+
exoPlayer.seekToNextMediaItem()
|
|
181
|
+
exoPlayer.prepare()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Skip to the previous item in the queue, which may depend on the current repeat mode.
|
|
186
|
+
* Does nothing if there is no previous item to skip to.
|
|
187
|
+
*/
|
|
188
|
+
fun previous() {
|
|
189
|
+
exoPlayer.seekToPreviousMediaItem()
|
|
190
|
+
exoPlayer.prepare()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Move an item in the queue from one position to another.
|
|
195
|
+
* @param fromIndex The index of the item ot move.
|
|
196
|
+
* @param toIndex The index to move the item to. If the index is larger than the size of the queue, the item is moved to the end of the queue instead.
|
|
197
|
+
*/
|
|
198
|
+
fun move(fromIndex: Int, toIndex: Int) {
|
|
199
|
+
exoPlayer.moveMediaItem(fromIndex, toIndex)
|
|
200
|
+
var item = queue[fromIndex]
|
|
201
|
+
queue.removeAt(fromIndex)
|
|
202
|
+
queue.add(max(0, min(items.size, if (toIndex > fromIndex) toIndex else toIndex - 1)), item)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Jump to an item in the queue.
|
|
207
|
+
* @param index the index to jump to
|
|
208
|
+
* @param playWhenReady Whether playback starts automatically.
|
|
209
|
+
*/
|
|
210
|
+
fun jumpToItem(index: Int, playWhenReady: Boolean) {
|
|
211
|
+
exoPlayer.playWhenReady = playWhenReady
|
|
212
|
+
jumpToItem(index)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Jump to an item in the queue.
|
|
217
|
+
* @param index the index to jump to
|
|
218
|
+
*/
|
|
219
|
+
fun jumpToItem(index: Int) {
|
|
220
|
+
try {
|
|
221
|
+
exoPlayer.seekTo(index, C.TIME_UNSET)
|
|
222
|
+
exoPlayer.prepare()
|
|
223
|
+
} catch (e: IllegalSeekPositionException) {
|
|
224
|
+
throw Error("This item index $index does not exist. The size of the queue is ${queue.size} items.")
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Replaces item at index in queue.
|
|
230
|
+
* If updating current index, we update the notification metadata if [automaticallyUpdateNotificationMetadata] is true.
|
|
231
|
+
*/
|
|
232
|
+
fun replaceItem(index: Int, item: AudioItem) {
|
|
233
|
+
val mediaSource = getMediaSourceFromAudioItem(item)
|
|
234
|
+
queue[index] = mediaSource
|
|
235
|
+
if (index == currentIndex) {
|
|
236
|
+
updateNotificationMetadataIfAutomatic(item)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Removes all the upcoming items, if any (the ones returned by [next]).
|
|
242
|
+
*/
|
|
243
|
+
fun removeUpcomingItems() {
|
|
244
|
+
if (queue.lastIndex == -1 || currentIndex == -1) return
|
|
245
|
+
val lastIndex = queue.lastIndex + 1
|
|
246
|
+
val fromIndex = currentIndex + 1
|
|
247
|
+
|
|
248
|
+
exoPlayer.removeMediaItems(fromIndex, lastIndex)
|
|
249
|
+
queue.subList(fromIndex, lastIndex).clear()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Removes all the previous items, if any (the ones returned by [previous]).
|
|
254
|
+
*/
|
|
255
|
+
fun removePreviousItems() {
|
|
256
|
+
exoPlayer.removeMediaItems(0, currentIndex)
|
|
257
|
+
queue.subList(0, currentIndex).clear()
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
override fun destroy() {
|
|
261
|
+
queue.clear()
|
|
262
|
+
super.destroy()
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
override fun clear() {
|
|
266
|
+
queue.clear()
|
|
267
|
+
super.clear()
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.players.components
|
|
2
|
+
|
|
3
|
+
import android.support.v4.media.MediaMetadataCompat
|
|
4
|
+
import android.support.v4.media.RatingCompat
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.AudioItemHolder
|
|
7
|
+
import com.google.android.exoplayer2.source.MediaSource
|
|
8
|
+
|
|
9
|
+
fun MediaSource.getMediaMetadataCompat(): MediaMetadataCompat {
|
|
10
|
+
val audioItem = (mediaItem.localConfiguration?.tag as AudioItemHolder?)?.audioItem
|
|
11
|
+
val metadata = mediaItem.mediaMetadata
|
|
12
|
+
val title = metadata.title ?: audioItem?.title
|
|
13
|
+
val artist = metadata.artist ?: audioItem?.artist
|
|
14
|
+
val albumTitle = metadata.albumTitle ?: audioItem?.albumTitle
|
|
15
|
+
val genre = metadata.genre
|
|
16
|
+
val duration = audioItem?.duration ?: -1
|
|
17
|
+
val artwork = metadata.artworkUri ?: audioItem?.artwork
|
|
18
|
+
val rating = RatingCompat.fromRating(metadata.userRating)
|
|
19
|
+
|
|
20
|
+
return MediaMetadataCompat.Builder().apply {
|
|
21
|
+
putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist.toString())
|
|
22
|
+
putString(MediaMetadataCompat.METADATA_KEY_TITLE, title.toString())
|
|
23
|
+
putString(MediaMetadataCompat.METADATA_KEY_ALBUM, albumTitle.toString())
|
|
24
|
+
putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre.toString())
|
|
25
|
+
putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration)
|
|
26
|
+
|
|
27
|
+
if (artwork != null) {
|
|
28
|
+
putString(MediaMetadataCompat.METADATA_KEY_ART_URI, artwork.toString())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (rating != null) {
|
|
32
|
+
putRating(MediaMetadataCompat.METADATA_KEY_RATING, rating)
|
|
33
|
+
}
|
|
34
|
+
}.build()
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.players.components
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.guichaguri.trackplayer.kotlinaudio.models.CacheConfig
|
|
5
|
+
import com.google.android.exoplayer2.database.DatabaseProvider
|
|
6
|
+
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
|
|
7
|
+
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
|
|
8
|
+
import com.google.android.exoplayer2.upstream.cache.SimpleCache
|
|
9
|
+
import java.io.File
|
|
10
|
+
|
|
11
|
+
object PlayerCache {
|
|
12
|
+
@Volatile
|
|
13
|
+
private var instance: SimpleCache? = null
|
|
14
|
+
|
|
15
|
+
fun getInstance(context: Context, cacheConfig: CacheConfig): SimpleCache? {
|
|
16
|
+
val cacheDir = File(context.cacheDir, cacheConfig.identifier)
|
|
17
|
+
val db: DatabaseProvider = StandaloneDatabaseProvider(context)
|
|
18
|
+
|
|
19
|
+
instance ?: synchronized(this) {
|
|
20
|
+
instance ?: SimpleCache(cacheDir, LeastRecentlyUsedCacheEvictor(cacheConfig.maxCacheSize ?: 0), db)
|
|
21
|
+
.also { instance = it }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return instance
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.kotlinaudio.utils
|
|
2
|
+
|
|
3
|
+
import android.content.ContentResolver
|
|
4
|
+
import android.net.Uri
|
|
5
|
+
import com.google.android.exoplayer2.upstream.RawResourceDataSource
|
|
6
|
+
|
|
7
|
+
fun isUriLocal(uri: Uri?): Boolean {
|
|
8
|
+
if (uri == null) return false
|
|
9
|
+
val scheme = uri.scheme
|
|
10
|
+
val host = uri.host
|
|
11
|
+
return scheme == null || scheme == ContentResolver.SCHEME_FILE || scheme == ContentResolver.SCHEME_ANDROID_RESOURCE || scheme == ContentResolver.SCHEME_CONTENT || scheme == RawResourceDataSource.RAW_RESOURCE_SCHEME || scheme == "res" || host == null || host == "localhost" || host == "127.0.0.1" || host == "[::1]"
|
|
12
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.model
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import com.google.android.exoplayer2.MediaMetadata
|
|
5
|
+
import com.google.android.exoplayer2.metadata.Metadata
|
|
6
|
+
import com.google.android.exoplayer2.metadata.flac.VorbisComment
|
|
7
|
+
import com.google.android.exoplayer2.metadata.icy.IcyHeaders
|
|
8
|
+
import com.google.android.exoplayer2.metadata.icy.IcyInfo
|
|
9
|
+
import com.google.android.exoplayer2.metadata.id3.ChapterFrame
|
|
10
|
+
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame
|
|
11
|
+
import com.google.android.exoplayer2.metadata.id3.UrlLinkFrame
|
|
12
|
+
import com.google.android.exoplayer2.metadata.mp4.MdtaMetadataEntry
|
|
13
|
+
import timber.log.Timber
|
|
14
|
+
|
|
15
|
+
sealed class MetadataAdapter {
|
|
16
|
+
companion object {
|
|
17
|
+
fun fromMetadata(metadata: Metadata): List<Bundle> {
|
|
18
|
+
val group = mutableListOf<Bundle>()
|
|
19
|
+
|
|
20
|
+
(0 until metadata.length()).forEach { i ->
|
|
21
|
+
group.add(Bundle().apply {
|
|
22
|
+
val rawEntries = mutableListOf<Bundle>()
|
|
23
|
+
|
|
24
|
+
when (val entry = metadata[i]) {
|
|
25
|
+
is ChapterFrame -> {
|
|
26
|
+
Timber.d("ChapterFrame: ${entry.id}")
|
|
27
|
+
}
|
|
28
|
+
is TextInformationFrame -> {
|
|
29
|
+
val rawEntry = Bundle()
|
|
30
|
+
|
|
31
|
+
when (entry.id.uppercase()) {
|
|
32
|
+
"TIT2", "TT2" -> {
|
|
33
|
+
putString("title", entry.value)
|
|
34
|
+
rawEntry.putString("commonKey", "title")
|
|
35
|
+
}
|
|
36
|
+
"TALB", "TOAL", "TAL" -> {
|
|
37
|
+
putString("albumName", entry.value)
|
|
38
|
+
rawEntry.putString("commonKey", "albumName")
|
|
39
|
+
}
|
|
40
|
+
"TOPE", "TPE1", "TP1" -> {
|
|
41
|
+
putString("artist", entry.value)
|
|
42
|
+
rawEntry.putString("commonKey", "artist")
|
|
43
|
+
}
|
|
44
|
+
"TDRC", "TOR" -> {
|
|
45
|
+
putString("creationDate", entry.value)
|
|
46
|
+
rawEntry.putString("commonKey", "creationDate")
|
|
47
|
+
}
|
|
48
|
+
"TCON", "TCO" -> {
|
|
49
|
+
putString("genre", entry.value)
|
|
50
|
+
rawEntry.putString("commonKey", "genre")
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
rawEntry.putString("key", entry.id.uppercase())
|
|
55
|
+
rawEntry.putString("keySpace", "org.id3")
|
|
56
|
+
rawEntry.putString("value", entry.value)
|
|
57
|
+
rawEntry.putString("time", "-1")
|
|
58
|
+
rawEntries.add(rawEntry)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
is UrlLinkFrame -> {
|
|
62
|
+
rawEntries.add(Bundle().apply {
|
|
63
|
+
putString("value", entry.url)
|
|
64
|
+
putString("key", entry.id.uppercase())
|
|
65
|
+
putString("keySpace", "org.id3")
|
|
66
|
+
putString("time", "-1")
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
is IcyHeaders -> {
|
|
71
|
+
putString("title", entry.name)
|
|
72
|
+
putString("genre", entry.genre)
|
|
73
|
+
|
|
74
|
+
rawEntries.add(Bundle().apply {
|
|
75
|
+
putString("value", entry.name)
|
|
76
|
+
putString("commonKey", "title")
|
|
77
|
+
putString("key", "StreamTitle")
|
|
78
|
+
putString("keySpace", "icy")
|
|
79
|
+
putString("time", "-1")
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
rawEntries.add(Bundle().apply {
|
|
83
|
+
putString("value", entry.url)
|
|
84
|
+
putString("key", "StreamURL")
|
|
85
|
+
putString("keySpace", "icy")
|
|
86
|
+
putString("time", "-1")
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
rawEntries.add(Bundle().apply {
|
|
90
|
+
putString("value", entry.genre)
|
|
91
|
+
putString("commonKey", "genre")
|
|
92
|
+
putString("key", "StreamGenre")
|
|
93
|
+
putString("keySpace", "icy")
|
|
94
|
+
putString("time", "-1")
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
is IcyInfo -> {
|
|
99
|
+
putString("title", entry.title)
|
|
100
|
+
|
|
101
|
+
rawEntries.add(Bundle().apply {
|
|
102
|
+
putString("value", entry.url)
|
|
103
|
+
putString("key", "StreamURL")
|
|
104
|
+
putString("keySpace", "icy")
|
|
105
|
+
putString("time", "-1")
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
rawEntries.add(Bundle().apply {
|
|
109
|
+
putString("value", entry.title)
|
|
110
|
+
putString("commonKey", "title")
|
|
111
|
+
putString("key", "StreamTitle")
|
|
112
|
+
putString("keySpace", "icy")
|
|
113
|
+
putString("time", "-1")
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
is VorbisComment -> {
|
|
118
|
+
val rawEntry = Bundle()
|
|
119
|
+
|
|
120
|
+
when (entry.key) {
|
|
121
|
+
"TITLE" -> {
|
|
122
|
+
putString("title", entry.value)
|
|
123
|
+
rawEntry.putString("commonKey", "title")
|
|
124
|
+
}
|
|
125
|
+
"ARTIST" -> {
|
|
126
|
+
putString("artist", entry.value)
|
|
127
|
+
rawEntry.putString("commonKey", "artist")
|
|
128
|
+
}
|
|
129
|
+
"ALBUM" -> {
|
|
130
|
+
putString("albumName", entry.value)
|
|
131
|
+
rawEntry.putString("commonKey", "albumName")
|
|
132
|
+
}
|
|
133
|
+
"DATE" -> {
|
|
134
|
+
putString("creationDate", entry.value)
|
|
135
|
+
rawEntry.putString("commonKey", "creationDate")
|
|
136
|
+
}
|
|
137
|
+
"GENRE" -> {
|
|
138
|
+
putString("genre", entry.value)
|
|
139
|
+
rawEntry.putString("commonKey", "genre")
|
|
140
|
+
}
|
|
141
|
+
"URL" -> {
|
|
142
|
+
putString("url", entry.value)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
rawEntry.putString("key", entry.key)
|
|
147
|
+
rawEntry.putString("keySpace", "org.vorbis")
|
|
148
|
+
rawEntry.putString("value", entry.value)
|
|
149
|
+
rawEntry.putString("time", "-1")
|
|
150
|
+
rawEntries.add(rawEntry)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
is MdtaMetadataEntry -> {
|
|
154
|
+
val rawEntry = Bundle()
|
|
155
|
+
when (entry.key) {
|
|
156
|
+
"com.apple.quicktime.title" -> {
|
|
157
|
+
putString("title", entry.value.toString())
|
|
158
|
+
rawEntry.putString("commonKey", "title")
|
|
159
|
+
}
|
|
160
|
+
"com.apple.quicktime.artist" -> {
|
|
161
|
+
putString("artist", entry.value.toString())
|
|
162
|
+
rawEntry.putString("commonKey", "artist")
|
|
163
|
+
}
|
|
164
|
+
"com.apple.quicktime.album" -> {
|
|
165
|
+
putString("albumName", entry.value.toString())
|
|
166
|
+
rawEntry.putString("commonKey", "albumName")
|
|
167
|
+
}
|
|
168
|
+
"com.apple.quicktime.creationdate" -> {
|
|
169
|
+
putString("creationDate", entry.value.toString())
|
|
170
|
+
rawEntry.putString("commonKey", "creationDate")
|
|
171
|
+
}
|
|
172
|
+
"com.apple.quicktime.genre" -> {
|
|
173
|
+
putString("genre", entry.value.toString())
|
|
174
|
+
rawEntry.putString("commonKey", "genre")
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
rawEntry.putString("key", entry.key.substringAfterLast("."))
|
|
179
|
+
rawEntry.putString("keySpace", "com.apple.quicktime")
|
|
180
|
+
rawEntry.putString("value", entry.value.toString())
|
|
181
|
+
rawEntry.putString("time", "-1")
|
|
182
|
+
rawEntries.add(rawEntry)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
putParcelableArray("raw", rawEntries.toTypedArray())
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return group
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
fun fromMediaMetadata(metadata: MediaMetadata): Bundle {
|
|
194
|
+
return Bundle().apply {
|
|
195
|
+
metadata.title?.let { putString("title", it.toString()) }
|
|
196
|
+
metadata.artist?.let { putString("artist", it.toString()) }
|
|
197
|
+
metadata.albumTitle?.let { putString("albumName", it.toString()) }
|
|
198
|
+
metadata.subtitle?.let { putString("subtitle", it.toString()) }
|
|
199
|
+
metadata.description?.let { putString("description", it.toString()) }
|
|
200
|
+
metadata.artworkUri?.let { putString("artworkUri", it.toString()) }
|
|
201
|
+
metadata.trackNumber?.let { putInt("trackNumber", it) }
|
|
202
|
+
metadata.composer?.let { putString("composer", it.toString()) }
|
|
203
|
+
metadata.conductor?.let { putString("conductor", it.toString()) }
|
|
204
|
+
metadata.genre?.let { putString("genre", it.toString()) }
|
|
205
|
+
metadata.compilation?.let { putString("compilation", it.toString()) }
|
|
206
|
+
metadata.station?.let { putString("station", it.toString()) }
|
|
207
|
+
// metadata.mediaType?.let { putInt("mediaType", it) }
|
|
208
|
+
|
|
209
|
+
// This is how SwiftAudioEx outputs it in the metadata dictionary
|
|
210
|
+
(metadata.recordingDay to metadata.recordingMonth).let { (day, month) ->
|
|
211
|
+
// if both are not null, combine them into a single string
|
|
212
|
+
if (day != null && month != null) {
|
|
213
|
+
putString("creationDate", "${String.format("%02d", day)}${String.format("%02d", month)}")
|
|
214
|
+
} else if (day != null) {
|
|
215
|
+
putString("creationDate", String.format("%02d", day))
|
|
216
|
+
} else if (month != null) {
|
|
217
|
+
putString("creationDate", String.format("%02d", month))
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
metadata.recordingYear?.let { putString("creationYear", it.toString()) }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package com.guichaguri.trackplayer.model
|
|
2
|
+
|
|
3
|
+
enum class State(val state: String) {
|
|
4
|
+
Buffering("buffering"),
|
|
5
|
+
None("none"),
|
|
6
|
+
Ready("ready"),
|
|
7
|
+
Paused("paused"),
|
|
8
|
+
Stopped("stopped"),
|
|
9
|
+
Playing("playing"),
|
|
10
|
+
Loading("loading"),
|
|
11
|
+
Error("error"),
|
|
12
|
+
Ended("ended"),
|
|
13
|
+
}
|