ChromecastListener has always implemented CastStateListener, but nothing
ever registered it. Whether a receiver was reported as available hung
entirely on the media router callback, which does not always fire - and
then the cast button never appears even though devices are there.
The framework's own signal is registered now and the current state is
reported straight away. It is not taken at face value in one direction:
the framework drops back to NO_DEVICES_AVAILABLE when a session ends,
because it stops discovering at that point, which would hide the button
right after someone stops casting. The devices the media router still
knows decide that case.
The listener is dropped again when the activity goes.
The sleep timer fades playback down to 10% over its last minute by setting the
player's volume. CastPlayer.setVolume was an empty stub and getVolume returned
zero, so while casting the fade did nothing at all.
Both now go through the media stream volume the Cast SDK offers. That is the
receiver's volume for this stream only: the device volume stays where the user
put it, and on a cast group the balance between its members is untouched,
because the receiver applies the stream volume to the group's output.
* Render a higher resolution bitmap in the notification background art
Previously only METADATA_KEY_ALBUM_ART_URI/ART_URI were set, leaving notification/lock-screen/Android Auto consumers to resolve the cover art themselves. Likely due to internal scaling, a lower quality bitmap was loaded.
This commit adds a shared resolveUriAsBitmap() helper (extracted from AbMediaDescriptionAdapter.kt) and uses it to:
- Resolve and cache a bitmap on PlaybackSession once per
session (synchronously for local covers, asynchronously for server covers), then set it on METADATA_KEY_ALBUM_ART/ART once available, falling back to the URI keys until it resolves.
- Reuse the same helper in AbMediaDescriptionAdapter so the notification icon is resolved consistently.
PlayerNotificationService tracks the resolution Job and cancels/replaces it on each new playback session, invalidating the media session metadata once the bitmap is ready.
* Remove the size override in Glide
The override was not needed. It wasn't in the original code, so I'll remove it for consistency.
* Update notification icon to reuse cover bitmap if already loaded on session
---------
Co-authored-by: advplyr <advplyr@protonmail.com>
Android Auto browsing could freeze and crash the app (phone app "closes",
Android Auto shows a generic connection error) whenever the Capacitor
webview had not yet established the server connection.
Root cause: onLoadChildren runs on the media browser service main thread.
It calls loadAndroidAutoItems -> checkSetValidServerConnectionConfig, which
used runBlocking to ping every saved server config and authorize the user.
That blocked the main thread on network I/O. Android Auto (plus Assistant)
re-request the browse root every ~2s, and every onGetRoot flags a reload
while disconnected, so the blocking work was triggered repeatedly and
re-entrantly, producing an ANR.
Changes:
- checkSetValidServerConnectionConfig now runs on a dedicated
Dispatchers.IO scope instead of runBlocking, so pings/authorize never
block the caller. The callback contract is unchanged; downstream Android
Auto callbacks already ran off the main thread.
- loadAndroidAutoItems coalesces overlapping calls into a single in-flight
load and fires all queued callbacks on completion, so the browse-root
polling storm can no longer spawn concurrent loads racing shared state.
- Fix latent bug in checkResetServerItems: server config id was compared
with !== (reference identity) instead of != (value), causing spurious
cache resets that fed the reload storm.
Co-authored-by: databoy2k <18686442+databoy2k@users.noreply.github.com>
Previously only METADATA_KEY_ALBUM_ART_URI/ART_URI were set, leaving notification/lock-screen/Android Auto consumers to resolve the cover art themselves. Likely due to internal scaling, a lower quality bitmap was loaded.
This commit adds a shared resolveUriAsBitmap() helper (extracted from AbMediaDescriptionAdapter.kt) and uses it to:
- Resolve and cache a bitmap on PlaybackSession once per
session (synchronously for local covers, asynchronously for server covers), then set it on METADATA_KEY_ALBUM_ART/ART once available, falling back to the URI keys until it resolves.
- Reuse the same helper in AbMediaDescriptionAdapter so the notification icon is resolved consistently.
PlayerNotificationService tracks the resolution Job and cancels/replaces it on each new playback session, invalidating the media session metadata once the bitmap is ready.
The POST /api/items/<id>/play/<episodeId> response inlines every episode
of a podcast with an audioTrack per episode. Server-side, audioTrack.mimeType
is derived from audioFile.mimeType, which is null when the row was created
without a successful audio probe (direct DB inserts, import scripts,
partial probe failures).
The Jackson deserializer hits one null mimeType among the inlined
episodes, throws MissingKotlinParameterException, and the entire
play-session response fails to deserialize. ExoPlayer is never called,
the UI silently stalls.
Make mimeType nullable on the data class to tolerate this. ExoPlayer's
MediaItem.Builder.setMimeType already accepts nullable. Defensively
coerce null to empty string for Cast's MediaInfo.Builder.setContentType,
whose Java signature is non-null.
Fixes#1905