maniac103 / squeezeclient

Android LMS controller application
GNU General Public License v3.0
13 stars 0 forks source link

Crashing with my lms server #2

Open ohuc opened 2 months ago

ohuc commented 2 months ago

Crashing constanly

maniac103 commented 2 months ago

What version of the app - built from git or F-Droid? Did you try restarting the server? What server version?

maniac103 commented 2 months ago

And most importantly: can you provide output of adb logcat?

ohuc commented 2 months ago

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]

ohuc commented 2 months ago

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

droyholmes commented 2 months ago

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.

ohuc commented 2 months ago

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

maniac103 commented 2 months ago

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.

ohuc commented 2 months ago

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

droyholmes commented 2 months ago

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!

maniac103 commented 2 months ago

Test APK (rename to .apk)

(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.

ohuc commented 2 months ago

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]

maniac103 commented 2 months ago

Stupid me ... note to self: don't do stuff in a hurry, it leads to mistakes :-(

Next attempt

ohuc commented 2 months ago

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]

maniac103 commented 2 months ago

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?

ohuc commented 2 months ago

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"}]})

ohuc commented 2 months ago

These are the logs right before the crash Screenshot_20240825-191306

maniac103 commented 2 months ago

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)?

ohuc commented 2 months ago

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)

maniac103 commented 2 months ago

OK, thanks. Strangely enough your new JSON also doesn't reproduce it, but looking at MA sources hopefully got me on the right track.

-> Next test APK

(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()
 )
ohuc commented 2 months ago

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 :)

ohuc commented 2 months ago

Also I get this message out of nowhere a lot of times Screenshot_20240826-213549

maniac103 commented 2 months ago

Well, a log would help ;-)

ohuc commented 2 months ago

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)

ohuc commented 2 months ago

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

maniac103 commented 2 months ago

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.

ohuc commented 2 months ago

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)

maniac103 commented 2 months ago

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.

maniac103 commented 2 months ago

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

ohuc commented 2 months ago

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

maniac103 commented 2 months ago

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.

droyholmes commented 2 months ago

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.

borgqueenx commented 1 month ago

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.

ohuc commented 1 month ago

Which SB app are you referring to?

borgqueenx commented 1 month ago

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.

droyholmes commented 1 month ago

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.

borgqueenx commented 1 month ago

it seems this issue is a lot less common with the slimproto in music assistant, compared to slimproto without using music assistant. weird.