Remove embedded music player

The music feature is retired: delete the Media tab, MediaAPI,
MediaPlayerController, PinnedMediaResourceLoader, MediaPanelView, the
media_state control publish, media scope handling in VoiceSession, the
volume setting, and all media tests. App is now Talk + Activity tabs.

Backend media API in hope-voice-api is untouched (still serves the web UI).
This commit is contained in:
snowspeeder committed 2026-09-12 06:26:58 -04:00
1 parent 3620a2387b
commit ed329213de
18 files changed
+55 -2393

No files matched your search

+4 -14
View File
@@ -48,7 +48,6 @@ final class VoiceSession: ObservableObject {
let transcriptHandler = TranscriptHandler()
let stateModel = ConversationStateModel()
let taskStore = TaskStore()
let mediaController: MediaPlayerController
private let config: ServerConfig
private let tokenClient: TokenClient
private let settings: SettingsStore
@@ -90,9 +89,6 @@ final class VoiceSession: ObservableObject {
self.config = config
self.tokenClient = tokenClient
self.settings = settings
let mediaAPI = MediaAPI(config: config)
self.mediaController = MediaPlayerController(api: mediaAPI, settings: settings)
mediaController.attach(session: self)
room.add(delegate: self)
room.add(delegate: controlChannel)
room.add(delegate: transcriptHandler)
@@ -211,7 +207,6 @@ final class VoiceSession: ObservableObject {
do {
let token = try await tokenClient.fetchToken()
logger.log("token ok room=\(token.room, privacy: .public)")
await mediaController.enterMediaScope(roomName: token.room)
try await room.connect(url: config.livekitURL.absoluteString, token: token.token, connectOptions: makeConnectOptions())
result = .success(())
} catch {
@@ -263,8 +258,7 @@ final class VoiceSession: ObservableObject {
private func handleAgentTimeout(generation: Int) async {
guard generation == sessionGeneration, state == .waitingAgent else { return }
guard !reconnectAttempted else {
// Final failure: tear down the live room, restore the idle timer,
// and end the media scope so no stale room or wake lock survives.
// Final failure: tear down the live room and restore the idle timer.
logger.log("agent timeout final, tearing down")
await teardownForFailure(message: "Agent never joined. Is the agent worker running?")
return
@@ -281,8 +275,7 @@ final class VoiceSession: ObservableObject {
/// current generation (so stale callbacks become no-ops), clear all
/// per-room/session ephemeral published fields (agent, mute state, model
/// list, error state, interruption ownership), disconnect and recreate the
/// room, stop conversation state, restore the idle timer, and end the media
/// scope. Only after all cleanup completes does the session publish
/// room, stop conversation state, restore the idle timer, and publish
/// `.failed(message)`, making retry safe: the old room is fully torn down
/// before Start becomes available again.
///
@@ -308,7 +301,6 @@ final class VoiceSession: ObservableObject {
interruptionSequence += 1
stateModel.stop()
UIApplication.shared.isIdleTimerDisabled = false
await mediaController.endConversation()
await teardownRoom()
// Final reset immediately before publishing .failed: any old-room
@@ -540,15 +532,13 @@ final class VoiceSession: ObservableObject {
interruptionSequence += 1
stateModel.stop()
UIApplication.shared.isIdleTimerDisabled = false
await mediaController.endConversation()
await teardownRoom()
// Final reset before publishing .idle: any old-room callback delivered
// during the teardownRoom() await may have repopulated ephemeral fields.
// This ensures the idle state is clean for server replacement (Iteration 09).
resetEphemeralFields()
// Publish .idle only after media and room teardown have completed.
// This makes idle a truthful readiness signal for server replacement:
// the old session is fully torn down before the UI shows "ready to start".
// Publish .idle only after room teardown has completed: the old session
// is fully torn down before the UI shows "ready to start".
state = .idle
}