Add console logs.

This commit is contained in:
Adrian Kuta (DZCQIWG)
2025-09-18 15:56:49 +02:00
parent 83d8fa1945
commit f459482ddd
5 changed files with 81 additions and 7 deletions

View File

@@ -49,6 +49,8 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
implementation(libs.timber)
implementation(libs.kotlinx.coroutines.android)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
@@ -56,4 +58,4 @@ dependencies {
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
}
}

View File

@@ -42,6 +42,7 @@ import dev.adriankuta.visualizer.components.MetricsSection
import dev.adriankuta.visualizer.components.PermissionSection
import dev.adriankuta.visualizer.components.WaveformView
import dev.adriankuta.visualizer.ui.theme.VisualizerTheme
import timber.log.Timber
/**
* Entry point activity that hosts the Compose UI for the audio visualizer demo.
@@ -51,6 +52,10 @@ import dev.adriankuta.visualizer.ui.theme.VisualizerTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize Timber for logging
Timber.plant(Timber.DebugTree())
enableEdgeToEdge()
setContent {
VisualizerTheme {
@@ -103,8 +108,8 @@ private fun VisualizerScreen(modifier: Modifier = Modifier) {
val observer = LifecycleEventObserver { _, event ->
if (!permissionGranted) return@LifecycleEventObserver
when (event) {
Lifecycle.Event.ON_START -> runCatching { controller.start() }
Lifecycle.Event.ON_STOP -> runCatching { controller.stop() }
Lifecycle.Event.ON_CREATE -> runCatching { controller.start() }
Lifecycle.Event.ON_DESTROY -> runCatching { controller.stop() }
else -> {}
}
}
@@ -179,4 +184,4 @@ fun VisualizerPreview() {
VisualizerTheme {
VisualizerScreen()
}
}
}

View File

@@ -1,6 +1,8 @@
package dev.adriankuta.visualizer
import android.media.audiofx.Visualizer
import kotlinx.coroutines.*
import timber.log.Timber
/**
* Simple wrapper over Android Visualizer to capture global output mix (audio session 0).
@@ -11,6 +13,10 @@ class VisualizerController(
private val onFft: (ByteArray) -> Unit,
) {
private var visualizer: Visualizer? = null
private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var loggingJob: Job? = null
private var latestWaveform: ByteArray? = null
private var latestFft: ByteArray? = null
/**
* Starts capturing audio data via [Visualizer].
@@ -23,6 +29,7 @@ class VisualizerController(
fun start() {
if (visualizer != null) return
try {
Timber.d("Starting audio visualizer listening (audioSessionId: $audioSessionId)")
val v = Visualizer(audioSessionId)
// Use the maximum supported capture size for better resolution
val captureSize = Visualizer.getCaptureSizeRange().let { it[1] }
@@ -34,7 +41,10 @@ class VisualizerController(
waveform: ByteArray?,
samplingRate: Int
) {
if (waveform != null) onWaveform(waveform)
if (waveform != null) {
latestWaveform = waveform.clone()
onWaveform(waveform)
}
}
override fun onFftDataCapture(
@@ -42,13 +52,22 @@ class VisualizerController(
fft: ByteArray?,
samplingRate: Int
) {
if (fft != null) onFft(fft)
if (fft != null) {
latestFft = fft.clone()
onFft(fft)
}
}
}, rate, true, true)
v.enabled = true
visualizer = v
// Start coroutine-based logging for raw data samples every 1 second
startDataLogging()
Timber.i("Audio visualizer listening started successfully")
} catch (e: Throwable) {
// If Visualizer cannot be initialized (e.g. permission or device restriction), ensure cleanup
Timber.e(e, "Failed to start audio visualizer listening")
stop()
throw e
}
@@ -60,8 +79,45 @@ class VisualizerController(
*/
@Synchronized
fun stop() {
Timber.d("Stopping audio visualizer listening")
// Stop the logging coroutine
loggingJob?.cancel()
loggingJob = null
visualizer?.enabled = false
visualizer?.release()
visualizer = null
// Clear latest data
latestWaveform = null
latestFft = null
Timber.i("Audio visualizer listening stopped")
}
/**
* Starts a coroutine that logs raw data samples every 1 second.
*/
private fun startDataLogging() {
loggingJob?.cancel() // Cancel any existing logging job
loggingJob = coroutineScope.launch {
while (isActive) {
delay(1000) // Wait for 1 second
val waveform = latestWaveform
val fft = latestFft
if (waveform != null && fft != null) {
// Log sample of raw data (first few bytes to avoid too much log spam)
val waveformSample = waveform.take(8).joinToString(", ") { it.toString() }
val fftSample = fft.take(8).joinToString(", ") { it.toString() }
Timber.d("Raw data sample - Waveform {size: ${waveform.size}, sample: [$waveformSample...]}, FFT {size: {${fft.size}}, sample: [$fftSample...]}")
} else {
Timber.d("Raw data sample - No data available yet")
}
}
}
}
}