react-native-nitro-player 1.2.2 → 1.4.0
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
CHANGED
|
@@ -140,11 +140,14 @@ dependencies {
|
|
|
140
140
|
implementation project(":react-native-nitro-modules")
|
|
141
141
|
|
|
142
142
|
implementation "androidx.media3:media3-exoplayer:$media3_version"
|
|
143
|
+
implementation "androidx.media3:media3-exoplayer-hls:$media3_version" //for .m3u8
|
|
144
|
+
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
|
|
145
|
+
implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version"
|
|
143
146
|
implementation "androidx.media3:media3-session:$media3_version"
|
|
144
147
|
implementation "androidx.media3:media3-common:$media3_version"
|
|
145
148
|
implementation "androidx.media:media:1.7.0"
|
|
146
|
-
|
|
147
|
-
// WorkManager for background downloads
|
|
148
|
-
implementation "androidx.work:work-runtime-ktx:2.
|
|
149
|
+
|
|
150
|
+
// WorkManager for background downloads.
|
|
151
|
+
implementation "androidx.work:work-runtime-ktx:2.10.5" // Latest version of 2.10
|
|
149
152
|
}
|
|
150
153
|
|
|
@@ -125,6 +125,7 @@ class TrackPlayerCore private constructor(
|
|
|
125
125
|
|
|
126
126
|
// ── Service binding ────────────────────────────────────────────────────
|
|
127
127
|
private var serviceBound = false
|
|
128
|
+
private var rebindAttempts = 0
|
|
128
129
|
|
|
129
130
|
private val serviceConnection =
|
|
130
131
|
object : ServiceConnection {
|
|
@@ -132,7 +133,35 @@ class TrackPlayerCore private constructor(
|
|
|
132
133
|
name: ComponentName?,
|
|
133
134
|
service: IBinder?,
|
|
134
135
|
) {
|
|
135
|
-
|
|
136
|
+
// Android can redeliver the MediaSessionService binder instead of
|
|
137
|
+
// our LocalBinder (e.g. after the service is restarted). Guard the
|
|
138
|
+
// cast and rebind explicitly with ACTION_LOCAL_BIND instead of crashing.
|
|
139
|
+
val binder = service as? NitroPlayerPlaybackService.LocalBinder
|
|
140
|
+
if (binder == null) {
|
|
141
|
+
NitroPlayerLogger.log("TrackPlayerCore") {
|
|
142
|
+
"onServiceConnected received unexpected binder: $service"
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
context.unbindService(this)
|
|
146
|
+
} catch (_: Exception) {}
|
|
147
|
+
serviceBound = false
|
|
148
|
+
if (rebindAttempts < 3) {
|
|
149
|
+
rebindAttempts++
|
|
150
|
+
handler.post {
|
|
151
|
+
val bindIntent =
|
|
152
|
+
Intent(context, NitroPlayerPlaybackService::class.java).apply {
|
|
153
|
+
action = NitroPlayerPlaybackService.ACTION_LOCAL_BIND
|
|
154
|
+
}
|
|
155
|
+
context.bindService(
|
|
156
|
+
bindIntent,
|
|
157
|
+
this,
|
|
158
|
+
Context.BIND_AUTO_CREATE,
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
rebindAttempts = 0
|
|
136
165
|
playerHandler = binder.handler
|
|
137
166
|
binder.service.trackPlayerCore = this@TrackPlayerCore
|
|
138
167
|
serviceBound = true
|
|
@@ -11,7 +11,9 @@ import androidx.work.ForegroundInfo
|
|
|
11
11
|
import androidx.work.WorkerParameters
|
|
12
12
|
import com.margelo.nitro.nitroplayer.*
|
|
13
13
|
import kotlinx.coroutines.Dispatchers
|
|
14
|
+
import kotlinx.coroutines.TimeoutCancellationException
|
|
14
15
|
import kotlinx.coroutines.withContext
|
|
16
|
+
import kotlinx.coroutines.withTimeout
|
|
15
17
|
import java.io.BufferedInputStream
|
|
16
18
|
import java.io.FileOutputStream
|
|
17
19
|
import java.net.HttpURLConnection
|
|
@@ -35,6 +37,14 @@ class DownloadWorker(
|
|
|
35
37
|
private const val NOTIFICATION_CHANNEL_ID = "nitro_player_downloads"
|
|
36
38
|
private const val BASE_NOTIFICATION_ID = 2001
|
|
37
39
|
private const val BUFFER_SIZE = 8192
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Hard upper bound on a single download. Bounds runaway/trickling
|
|
43
|
+
* downloads so the dataSync foreground service is always released
|
|
44
|
+
* well within the Android 14+ FGS timeout window — otherwise the
|
|
45
|
+
* system kills the app with ForegroundServiceDidNotStopInTimeException.
|
|
46
|
+
*/
|
|
47
|
+
private const val MAX_DOWNLOAD_DURATION_MS = 30L * 60L * 1000L
|
|
38
48
|
private val CONTENT_DISPOSITION_REGEX = Regex("filename=\"?([^\";]+)\"?")
|
|
39
49
|
}
|
|
40
50
|
|
|
@@ -72,8 +82,12 @@ class DownloadWorker(
|
|
|
72
82
|
// Download continues in background.
|
|
73
83
|
}
|
|
74
84
|
|
|
75
|
-
// Perform download
|
|
76
|
-
|
|
85
|
+
// Perform download, bounded so the foreground service is
|
|
86
|
+
// always released within the Android 14+ FGS timeout window.
|
|
87
|
+
val localPath =
|
|
88
|
+
withTimeout(MAX_DOWNLOAD_DURATION_MS) {
|
|
89
|
+
downloadFile(downloadId, trackId, trackTitle, urlString, storageLocation)
|
|
90
|
+
}
|
|
77
91
|
|
|
78
92
|
if (localPath != null) {
|
|
79
93
|
downloadManager.onComplete(downloadId, trackId, localPath)
|
|
@@ -91,6 +105,17 @@ class DownloadWorker(
|
|
|
91
105
|
showErrorNotification(trackTitle)
|
|
92
106
|
Result.retry()
|
|
93
107
|
}
|
|
108
|
+
} catch (e: TimeoutCancellationException) {
|
|
109
|
+
val error =
|
|
110
|
+
DownloadError(
|
|
111
|
+
code = "DOWNLOAD_TIMEOUT",
|
|
112
|
+
message = "Download exceeded maximum allowed duration",
|
|
113
|
+
reason = DownloadErrorReason.TIMEOUT,
|
|
114
|
+
isRetryable = true,
|
|
115
|
+
)
|
|
116
|
+
downloadManager.onError(downloadId, trackId, error)
|
|
117
|
+
showErrorNotification(trackTitle)
|
|
118
|
+
Result.retry()
|
|
94
119
|
} catch (e: Exception) {
|
|
95
120
|
val errorReason =
|
|
96
121
|
when {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-player",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A powerful audio player library for React Native with playlist management, playback controls, and support for Android Auto and CarPlay",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"module": "lib/index",
|
|
@@ -114,7 +114,8 @@
|
|
|
114
114
|
},
|
|
115
115
|
"release-it": {
|
|
116
116
|
"npm": {
|
|
117
|
-
"publish": true
|
|
117
|
+
"publish": true,
|
|
118
|
+
"skipChecks": true
|
|
118
119
|
},
|
|
119
120
|
"git": {
|
|
120
121
|
"commitMessage": "chore: release ${version}",
|