Wire VoiceLoop into ClippySession lifecycle and ClippyScreen talk button
This commit is contained in:
@@ -3,6 +3,7 @@ package farm.hobbs.clippyauto.auto
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.*
|
||||
import farm.hobbs.clippyauto.VoiceLoop
|
||||
|
||||
/**
|
||||
* The Android Auto screen for ClippyAuto.
|
||||
@@ -15,6 +16,11 @@ import androidx.car.app.model.*
|
||||
class ClippyScreen(carContext: CarContext) : Screen(carContext) {
|
||||
|
||||
private var statusText = "Tap to talk to Clippy"
|
||||
private var voiceLoop: VoiceLoop? = null
|
||||
|
||||
fun attachVoiceLoop(loop: VoiceLoop) {
|
||||
voiceLoop = loop
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
val action = Action.Builder()
|
||||
@@ -51,11 +57,7 @@ class ClippyScreen(carContext: CarContext) : Screen(carContext) {
|
||||
}
|
||||
|
||||
private fun onTalkPressed() {
|
||||
// TODO: Wire to VoiceStateMachine
|
||||
// IDLE → start listening
|
||||
// SPEAKING → interrupt (fade TTS, activate STT)
|
||||
statusText = "Listening..."
|
||||
invalidate() // Refresh the screen
|
||||
voiceLoop?.onTalkPressed()
|
||||
}
|
||||
|
||||
fun updateStatus(status: String) {
|
||||
|
||||
@@ -5,26 +5,55 @@ import androidx.car.app.Screen
|
||||
import androidx.car.app.Session
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import farm.hobbs.clippyauto.VoiceLoop
|
||||
import farm.hobbs.clippyauto.matrix.MatrixRestClient
|
||||
|
||||
/**
|
||||
* Android Auto session — manages the lifecycle of a Clippy voice interaction.
|
||||
* Sends session_start on create, session_end on destroy.
|
||||
* Owns the VoiceLoop and passes it to the screen.
|
||||
*/
|
||||
class ClippySession : Session(), DefaultLifecycleObserver {
|
||||
|
||||
private var voiceLoop: VoiceLoop? = null
|
||||
private var screen: ClippyScreen? = null
|
||||
|
||||
// TODO: Move to config / SharedPreferences / SetupActivity
|
||||
companion object {
|
||||
const val HOMESERVER = "https://mess.hobbs.farm"
|
||||
const val ROOM_ID = "" // Set after #clippy-voice room is created
|
||||
const val CLIPPY_USER = "@clippy:hobbs.farm"
|
||||
}
|
||||
|
||||
override fun onCreateScreen(intent: Intent): Screen {
|
||||
lifecycle.addObserver(this)
|
||||
return ClippyScreen(carContext)
|
||||
val clippyScreen = ClippyScreen(carContext)
|
||||
screen = clippyScreen
|
||||
return clippyScreen
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
// TODO: Send session_start signal to Matrix #clippy-voice room
|
||||
// TODO: Start Matrix sync (fallback path)
|
||||
// TODO: Subscribe to FCM response bus
|
||||
val matrixClient = MatrixRestClient(HOMESERVER)
|
||||
|
||||
voiceLoop = VoiceLoop(
|
||||
context = carContext,
|
||||
matrixClient = matrixClient,
|
||||
roomId = ROOM_ID,
|
||||
clippyUserId = CLIPPY_USER,
|
||||
onStateChange = { state, status ->
|
||||
screen?.updateStatus(status)
|
||||
}
|
||||
)
|
||||
|
||||
voiceLoop?.initialize()
|
||||
voiceLoop?.startSession()
|
||||
|
||||
// Give the screen a reference so the talk button works
|
||||
screen?.attachVoiceLoop(voiceLoop!!)
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
// TODO: Send session_end signal to Matrix
|
||||
// TODO: Clean up voice pipeline
|
||||
voiceLoop?.endSession()
|
||||
voiceLoop?.destroy()
|
||||
voiceLoop = null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user