M9 diagnostics follow-ups: playback relabel, sort, connected fix, per-skip + track-identity #105
+20
-6
@@ -174,12 +174,16 @@ class DiagnosticsReporter @Inject constructor(
|
||||
.distinctUntilChanged()
|
||||
.collect { (index, _) ->
|
||||
val ui = playerController.uiState.value
|
||||
val casting = outputPicker.routesState.value.current.protocol !=
|
||||
OutputRoute.Protocol.SYSTEM
|
||||
record("playback", buildJsonObject {
|
||||
put("event", "track_change")
|
||||
put("local_index", index)
|
||||
// Track IDENTITY, not just index — indices wobble across
|
||||
// re-casts, so the id + Sonos URI make a desync unambiguous.
|
||||
put("local_track_id", ui.currentTrack?.id ?: "")
|
||||
put("local_pos_ms", ui.positionMs)
|
||||
put("sonos_track", remoteState.trackNumber)
|
||||
put("sonos_pos_ms", remoteState.positionMs)
|
||||
putSonos(this, casting)
|
||||
put("upnp_loading", ui.isUpnpLoading)
|
||||
put("server_health", networkStatus.state.value.name)
|
||||
put("route", outputPicker.routesState.value.current.name)
|
||||
@@ -214,13 +218,11 @@ class DiagnosticsReporter @Inject constructor(
|
||||
put("is_playing", ui.isPlaying)
|
||||
put("source", ui.currentSource ?: "")
|
||||
put("local_index", ui.queueIndex)
|
||||
put("local_track_id", ui.currentTrack?.id ?: "")
|
||||
put("local_pos_ms", ui.positionMs)
|
||||
put("route", route.name)
|
||||
put("route_protocol", route.protocol.name)
|
||||
// UPnP/Sonos remote-vs-local — the desync signal.
|
||||
put("sonos_track", remoteState.trackNumber)
|
||||
put("sonos_pos_ms", remoteState.positionMs)
|
||||
put("sonos_playing", remoteState.isPlaying)
|
||||
putSonos(this, routeActive)
|
||||
addPowerFields(this)
|
||||
})
|
||||
}
|
||||
@@ -285,6 +287,18 @@ class DiagnosticsReporter @Inject constructor(
|
||||
addPowerFields(this)
|
||||
}
|
||||
|
||||
// Sonos/UPnP remote-vs-local desync fields. Only meaningful while a
|
||||
// remote route is active; zeroed otherwise so a stale RemotePlayerState
|
||||
// from a just-ended cast can't masquerade as live Sonos data (the
|
||||
// cast→phone handoff artifact). currentTrackUri is the desync ground
|
||||
// truth — it carries the track the speaker is actually streaming.
|
||||
private fun putSonos(builder: kotlinx.serialization.json.JsonObjectBuilder, casting: Boolean) {
|
||||
builder.put("sonos_track", if (casting) remoteState.trackNumber else 0)
|
||||
builder.put("sonos_pos_ms", if (casting) remoteState.positionMs else 0)
|
||||
builder.put("sonos_playing", casting && remoteState.isPlaying)
|
||||
if (casting) builder.put("sonos_uri", remoteState.currentTrackUri)
|
||||
}
|
||||
|
||||
private fun addPowerFields(builder: kotlinx.serialization.json.JsonObjectBuilder) {
|
||||
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
builder.put("doze", pm.isDeviceIdleMode)
|
||||
|
||||
Reference in New Issue
Block a user