mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-01-27 07:46:09 +01:00
Fix a bunch of problems with the DataSources
This commit is contained in:
parent
7d33770fd6
commit
1564379bd1
@ -1079,8 +1079,7 @@ class PlayerFragment :
|
||||
Player.STATE_BUFFERING -> {
|
||||
|
||||
val downloadStatus = resources.getString(
|
||||
R.string.download_playerstate_downloading,
|
||||
Util.formatPercentage(progress)
|
||||
R.string.download_playerstate_loading
|
||||
)
|
||||
progressBar.secondaryProgress = progress
|
||||
setTitle(this@PlayerFragment, downloadStatus)
|
||||
|
@ -147,7 +147,7 @@ open class APIDataSource private constructor(
|
||||
val components = dataSpec.uri.toString().split('|')
|
||||
val id = components[0]
|
||||
val bitrate = components[1].toInt()
|
||||
val request = subsonicAPIClient.api.stream(id, bitrate, offset = 0)
|
||||
val request = subsonicAPIClient.api.stream(id, bitrate, offset = dataSpec.position)
|
||||
val response: retrofit2.Response<ResponseBody>?
|
||||
val streamResponse: StreamResponse
|
||||
|
||||
@ -220,7 +220,7 @@ open class APIDataSource private constructor(
|
||||
|
||||
@Throws(HttpDataSourceException::class)
|
||||
override fun read(buffer: ByteArray, offset: Int, length: Int): Int {
|
||||
Timber.i("APIDatasource: Read: %s %s %s", buffer, offset, length)
|
||||
Timber.d("APIDatasource: Read: %s %s", offset, length)
|
||||
return try {
|
||||
readInternal(buffer, offset, length)
|
||||
} catch (e: IOException) {
|
||||
|
@ -10,15 +10,15 @@ package org.moire.ultrasonic.playback
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.util.Util
|
||||
import androidx.media3.datasource.BaseDataSource
|
||||
import androidx.media3.datasource.DataSource
|
||||
import androidx.media3.datasource.DataSpec
|
||||
import androidx.media3.datasource.HttpDataSource
|
||||
import androidx.media3.datasource.cache.CacheDataSource
|
||||
import androidx.media3.datasource.cache.CacheDataSource.CacheIgnoredReason
|
||||
import androidx.media3.datasource.HttpDataSource.HttpDataSourceException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.InterruptedIOException
|
||||
import org.moire.ultrasonic.util.AbstractFile
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Storage
|
||||
@ -26,30 +26,13 @@ import timber.log.Timber
|
||||
|
||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||
class CachedDataSource(
|
||||
private var upstreamDataSource: DataSource,
|
||||
private var eventListener: EventListener?
|
||||
private var upstreamDataSource: DataSource
|
||||
) : BaseDataSource(false) {
|
||||
|
||||
class Factory(
|
||||
private var upstreamDataSourceFactory: DataSource.Factory
|
||||
) : DataSource.Factory {
|
||||
|
||||
private var eventListener: EventListener? = null
|
||||
|
||||
/**
|
||||
* Sets the {link EventListener} to which events are delivered.
|
||||
*
|
||||
*
|
||||
* The default is `null`.
|
||||
*
|
||||
* @param eventListener The [EventListener].
|
||||
* @return This factory.
|
||||
*/
|
||||
fun setEventListener(eventListener: EventListener?): Factory {
|
||||
this.eventListener = eventListener
|
||||
return this
|
||||
}
|
||||
|
||||
override fun createDataSource(): CachedDataSource {
|
||||
return createDataSourceInternal(
|
||||
upstreamDataSourceFactory.createDataSource()
|
||||
@ -60,30 +43,11 @@ class CachedDataSource(
|
||||
upstreamDataSource: DataSource
|
||||
): CachedDataSource {
|
||||
return CachedDataSource(
|
||||
upstreamDataSource,
|
||||
eventListener
|
||||
upstreamDataSource
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Listener of [CacheDataSource] events. */
|
||||
interface EventListener {
|
||||
/**
|
||||
* Called when bytes have been read from the cache.
|
||||
*
|
||||
* @param cacheSizeBytes Current cache size in bytes.
|
||||
* @param cachedBytesRead Total bytes read from the cache since this method was last called.
|
||||
*/
|
||||
fun onCachedBytesRead(cacheSizeBytes: Long, cachedBytesRead: Long)
|
||||
|
||||
/**
|
||||
* Called when the current request ignores cache.
|
||||
*
|
||||
* @param reason Reason cache is bypassed.
|
||||
*/
|
||||
fun onCacheIgnored(reason: @CacheIgnoredReason Int)
|
||||
}
|
||||
|
||||
private var bytesToRead: Long = 0
|
||||
private var bytesRead: Long = 0
|
||||
private var dataSpec: DataSpec? = null
|
||||
@ -94,9 +58,7 @@ class CachedDataSource(
|
||||
|
||||
override fun open(dataSpec: DataSpec): Long {
|
||||
Timber.i(
|
||||
"CachedDatasource: Open: %s %s %s",
|
||||
dataSpec.uri,
|
||||
dataSpec.position,
|
||||
"CachedDatasource: Open: %s",
|
||||
dataSpec.toString()
|
||||
)
|
||||
|
||||
@ -112,6 +74,8 @@ class CachedDataSource(
|
||||
if (cacheLength > 0) {
|
||||
transferInitializing(dataSpec)
|
||||
bytesToRead = cacheLength
|
||||
transferStarted(dataSpec)
|
||||
skipFully(dataSpec.position, dataSpec)
|
||||
return bytesToRead
|
||||
}
|
||||
|
||||
@ -120,13 +84,14 @@ class CachedDataSource(
|
||||
}
|
||||
|
||||
override fun read(buffer: ByteArray, offset: Int, length: Int): Int {
|
||||
Timber.i("CachedDatasource: Read: %s %s %s", buffer, offset, length)
|
||||
if (offset > 0 || length > 4)
|
||||
Timber.d("CachedDatasource: Read: %s %s", offset, length)
|
||||
return if (cachePath != null) {
|
||||
try {
|
||||
readInternal(buffer, offset, length)
|
||||
} catch (e: IOException) {
|
||||
throw HttpDataSource.HttpDataSourceException.createForIOException(
|
||||
e, Util.castNonNull(dataSpec), HttpDataSource.HttpDataSourceException.TYPE_READ
|
||||
throw HttpDataSourceException.createForIOException(
|
||||
e, Util.castNonNull(dataSpec), HttpDataSourceException.TYPE_READ
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -148,14 +113,63 @@ class CachedDataSource(
|
||||
}
|
||||
val read = Util.castNonNull(responseByteStream).read(buffer, offset, readLength)
|
||||
if (read == -1) {
|
||||
Timber.i("CachedDatasource: EndOfInput")
|
||||
return C.RESULT_END_OF_INPUT
|
||||
}
|
||||
bytesRead += read.toLong()
|
||||
// TODO
|
||||
// bytesTransferred(read)
|
||||
bytesTransferred(read)
|
||||
return read
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to skip the specified number of bytes in full.
|
||||
*
|
||||
* @param bytesToSkip The number of bytes to skip.
|
||||
* @param dataSpec The [DataSpec].
|
||||
* @throws HttpDataSourceException If the thread is interrupted during the operation, or an error
|
||||
* occurs while reading from the source, or if the data ended before skipping the specified
|
||||
* number of bytes.
|
||||
*/
|
||||
@Suppress("ThrowsCount")
|
||||
@Throws(HttpDataSourceException::class)
|
||||
private fun skipFully(bytesToSkip: Long, dataSpec: DataSpec) {
|
||||
var bytesToSkip = bytesToSkip
|
||||
if (bytesToSkip == 0L) {
|
||||
return
|
||||
}
|
||||
val skipBuffer = ByteArray(4096)
|
||||
try {
|
||||
while (bytesToSkip > 0) {
|
||||
val readLength =
|
||||
bytesToSkip.coerceAtMost(skipBuffer.size.toLong()).toInt()
|
||||
val read = Util.castNonNull(responseByteStream).read(skipBuffer, 0, readLength)
|
||||
if (Thread.currentThread().isInterrupted) {
|
||||
throw InterruptedIOException()
|
||||
}
|
||||
if (read == -1) {
|
||||
throw HttpDataSourceException(
|
||||
dataSpec,
|
||||
PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE,
|
||||
HttpDataSourceException.TYPE_OPEN
|
||||
)
|
||||
}
|
||||
bytesToSkip -= read.toLong()
|
||||
bytesTransferred(read)
|
||||
}
|
||||
return
|
||||
} catch (e: IOException) {
|
||||
if (e is HttpDataSourceException) {
|
||||
throw e
|
||||
} else {
|
||||
throw HttpDataSourceException(
|
||||
dataSpec,
|
||||
PlaybackException.ERROR_CODE_IO_UNSPECIFIED,
|
||||
HttpDataSourceException.TYPE_OPEN
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is called by StatsDataSource to verify that the loading succeeded,
|
||||
* so its important that we return the correct value here..
|
||||
@ -165,9 +179,10 @@ class CachedDataSource(
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
Timber.i("CachedDatasource: close")
|
||||
Timber.i("CachedDatasource: close %s", openedFile)
|
||||
if (openedFile) {
|
||||
openedFile = false
|
||||
transferEnded()
|
||||
responseByteStream?.close()
|
||||
responseByteStream = null
|
||||
}
|
||||
@ -193,6 +208,10 @@ class CachedDataSource(
|
||||
cacheFile = Storage.getFromPath(filePath)!!
|
||||
responseByteStream = cacheFile!!.getFileInputStream()
|
||||
|
||||
return cacheFile!!.getDocumentFileDescriptor("r")!!.length
|
||||
val descriptor = cacheFile!!.getDocumentFileDescriptor("r")
|
||||
val length = descriptor!!.length
|
||||
descriptor.close()
|
||||
|
||||
return length
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ class Downloader(
|
||||
override fun run() {
|
||||
try {
|
||||
Timber.w("Checking Downloads")
|
||||
checkDownloadsInternal()
|
||||
// FIXME
|
||||
// checkDownloadsInternal()
|
||||
} catch (all: Exception) {
|
||||
Timber.e(all, "checkDownloads() failed.")
|
||||
} finally {
|
||||
|
@ -298,11 +298,13 @@ class MediaPlayerController(
|
||||
|
||||
@Synchronized
|
||||
fun seekTo(position: Int) {
|
||||
Timber.i("SeekTo: %s", position)
|
||||
controller?.seekTo(position.toLong())
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun seekTo(index: Int, position: Int) {
|
||||
Timber.i("SeekTo: %s %s", index, position)
|
||||
controller?.seekTo(index, position.toLong())
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,6 @@
|
||||
<string name="download.menu_show_album">Zobrazit album</string>
|
||||
<string name="download.menu_shuffle">Náhodně</string>
|
||||
<string name="download.menu_visualizer">Vizualizér</string>
|
||||
<string name="download.playerstate_downloading">Stahuji - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Přehrávám mix</string>
|
||||
<string name="download.playlist_done">Playlist úspěšně uložen.</string>
|
||||
<string name="download.playlist_error">Chyba ukládání playlistu, zkuste později.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">Album anzeigen</string>
|
||||
<string name="download.menu_shuffle">Mischen</string>
|
||||
<string name="download.menu_visualizer">Grafik</string>
|
||||
<string name="download.playerstate_downloading">Herunterladen - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Wiedergabeliste mischen</string>
|
||||
<string name="download.playlist_done">Die Wiedergabeliste wurde gespeichert</string>
|
||||
<string name="download.playlist_error">Konnte die Wiedergabeliste nicht speichern, bitte später erneut versuchen.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">Mostrar Álbum</string>
|
||||
<string name="download.menu_shuffle">Aleatorio</string>
|
||||
<string name="download.menu_visualizer">Visualizador</string>
|
||||
<string name="download.playerstate_downloading">Descargando - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Reproduciendo en modo aleatorio</string>
|
||||
<string name="download.playlist_done">Lista de reproducción guardada con éxito.</string>
|
||||
<string name="download.playlist_error">Fallo al guardar la lista de reproducción, por favor reinténtalo mas tarde.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">Afficher l\'album</string>
|
||||
<string name="download.menu_shuffle">Aléatoire</string>
|
||||
<string name="download.menu_visualizer">Visualiseur</string>
|
||||
<string name="download.playerstate_downloading">Téléchargement - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">En lecture aléatoire</string>
|
||||
<string name="download.playlist_done">Playlist enregistrée avec succès !</string>
|
||||
<string name="download.playlist_error">Échec de l\'enregistrement de la playlist, veuillez réessayer plus tard.</string>
|
||||
|
@ -71,7 +71,6 @@
|
||||
<string name="download.menu_show_album">Ugrás az albumhoz</string>
|
||||
<string name="download.menu_shuffle">Véletlen sorrendű</string>
|
||||
<string name="download.menu_visualizer">Visualizer</string>
|
||||
<string name="download.playerstate_downloading">Letöltés - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Véletlen sorrendű</string>
|
||||
<string name="download.playlist_done">Lejátszási lista mentése sikeres.</string>
|
||||
<string name="download.playlist_error">Lejátszási lista mentése sikertelen, próbálja később!</string>
|
||||
|
@ -59,7 +59,6 @@
|
||||
<string name="download.menu_show_album">Visualizza Album</string>
|
||||
<string name="download.menu_shuffle">Casuale</string>
|
||||
<string name="download.menu_visualizer">Visualizzatore</string>
|
||||
<string name="download.playerstate_downloading">In scaricamento - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Riproduzione casuale</string>
|
||||
<string name="download.playlist_done">Playlist salvata con successo </string>
|
||||
<string name="download.playlist_error">Impossibile salvare la playlist, riprovare più tardi.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">Album tonen</string>
|
||||
<string name="download.menu_shuffle">Willekeurig</string>
|
||||
<string name="download.menu_visualizer">Visualisatie</string>
|
||||
<string name="download.playerstate_downloading">Bezig met downloaden - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Bezig met willekeurig afspelen</string>
|
||||
<string name="download.playlist_done">Afspeellijst is opgeslagen.</string>
|
||||
<string name="download.playlist_error">Afspeellijst kan niet worden opgeslagen. Probeer het later opnieuw.</string>
|
||||
|
@ -62,7 +62,6 @@
|
||||
<string name="download.menu_show_album">Wyświetl album</string>
|
||||
<string name="download.menu_shuffle">Wymieszaj</string>
|
||||
<string name="download.menu_visualizer">Efekt wizualny</string>
|
||||
<string name="download.playerstate_downloading">Pobieranie - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Odtwarzanie losowe</string>
|
||||
<string name="download.playlist_done">Playlista została zapisana.</string>
|
||||
<string name="download.playlist_error">Błąd zapisu playlisty. Proszę spróbować później.</string>
|
||||
|
@ -74,7 +74,6 @@
|
||||
<string name="download.menu_show_album">Mostrar Álbum</string>
|
||||
<string name="download.menu_shuffle">Misturar</string>
|
||||
<string name="download.menu_visualizer">Visualizador</string>
|
||||
<string name="download.playerstate_downloading">Baixando - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Tocando misturado</string>
|
||||
<string name="download.playlist_done">Playlist salva com sucesso.</string>
|
||||
<string name="download.playlist_error">Falha ao salvar a playlist, Tente mais tarde.</string>
|
||||
|
@ -62,7 +62,6 @@
|
||||
<string name="download.menu_show_album">Mostrar Álbum</string>
|
||||
<string name="download.menu_shuffle">Misturar</string>
|
||||
<string name="download.menu_visualizer">Visualizador</string>
|
||||
<string name="download.playerstate_downloading">Descarregando - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Tocando misturado</string>
|
||||
<string name="download.playlist_done">Playlist salva com sucesso.</string>
|
||||
<string name="download.playlist_error">Falha ao salvar a playlist, Tente mais tarde.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">Показать альбом</string>
|
||||
<string name="download.menu_shuffle">Случайное воспроизведение</string>
|
||||
<string name="download.menu_visualizer">Визуализатор</string>
|
||||
<string name="download.playerstate_downloading">Загрузка - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">Игра в случайном порядке</string>
|
||||
<string name="download.playlist_done">Плейлист был успешно сохранен.</string>
|
||||
<string name="download.playlist_error">Не удалось сохранить плейлист, попробуйте позже.</string>
|
||||
|
@ -76,7 +76,6 @@
|
||||
<string name="download.menu_show_album">显示专辑</string>
|
||||
<string name="download.menu_shuffle">随机</string>
|
||||
<string name="download.menu_visualizer">可视化</string>
|
||||
<string name="download.playerstate_downloading">下载中 - %s</string>
|
||||
<string name="download.playerstate_playing_shuffle">随机播放</string>
|
||||
<string name="download.playlist_done">已成功保存播放列表。</string>
|
||||
<string name="download.playlist_error">保存播放列表失败,请重试。</string>
|
||||
|
@ -78,7 +78,7 @@
|
||||
<string name="download.menu_shuffle_on">Shuffle mode enabled</string>
|
||||
<string name="download.menu_shuffle_off">Shuffle mode disabled</string>
|
||||
<string name="download.menu_visualizer">Visualizer</string>
|
||||
<string name="download.playerstate_downloading">Downloading - %s</string>
|
||||
<string name="download.playerstate_loading">Buffering …</string>
|
||||
<string name="download.playerstate_playing_shuffle">Playing shuffle</string>
|
||||
<string name="download.playlist_done">Playlist was successfully saved.</string>
|
||||
<string name="download.playlist_error">Failed to save playlist, please try later.</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user