feat: also collect track position in ms, allows pause handling
This commit is contained in:
@@ -232,13 +232,17 @@ fun NowPlayingRoute(
|
|||||||
|
|
||||||
LaunchedEffect(collectRunData, playback) {
|
LaunchedEffect(collectRunData, playback) {
|
||||||
if (!collectRunData) {
|
if (!collectRunData) {
|
||||||
collector.setAcceptSamples(false)
|
collector.setCollectingEnabled(false)
|
||||||
return@LaunchedEffect
|
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
|
var lastTrackId: String? = null
|
||||||
service.uiState.collect { state ->
|
service.uiState.collect { state ->
|
||||||
collector.setAcceptSamples(state.isPlaying)
|
|
||||||
val trackId = state.currentTrackId
|
val trackId = state.currentTrackId
|
||||||
if (trackId != null && trackId != lastTrackId) {
|
if (trackId != null && trackId != lastTrackId) {
|
||||||
collector.markSongStart()
|
collector.markSongStart()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class RunDataCollector(
|
|||||||
private val handlerThread = HandlerThread("RunDataCollect").apply { start() }
|
private val handlerThread = HandlerThread("RunDataCollect").apply { start() }
|
||||||
private val handler = Handler(handlerThread.looper)
|
private val handler = Handler(handlerThread.looper)
|
||||||
|
|
||||||
private val accelBuffer = mutableListOf<RunDataSample>()
|
private val accelBuffer = mutableListOf<RunAccelSample>()
|
||||||
private val gyroBuffer = mutableListOf<RunDataSample>()
|
private val gyroBuffer = mutableListOf<RunDataSample>()
|
||||||
private val gpsBuffer = mutableListOf<RunGpsSample>()
|
private val gpsBuffer = mutableListOf<RunGpsSample>()
|
||||||
|
|
||||||
@@ -34,7 +34,10 @@ class RunDataCollector(
|
|||||||
private var songStartElapsedRealtimeNanos: Long? = null
|
private var songStartElapsedRealtimeNanos: Long? = null
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var acceptSamples = false
|
private var collectingEnabled = false
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var playbackPositionMsProvider: () -> Long = { 0L }
|
||||||
|
|
||||||
private var sensorsRegistered = false
|
private var sensorsRegistered = false
|
||||||
private var locationRegistered = false
|
private var locationRegistered = false
|
||||||
@@ -42,24 +45,32 @@ class RunDataCollector(
|
|||||||
private val sensorListener =
|
private val sensorListener =
|
||||||
object : SensorEventListener {
|
object : SensorEventListener {
|
||||||
override fun onSensorChanged(event: SensorEvent) {
|
override fun onSensorChanged(event: SensorEvent) {
|
||||||
if (!acceptSamples) return
|
if (!collectingEnabled) return
|
||||||
val timestamp = relativeTimestampNanos(event.timestamp) ?: 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 =
|
val sample =
|
||||||
RunDataSample(
|
RunDataSample(
|
||||||
timestampNanos = timestamp,
|
timestampNanos = timestamp,
|
||||||
values = floatArrayOf(event.values[0], event.values[1], event.values[2]),
|
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) {
|
synchronized(gyroBuffer) {
|
||||||
gyroBuffer.add(sample)
|
gyroBuffer.add(sample)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onAccuracyChanged(
|
override fun onAccuracyChanged(
|
||||||
sensor: Sensor?,
|
sensor: Sensor?,
|
||||||
@@ -69,7 +80,7 @@ class RunDataCollector(
|
|||||||
|
|
||||||
private val locationListener =
|
private val locationListener =
|
||||||
LocationListener { location ->
|
LocationListener { location ->
|
||||||
if (!acceptSamples) return@LocationListener
|
if (!collectingEnabled) return@LocationListener
|
||||||
recordGpsLocation(location)
|
recordGpsLocation(location)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +159,12 @@ class RunDataCollector(
|
|||||||
songStartElapsedRealtimeNanos = null
|
songStartElapsedRealtimeNanos = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setAcceptSamples(accept: Boolean) {
|
fun setCollectingEnabled(enabled: Boolean) {
|
||||||
acceptSamples = accept
|
collectingEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPlaybackPositionMsProvider(provider: () -> Long) {
|
||||||
|
playbackPositionMsProvider = provider
|
||||||
}
|
}
|
||||||
|
|
||||||
fun snapshotAndClear(): RunTrackDataSnapshot =
|
fun snapshotAndClear(): RunTrackDataSnapshot =
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ object RunDataStorage {
|
|||||||
val jsonString =
|
val jsonString =
|
||||||
JSONObject()
|
JSONObject()
|
||||||
.apply {
|
.apply {
|
||||||
put("data", samplesToJsonArray(snapshot.accelerometer))
|
put("data", accelToJsonArray(snapshot.accelerometer))
|
||||||
put("gyro", samplesToJsonArray(snapshot.gyroscope))
|
put("gyro", samplesToJsonArray(snapshot.gyroscope))
|
||||||
put("gps", gpsToJsonArray(snapshot.gps))
|
put("gps", gpsToJsonArray(snapshot.gps))
|
||||||
put("meta", metaContentUri)
|
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 {
|
private fun samplesToJsonArray(samples: List<RunDataSample>): JSONArray {
|
||||||
val array = JSONArray()
|
val array = JSONArray()
|
||||||
for (sample in samples) {
|
for (sample in samples) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ data class RunGpsSample(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class RunTrackDataSnapshot(
|
data class RunTrackDataSnapshot(
|
||||||
val accelerometer: List<RunDataSample>,
|
val accelerometer: List<RunAccelSample>,
|
||||||
val gyroscope: List<RunDataSample>,
|
val gyroscope: List<RunDataSample>,
|
||||||
val gps: List<RunGpsSample>,
|
val gps: List<RunGpsSample>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user