Open ohuc opened 2 months ago
What version of the app - built from git or F-Droid? Did you try restarting the server? What server version?
And most importantly: can you provide output of adb logcat
?
Running the F-Droid Build Not sure about the server version this is how it's running https://music-assistant.io/player-support/slimproto/ Also, I'm trying to connect to a music assistant client which connects perfectly when I use the squeezer app.
Here are the logs
2024-08-24 11:09:39.133 27815 27815 de.maniac103.squeezeclient E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient, PID: 27815 T3.b: Field 'mediadirs' is required for type with serial name 'de.maniac103.squeezeclient.cometd.response.ServerStatusResponse', but it was missing at X3.P.f(Unknown Source:114) at O2.V.<init>(Unknown Source:26) at O2.T.a(Unknown Source:78) at Z3.n.i(Unknown Source:10) at Y3.c.a(Unknown Source:56) at M2.a0.b(Unknown Source:104) at M2.C.p(Unknown Source:32) at M2.C.k(Unknown Source:12) at I3.I.a(Unknown Source:76) at I3.x0.a(Unknown Source:799) at J3.G.j(Unknown Source:4) at J3.F.t(Unknown Source:138) at J3.F.a(Unknown Source:0) at Q2.c.p(Unknown Source:107) at Q2.c.j(Unknown Source:48) at I3.K.a(Unknown Source:60) at I3.o0.n(Unknown Source:201) at I3.n0.p(Unknown Source:12) at m3.a.n(Unknown Source:8) at F3.L.run(Unknown Source:114) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8700) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886) Suppressed: L3.g: [y0{Cancelling}@d35c1d2, Dispatchers.Main]
Also I'm trying to just get the controls of the Music assistant server in my mobile phone which the squeezer app could do but it has a lot of delay issues
I've been looking for an android client for Music Assistant also. I don't have a LMS up currently, does this act as a client/endpoint for any slim protocol/squeezelite server, or is it perhaps a wrapper around a LMS server's web interface? I'm currently sharing files to MA from a NAS.
I've been looking for an android client for Music Assistant also. I don't have a LMS up currently, does this act as a client/endpoint for any slim protocol/squeezelite server, or is it perhaps a wrapper around a LMS server's web interface? I'm currently sharing files to MA from a NAS.
Well i just enabled the "Slimproto (Squeezebox players)" as one of the player providers and used the music assistant companion app for windows to emulate it as a speaker, however now while trying to connect to the server with squeeze client it crashes
So I think the music assistant server acts as a LMS server itself
This app interacts as client to LMS' cometd server interface. From the log it looks like MA's implementation just doesn't provide media directories, which are used only for reconstructing the folder structure during music download, so I guess I can make those optional. I want to make one thing clear though: if MA differs more significantly from LMS than in such minor details, I don't have any intentions to support it, for two reasons:
I hope for your understanding there ;-)
I'll provide a test APK for making mediadirs optional, we'll see where this goes.
I don't think it differs too much because it seems to be running all good in the squeezer app except for the fact that there is a bit of a delay
Alright waiting for the APK
I appreciate you taking the time to even make a test APK. I totally understand the complications as well as your limited time. Good luck on this project either way!
(File is just named .zip due to Github's file name restrictions)
This makes mediadirs optional, which in turn renders the download folder structure option 'match server' useless. If all goes well, I'll improve things there to make that option become unavailable in that case.
Please let me know if this works for you, or - in case it doesn't - provide a new log.
Still crashing
Here's the logs:
2024-08-25 17:29:12.563 11297 11297 de.maniac103.squeezeclient E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient, PID: 11297 x3.b: Field 'mediadirs' is required for type with serial name 'de.maniac103.squeezeclient.cometd.response.ServerStatusResponse', but it was missing at B3.Q.f(Unknown Source:114) at u2.V.<init>(Unknown Source:26) at u2.T.a(Unknown Source:78) at D3.o.i(Unknown Source:10) at C3.c.a(Unknown Source:56) at s2.Z.b(Unknown Source:104) at s2.B.s(Unknown Source:32) at s2.B.n(Unknown Source:12) at n3.I.a(Unknown Source:76) at F2.u.a(Unknown Source:489) at o3.G.l(Unknown Source:4) at o3.F.u(Unknown Source:138) at o3.F.a(Unknown Source:0) at w2.c.s(Unknown Source:107) at w2.c.l(Unknown Source:48) at n3.K.a(Unknown Source:60) at n3.l0.m(Unknown Source:201) at n3.k0.s(Unknown Source:12) at R2.a.q(Unknown Source:8) at k3.K.run(Unknown Source:114) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8700) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886) Suppressed: q3.g: [x0{Cancelling}@fe36fd8, Dispatchers.Main]
Stupid me ... note to self: don't do stuff in a hurry, it leads to mistakes :-(
Thanks for the test apk :) However it still seems to be crashing
I think it may be a lot different to the way lms works I guess because it seems to be crashing at every little minor detail
2024-08-25 18:13:33.501 30406 30406 de.maniac103.squeezeclient E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient, PID: 30406 D3.j: String literal for key 'offset' should be quoted. Use 'isLenient = true' in 'Json {}' builder to accept non-compliant JSON. JSON input: .....ype":"track","style":"itemplay","nextWindow":"nowPlaying"}]} at D3.o.d(Unknown Source:36) at D3.o.e(Unknown Source:34) at D3.a.M(Unknown Source:52) at D3.a.w(Unknown Source:4) at B3.e0.a(Unknown Source:5) at D3.o.i(Unknown Source:10) at D3.a.f(Unknown Source:38) at u2.M.a(Unknown Source:392) at D3.o.i(Unknown Source:10) at C3.c.a(Unknown Source:56) at s2.Z.i(Unknown Source:91) at s2.L.s(Unknown Source:12) at R2.a.q(Unknown Source:8) at q3.s.A(Unknown Source:6) at k3.a.q(Unknown Source:22) at R2.a.q(Unknown Source:31) at k3.C.B(Unknown Source:50) at k3.h.r(Unknown Source:80) at k3.h.v(Unknown Source:2) at m3.j.a(Unknown Source:6) at m3.h.H(Unknown Source:114) at m3.h.g(Unknown Source:56) at m3.h.r(Unknown Source:89) at s2.Y.s(Unknown Source:93) at R2.a.q(Unknown Source:8) at k3.K.run(Unknown Source:114) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8700) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886) Suppressed: q3.g: [s0{Cancelling}@e8b172e, Dispatchers.Main.immediate]
One notable difference between Squeeze Client and Squeezer that was important to me is that I made the JSON consumer as rigid as possible to get a better understanding of what input data I can rely on and what data is optional. Squeezer is more lenient in that regard, at the expense of much more complicated code (because it needs special case handling for missing values everywhere). However, in this particular case, it looks like the JSON is not actually valid? Here's another APK, this time as debug version, which should dump the received data into logcat. The crash will be the same, but can you provide the data right before the crash from the log, please?
sorry provided the same log earlier Is this what you were looking for?
2024-08-25 19:10:55.936 26472 26503 de.maniac103.squeezeclient.debug D CometdClient : Received event message (2255 bytes): Message(channelId=ChannelId(channel=/a73e39a062e711ef934a181deab7bf10/slim/request/3), clientId=null, id=14, successful=true, data={"player_name":"nk-HP-EliteBook-850-G5","player_connected":1,"player_needs_upgrade":false,"player_is_upgrading":false,"power":1,"signalstrength":0,"waitingToPlay":0,"mode":"stop","remote":1,"current_title":"Music Assistant","time":0,"duration":359,"sync_master":"","sync_slaves":"","mixer volume":4,"player_ip":"192.168.29.201","playlist_cur_index":0,"playlist_tracks":2,"can_seek":0,"digital_volume_control":1,"playlist_timestamp":1724590059,"playlist repeat":1,"playlist shuffle":0,"playlist mode":"off","rate":1,"seq_no":0,"sleep":0,"will_sleep_in":0,"uuid":null,"alarm_state":"none","alarm_snooze_seconds":540,"alarm_timeout_seconds":3600,"count":2,"offset":"-","base":{"actions":{"more":{"itemsParams":"params","window":{"isContextMenu":1},"cmd":["contextmenu"],"player":0,"params":{"context":"playlist","menu":"track"}}}},"preset_loop":[0,0,0,0,0,0,0,0,0,0],"preset_data":[{},{},{},{},{},{},{},{},{},{}],"item_loop":[{"track":"Sunset in Calabasas","album":"","trackType":"radio","icon":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/63/0b/60/630b60e3-6234-9df1-80e2-833eee57be18/859770370543_cover.jpg/1400x1400bb.jpg","artist":"adrian","text":"Sunset in Calabasas","params":{"track_id":"d9860b39bc0147b69d8803a21886239e","item_id":"d9860b39bc0147b69d8803a21886239e","uri":"http://192.168.29.201:8097/single/18:1d:ea:b7:bf:10/d9860b39bc0147b69d8803a21886239e.flac?ts=1724590054"},"type":"track","style":"itemplay","nextWindow":"nowPlaying"},{"track":"Sunset in Calabasas","album":"","trackType":"radio","icon":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/63/0b/60/630b60e3-6234-9df1-80e2-833eee57be18/859770370543_cover.jpg/1400x1400bb.jpg","artist":"adrian","text":"Sunset in Calabasas","params":{"track_id":"d9860b39bc0147b69d8803a21886239e","item_id":"d9860b39bc0147b69d8803a21886239e","uri":"http://192.168.29.201:8097/single/18:1d:ea:b7:bf:10/d9860b39bc0147b69d8803a21886239e.flac?ts=1724590059"},"type":"track","style":"itemplay","nextWindow":"nowPlaying"}]})
These are the logs right before the crash
Hmm, what's strange is that that JSON seems fine. Both the JSON and the stack trace before suggest it's a PlayerStatusResponse
it's choking at, thus to reproduce what you're sseing, I tried this, what should match what the actual event decoding is doing:
val jsonstring = """
{"player_name":"nk-HP-EliteBook-850-G5","player_connected":1,"player_needs_upgrade":false,"player_is_upgrading":false,"power":1,"signalstrength":0,"waitingToPlay":0,"mode":"stop","remote":1,"current_title":"Music Assistant","time":0,"duration":359,"sync_master":"","sync_slaves":"","mixer volume":4,"player_ip":"192.168.29.201","playlist_cur_index":0,"playlist_tracks":2,"can_seek":0,"digital_volume_control":1,"playlist_timestamp":1724590059,"playlist repeat":1,"playlist shuffle":0,"playlist mode":"off","rate":1,"seq_no":0,"sleep":0,"will_sleep_in":0,"uuid":null,"alarm_state":"none","alarm_snooze_seconds":540,"alarm_timeout_seconds":3600,"count":2,"offset":"-","base":{"actions":{"more":{"itemsParams":"params","window":{"isContextMenu":1},"cmd":["contextmenu"],"player":0,"params":{"context":"playlist","menu":"track"}}}},"preset_loop":[0,0,0,0,0,0,0,0,0,0],"preset_data":[{},{},{},{},{},{},{},{},{},{}],"item_loop":[{"track":"Sunset in Calabasas","album":"","trackType":"radio","icon":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/63/0b/60/630b60e3-6234-9df1-80e2-833eee57be18/859770370543_cover.jpg/1400x1400bb.jpg","artist":"adrian","text":"Sunset in Calabasas","params":{"track_id":"d9860b39bc0147b69d8803a21886239e","item_id":"d9860b39bc0147b69d8803a21886239e","uri":"http://192.168.29.201:8097/single/18:1d:ea:b7:bf:10/d9860b39bc0147b69d8803a21886239e.flac?ts=1724590054"},"type":"track","style":"itemplay","nextWindow":"nowPlaying"},{"track":"Sunset in Calabasas","album":"","trackType":"radio","icon":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/63/0b/60/630b60e3-6234-9df1-80e2-833eee57be18/859770370543_cover.jpg/1400x1400bb.jpg","artist":"adrian","text":"Sunset in Calabasas","params":{"track_id":"d9860b39bc0147b69d8803a21886239e","item_id":"d9860b39bc0147b69d8803a21886239e","uri":"http://192.168.29.201:8097/single/18:1d:ea:b7:bf:10/d9860b39bc0147b69d8803a21886239e.flac?ts=1724590059"},"type":"track","style":"itemplay","nextWindow":"nowPlaying"}]}
""".trimIndent()
val jsonelem = json.parseToJsonElement(jsonstring)
val resp = json.decodeFromJsonElement<PlayerStatusResponse>(jsonelem)
Can you please provide a slightly fuller log of the debug app, including the fatal stack trace (basically including a full readable version of the log entries in your screenshot)?
Debug log I got right before it
2024-08-26 16:24:25.081 31402 31443 de.maniac103.squeezeclient.debug D CometdClient : Received event message (1159 bytes): Message(channelId=ChannelId(channel=/8ef9c9ec639911ef96b9181deab7bf10/slim/playerstatus/181deab7bf10), clientId=null, id=9, successful=true, data={"player_name":"nk-HP-EliteBook-850-G5","player_connected":1,"player_needs_upgrade":false,"player_is_upgrading":false,"power":1,"signalstrength":0,"waitingToPlay":0,"mode":"stop","remote":1,"current_title":"Music Assistant","time":0,"duration":0,"sync_master":"","sync_slaves":"","mixer volume":66,"player_ip":"192.168.29.201","playlist_cur_index":0,"playlist_tracks":0,"can_seek":0,"digital_volume_control":1,"playlist_timestamp":1724667732,"playlist repeat":0,"playlist shuffle":0,"playlist mode":"off","rate":1,"seq_no":0,"sleep":0,"will_sleep_in":0,"uuid":null,"alarm_state":"none","alarm_snooze_seconds":540,"alarm_timeout_seconds":3600,"count":0,"offset":"-","base":{"actions":{"more":{"itemsParams":"params","window":{"isContextMenu":1},"cmd":["contextmenu"],"player":0,"params":{"context":"playlist","menu":"track"}}}},"preset_loop":[0,0,0,0,0,0,0,0,0,0],"preset_data":[{},{},{},{},{},{},{},{},{},{}],"item_loop":[]})
And fatal stack trace logs:
2024-08-26 16:23:25.644 31209 31209 de.maniac103.squeezeclient.debug E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient.debug, PID: 31209 kotlinx.serialization.json.internal.JsonDecodingException: String literal for key 'offset' should be quoted. Use 'isLenient = true' in 'Json {}' builder to accept non-compliant JSON. JSON input: .....preset_data":[{},{},{},{},{},{},{},{},{},{}],"item_loop":[]} at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24) at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32) at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeTaggedString(TreeJsonDecoder.kt:144) at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeTaggedString(TreeJsonDecoder.kt:36) at kotlinx.serialization.internal.TaggedDecoder.decodeString(Tagged.kt:231) at kotlinx.serialization.internal.StringSerializer.deserialize(Primitives.kt:160) at kotlinx.serialization.internal.StringSerializer.deserialize(Primitives.kt:156) at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:77) at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:52) at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:207) at kotlinx.serialization.internal.TaggedDecoder$decodeNullableSerializableElement$1.invoke(Tagged.kt:288) at kotlinx.serialization.internal.TaggedDecoder.tagBlock(Tagged.kt:294) at kotlinx.serialization.internal.TaggedDecoder.decodeNullableSerializableElement(Tagged.kt:286) at de.maniac103.squeezeclient.cometd.response.PlayerStatusResponse$$serializer.deserialize(PlayerStatusResponse.kt:40) at de.maniac103.squeezeclient.cometd.response.PlayerStatusResponse$$serializer.deserialize(PlayerStatusResponse.kt:40) at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:77) at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:52) at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readJson(TreeJsonDecoder.kt:25) at kotlinx.serialization.json.Json.decodeFromJsonElement(Json.kt:127) at de.maniac103.squeezeclient.cometd.ConnectionHelper.fetchPlaylist(ConnectionHelper.kt:565) at de.maniac103.squeezeclient.cometd.ConnectionHelper$fetchPlaylist$1.invokeSuspend(Unknown Source:15) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:28) at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:99) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:231) at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:187) at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:159) at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:466) at kotlinx.coroutines.CancellableContinuationImpl.completeResume(CancellableContinuationImpl.kt:582) at kotlinx.coroutines.channels.BufferedChannelKt.tryResume0(BufferedChannel.kt:2927) at kotlinx.coroutines.channels.BufferedChannelKt.access$tryResume0(BufferedChannel.kt:1) at kotlinx.coroutines.channels.BufferedChannel.tryResumeReceiver(BufferedChannel.kt:669) at kotlinx.coroutines.channels.BufferedChannel.updateCellSend(BufferedChannel.kt:481) at kotlinx.coroutines.channels.BufferedChannel.access$updateCellSend(BufferedChannel.kt:36) at kotlinx.coroutines.channels.BufferedChannel.send$suspendImpl(BufferedChannel.kt:3120) at kotlinx.coroutines.channels.BufferedChannel.send(Unknown Source:0) at kotlinx.coroutines.channels.ChannelCoroutine.send(Unknown Source:2) at de.maniac103.squeezeclient.cometd.ConnectionHelper$publishOneShotRequest$subscriptionChannel$1.invokeSuspend(ConnectionHelper.kt:322)
OK, thanks. Strangely enough your new JSON also doesn't reproduce it, but looking at MA sources hopefully got me on the right track.
(Built on another machine, so signing keys might be different ... just uninstall the previous debug APK in that case)
Diff so far:
diff --git a/app/src/main/java/de/maniac103/squeezeclient/cometd/response/PlayerStatusResponse.kt b/app/src/main/java/de/maniac103/squeezeclient/cometd/response/PlayerStatusResponse.kt
index 4a59509..cb84bae 100644
--- a/app/src/main/java/de/maniac103/squeezeclient/cometd/response/PlayerStatusResponse.kt
+++ b/app/src/main/java/de/maniac103/squeezeclient/cometd/response/PlayerStatusResponse.kt
@@ -34,14 +34,17 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.decodeFromJsonElement
+import kotlinx.serialization.json.int
·
// offset and item_loop are not returned when fetching non-existing pages
@Serializable
data class PlayerStatusResponse(
@SerialName("mode")
val state: PlayerStatus.PlayState,
- val offset: String? = null,
+ // might be a string or a number (LMS always sends strings, MA sends "-" or numbers)
+ val offset: JsonPrimitive? = null,
val count: Int,
@SerialName("item_loop")
private val items: List<JsonObject>? = null,
@@ -122,10 +125,10 @@ data class PlayerStatusResponse(
}
·
fun asModelPlaylist(json: Json, fetchOffset: Int): Playlist {
- val actualOffset = when (offset) {
- null -> fetchOffset
- "-" -> playlistCurrentIndex
- else -> offset.toInt()
+ val actualOffset = when {
+ offset == null -> fetchOffset
+ offset.content == "-" -> playlistCurrentIndex
+ else -> offset.int
}
val (playlist, reachableCount) = if (items != null) {
val playlist = items.mapNotNull {it.asModelPlaylistItem(json, base) }
diff --git a/app/src/main/java/de/maniac103/squeezeclient/cometd/response/ServerStatusResponse.kt b/app/src/main/java/de/maniac103/squeezeclient/cometd/response/ServerStatusResponse.kt
index e51c3ca..abc8431 100644
--- a/app/src/main/java/de/maniac103/squeezeclient/cometd/response/ServerStatusResponse.kt
+++ b/app/src/main/java/de/maniac103/squeezeclient/cometd/response/ServerStatusResponse.kt
@@ -25,7 +25,9 @@ import kotlinx.serialization.Serializable
data class ServerStatusResponse(
val version: String,
@SerialName("players_loop")
+ // players_loop is omitted if there are no players
val players: List<Player> = emptyList(),
@SerialName("mediadirs")
- val mediaDirectories: List<String>
+ // LMS sends those (with valid contents), MA doesn't
+ val mediaDirectories: List<String> = emptyList()
)
Finally! It stopped crashing But it has similar issues which squeezer app had -> there is a lot delay -> the app still crashes out of nowhere sometimes and stops working until reset the data
I don't think there is any point of trying to make it compatible with music assistant Thanks for providing the test apks :)
Also I get this message out of nowhere a lot of times
Well, a log would help ;-)
Here you go:
2024-08-26 21:35:49.089 20961 20961 de.maniac103.squeezeclient.debug E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient.debug, PID: 20961 java.lang.IllegalStateException at de.maniac103.squeezeclient.cometd.ConnectionHelper.publishOneShotRequest(ConnectionHelper.kt:313) at de.maniac103.squeezeclient.cometd.ConnectionHelper.setVolume(ConnectionHelper.kt:261) at de.maniac103.squeezeclient.ui.volume.VolumeFragment$handleKeyDown$1.invokeSuspend(VolumeFragment.kt:120) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:363) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:21) at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:88) at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:123) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52) at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:43) at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1) at de.maniac103.squeezeclient.ui.volume.VolumeFragment.handleKeyDown(VolumeFragment.kt:118) at de.maniac103.squeezeclient.ui.MainActivity.onKeyDown(MainActivity.kt:238) at android.view.KeyEvent.dispatch(KeyEvent.java:3029) at android.app.Activity.dispatchKeyEvent(Activity.java:4502) at androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.kt:103) at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:85) at androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.kt:117) at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:604) at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:59) at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDelegateImpl.java:3397) at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:364) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:7953) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:7793) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7186) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7243) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7209) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:7375) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7217) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:7432) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7190) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7243) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7209) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7217) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7190) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7243) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7209) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:7408) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:7641) at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:4910) at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:4287) at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:4278) at android.view.inputmethod.InputMethodManager.-$$Nest$mfinishedInputEvent(Unknown Source:0) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:4887)
Also, after playing around a bit, I can definitely say that the app is working way better than the Squeezer app.
However, I'm not sure wheather the delay in updating the squeeze client app normal behaviour Like when I press the play pause buttons, they do work but they don't update in the app
Like in this video when I pressed the play pause button it did work and paused the music but it never updated in the app until I forced tap and restarted the app
https://github.com/user-attachments/assets/faa293d5-c876-41db-ae91-3432d99b93c2
This sounds like player status updates aren't sent as expected. Unlike Squeezer I'm not trying to 'predict' server responses to commands for updating the UI, but wait for the server sending an update event as kind of acknowledgement. As mentioned, a log from the time before pressing the button until - say - 10 seconds after pressing would be helpful.
2024-08-26 22:22:05.800 28500 28500 de.maniac103.squeezeclient.debug W MediaSessionCompat : Couldn't find a unique registered media button receiver in the given context.
2024-08-26 22:22:44.300 28885 28885 de.maniac103.squeezeclient.debug I view_enqueue_input_event : [Motion - Cancel,de.maniac103.squeezeclient.debug/de.maniac103.squeezeclient.ui.MainActivity]
The xonnection lost error I keep getting out of nowhere
2024-08-26 22:23:37.673 28885 28885 de.maniac103.squeezeclient.debug W MainActivity : Connection failed de.maniac103.squeezeclient.cometd.CometdClient$CometdException: Not connected at de.maniac103.squeezeclient.cometd.CometdClient.publish(CometdClient.kt:118) at de.maniac103.squeezeclient.cometd.ConnectionHelper.publishRequest(ConnectionHelper.kt:349) at de.maniac103.squeezeclient.cometd.ConnectionHelper.publishRequest$default(ConnectionHelper.kt:339) at de.maniac103.squeezeclient.cometd.ConnectionHelper$connect$1.invokeSuspend(ConnectionHelper.kt:154) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:28) at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:99) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8700) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
By log I was referring to the full log generated by the app, not only stack traces and warnings ;-) In particular, I'm interested in the messages exchanged between app and server. To give a bit of background/explanation:
I want to see the communication to confirm the assumptions. If they hold true, I guess that's a topic for the MA folks to solve; I don't want to adopt for that in the app because it means restructuring a lot of stuff. If they don't hold true, we'll need to see what else is off there. Looking at the MA code it looks like they implemented sending events in response to subscriptions, but I don't understand that code well enough to judge whether the implementation is sufficient.
2024-08-26 21:35:49.089 20961 20961 de.maniac103.squeezeclient.debug E AndroidRuntime : FATAL EXCEPTION: main Process: de.maniac103.squeezeclient.debug, PID: 20961 java.lang.IllegalStateException at de.maniac103.squeezeclient.cometd.ConnectionHelper.publishOneShotRequest(ConnectionHelper.kt:313) at de.maniac103.squeezeclient.cometd.ConnectionHelper.setVolume(ConnectionHelper.kt:261) at de.maniac103.squeezeclient.ui.volume.VolumeFragment$handleKeyDown$1.invokeSuspend(VolumeFragment.kt:120)
I fixed this one via https://github.com/maniac103/squeezeclient/commit/3229162964eb6f283a9097a7eb04691271abbaf9
Hey sorry for the late response, Here's all the logs logs.log
I also noticed that if there is nothing playing or in the queue the app keeps crashing
The crashing is because they omit parts of the player status response if a given player is not powered, unlike LMS (example). I'd consider this an MA bug, but I can work around that (and probably should review LMS code as well to see what properties actually might be optional).
The larger issue is the update events, where, if I'm reading the code here correctly, determine the type of events to be sent (and whether to send events at all) by interpreting the channel names the client subscribed for instead of looking at the subscription itself. In particular, they seem to expect the player ID as part of the channel name in its original MAC address form (11:22:33:44:55:66
), but I cut out the colons (112233445566
) because colons are not allowed in channel names as per the cometd spec (mind :
not being part of mark
). I consider that a bug in MA as well, but one I think it's worth filing a bug report for: they should treat channel names in subscriptions as opaque and look at the actual subscription contents.
At this point I agree that a rollup of this thread should be posted to the MA Git issues. Perhaps some modifications to the Lyrion "light" server should be made. I wonder if it has been tested with many squeezebox devices. I agree out of all the protocols offered by MA, slimproto is the most feature complete. And it could spark interest in the squeezebox used market.
I haven't been involved in the testing of the client so I'm not the person to bring their attention to it. If further assistance in testing is needed message me. I've got several "ThinkView Smart"s running lineageOS that i need a simple solution like this for.
At this point I agree that a rollup of this thread should be posted to the MA Git issues. Perhaps some modifications to the Lyrion "light" server should be made. I wonder if it has been tested with many squeezebox devices. I agree out of all the protocols offered by MA, slimproto is the most feature complete. And it could spark interest in the squeezebox used market.
I haven't been involved in the testing of the client so I'm not the person to bring their attention to it. If further assistance in testing is needed message me. I've got several "ThinkView Smart"s running lineageOS that i need a simple solution like this for.
haha, i also got 3 thinksmart view devices to run this, but the app is crashing as soon as i try to connect to home assistant. (slimproto integration)
There is a well working SB Player app in the play store thats just 4 euro or so, however it disconnects and wont reconnect after some time, even with all settings to prevent the app from closing. i want to use this for notification sounds, so disconnects are sad.
Which SB app are you referring to?
Which SB app are you referring to?
Thats literary the name of it. SB Player. It also connects to home assistant slimproto. but it disconnects quite often at seemingly random times, and does not try to reconnect.
At this point I agree that a rollup of this thread should be posted to the MA Git issues. Perhaps some modifications to the Lyrion "light" server should be made. I wonder if it has been tested with many squeezebox devices. I agree out of all the protocols offered by MA, slimproto is the most feature complete. And it could spark interest in the squeezebox used market. I haven't been involved in the testing of the client so I'm not the person to bring their attention to it. If further assistance in testing is needed message me. I've got several "ThinkView Smart"s running lineageOS that i need a simple solution like this for.
haha, i also got 3 thinksmart view devices to run this, but the app is crashing as soon as i try to connect to home assistant. (slimproto integration)
There is a well working SB Player app in the play store thats just 4 euro or so, however it disconnects and wont reconnect after some time, even with all settings to prevent the app from closing. i want to use this for notification sounds, so disconnects are sad.
Did you try using Music Assistant? Check their documentation for player, you cannot have the slimproto integration cannot run side by side with MA. Strangely MA doesn't use LMS as a music source, so I'm not sure what is going on with that.
it seems this issue is a lot less common with the slimproto in music assistant, compared to slimproto without using music assistant. weird.
Crashing constanly