feat: media player with reconciliation and pinned media proxy (Phase 5)
- MediaAPI client for all 10 media endpoints + Codable models - PinnedMediaResourceLoader: AVAssetResourceLoaderDelegate proxying https media through the pinned-TLS session (AVPlayer ignores registered URLProtocol subclasses and can't trust the self-signed cert) - MediaPlayerController: AVPlayer + 1.5s poll reconciliation ported from web app.js (track swap, late audio_url, desired state, seek_hint, reporting, enter-media-scope carry-over, post-talk resume) - MediaPanelView UI + music.note toolbar entry - VoiceSession wiring (enterMediaScope/endConversation) Playback of the library's webm tracks is blocked by an iOS platform limitation (AVPlayer cannot decode webm); TLS/Range proxy, reconciliation, polling, reporting and UI are all verified working in the simulator.
This commit is contained in:
1 parent
f2022f8a96
commit
0af944e60d
8 files changed
+964
-5
No files matched your search
@@ -33,6 +33,7 @@ final class VoiceSession: ObservableObject {
|
||||
let controlChannel = ControlChannel()
|
||||
let transcriptHandler = TranscriptHandler()
|
||||
let stateModel = ConversationStateModel()
|
||||
let mediaController: MediaPlayerController
|
||||
private let config: ServerConfig
|
||||
private let tokenClient: TokenClient
|
||||
private let settings: SettingsStore
|
||||
@@ -44,6 +45,9 @@ 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)
|
||||
@@ -97,6 +101,7 @@ 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 {
|
||||
@@ -282,6 +287,7 @@ final class VoiceSession: ObservableObject {
|
||||
reconnectAttempted = false
|
||||
stateModel.stop()
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
await mediaController.endConversation()
|
||||
await teardownRoom()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user