feat: also collect track position in ms, allows pause handling

This commit is contained in:
2026-05-24 07:29:26 +02:00
parent 698605d7a9
commit b5bc01fac2
4 changed files with 58 additions and 18 deletions

View File

@@ -232,13 +232,17 @@ fun NowPlayingRoute(
LaunchedEffect(collectRunData, playback) {
if (!collectRunData) {
collector.setAcceptSamples(false)
collector.setCollectingEnabled(false)
return@LaunchedEffect
}
val service = playback ?: return@LaunchedEffect
val service = playback ?: run {
collector.setCollectingEnabled(false)
return@LaunchedEffect
}
collector.setPlaybackPositionMsProvider { service.getPlaybackPositionMs() }
collector.setCollectingEnabled(true)
var lastTrackId: String? = null
service.uiState.collect { state ->
collector.setAcceptSamples(state.isPlaying)
val trackId = state.currentTrackId
if (trackId != null && trackId != lastTrackId) {
collector.markSongStart()

View File

@@ -26,7 +26,7 @@ class RunDataCollector(
private val handlerThread = HandlerThread("RunDataCollect").apply { start() }
private val handler = Handler(handlerThread.looper)
private val accelBuffer = mutableListOf<RunDataSample>()
private val accelBuffer = mutableListOf<RunAccelSample>()
private val gyroBuffer = mutableListOf<RunDataSample>()
private val gpsBuffer = mutableListOf<RunGpsSample>()
@@ -34,7 +34,10 @@ class RunDataCollector(
private var songStartElapsedRealtimeNanos: Long? = null
@Volatile
private var acceptSamples = false
private var collectingEnabled = false
@Volatile
private var playbackPositionMsProvider: () -> Long = { 0L }
private var sensorsRegistered = false
private var locationRegistered = false
@@ -42,24 +45,32 @@ class RunDataCollector(
private val sensorListener =
object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
if (!acceptSamples) return
if (!collectingEnabled) return
val timestamp = relativeTimestampNanos(event.timestamp) ?: return
when (event.sensor.type) {
Sensor.TYPE_ACCELEROMETER -> {
val sample =
RunAccelSample(
timestampNanos = timestamp,
positionMs = playbackPositionMsProvider(),
values = floatArrayOf(event.values[0], event.values[1], event.values[2]),
)
synchronized(accelBuffer) {
accelBuffer.add(sample)
}
}
Sensor.TYPE_GYROSCOPE -> {
val sample =
RunDataSample(
timestampNanos = timestamp,
values = floatArrayOf(event.values[0], event.values[1], event.values[2]),
)
when (event.sensor.type) {
Sensor.TYPE_ACCELEROMETER ->
synchronized(accelBuffer) {
accelBuffer.add(sample)
}
Sensor.TYPE_GYROSCOPE ->
synchronized(gyroBuffer) {
gyroBuffer.add(sample)
}
}
}
}
override fun onAccuracyChanged(
sensor: Sensor?,
@@ -69,7 +80,7 @@ class RunDataCollector(
private val locationListener =
LocationListener { location ->
if (!acceptSamples) return@LocationListener
if (!collectingEnabled) return@LocationListener
recordGpsLocation(location)
}
@@ -148,8 +159,12 @@ class RunDataCollector(
songStartElapsedRealtimeNanos = null
}
fun setAcceptSamples(accept: Boolean) {
acceptSamples = accept
fun setCollectingEnabled(enabled: Boolean) {
collectingEnabled = enabled
}
fun setPlaybackPositionMsProvider(provider: () -> Long) {
playbackPositionMsProvider = provider
}
fun snapshotAndClear(): RunTrackDataSnapshot =

View File

@@ -49,7 +49,7 @@ object RunDataStorage {
val jsonString =
JSONObject()
.apply {
put("data", samplesToJsonArray(snapshot.accelerometer))
put("data", accelToJsonArray(snapshot.accelerometer))
put("gyro", samplesToJsonArray(snapshot.gyroscope))
put("gps", gpsToJsonArray(snapshot.gps))
put("meta", metaContentUri)
@@ -65,6 +65,27 @@ object RunDataStorage {
}
}
private fun accelToJsonArray(samples: List<RunAccelSample>): JSONArray {
val array = JSONArray()
for (sample in samples) {
array.put(
JSONObject().apply {
put("timestamp", sample.timestampNanos)
put("positionMs", sample.positionMs)
put(
"values",
JSONArray().apply {
for (v in sample.values) {
put(v.toDouble())
}
},
)
},
)
}
return array
}
private fun samplesToJsonArray(samples: List<RunDataSample>): JSONArray {
val array = JSONArray()
for (sample in samples) {

View File

@@ -8,7 +8,7 @@ data class RunGpsSample(
)
data class RunTrackDataSnapshot(
val accelerometer: List<RunDataSample>,
val accelerometer: List<RunAccelSample>,
val gyroscope: List<RunDataSample>,
val gps: List<RunGpsSample>,
) {