@@ -5,18 +5,17 @@ import {
55 normalizeAudioProbeRecord ,
66 type AudioProbeResult ,
77} from '../audio-probe-result.ts' ;
8- import { startMacOsAudioProbeProcess } from '../platforms/apple/os/macos/helper .ts' ;
8+ import type { HostAudioProbeBackend } from '../platforms/audio-probe-backend .ts' ;
99import { AppError } from '../kernel/errors.ts' ;
1010import { sleep } from '../utils/timeouts.ts' ;
1111import type { SessionStore } from './session-store.ts' ;
1212import type { SessionState } from './types.ts' ;
1313
14- const HOST_AUDIO_BACKEND = 'macos-screencapturekit' ;
15-
1614export type HostAudioProbeCommand = {
1715 session : SessionState ;
1816 sessionName : string ;
1917 sessionStore : SessionStore ;
18+ backend : HostAudioProbeBackend ;
2019 probeAction : 'start' | 'status' | 'stop' ;
2120 durationMs : number ;
2221 bucketMs : number ;
@@ -25,20 +24,24 @@ export type HostAudioProbeCommand = {
2524export async function runHostSystemAudioProbeCommand (
2625 request : HostAudioProbeCommand ,
2726) : Promise < AudioProbeResult > {
28- const { session, probeAction } = request ;
27+ const { session, probeAction, backend } = request ;
2928 if ( probeAction === 'start' ) {
3029 await stopSessionAudioProbe ( session , 'restarted' ) ;
3130 const statusPath = path . join (
3231 request . sessionStore . ensureSessionDir ( request . sessionName ) ,
3332 'audio-probe.json' ,
3433 ) ;
35- const probe = await startMacOsAudioProbeProcess ( {
34+ const probe = await backend . start ( {
3635 durationMs : request . durationMs ,
3736 bucketMs : request . bucketMs ,
3837 statusPath,
3938 } ) ;
4039 session . audioProbe = {
41- platform : 'host-system-audio' ,
40+ platform : backend . platform ,
41+ source : backend . source ,
42+ backend : backend . backend ,
43+ sourceCount : backend . sourceCount ,
44+ notes : backend . notes ( session . device ) ,
4245 child : probe . child ,
4346 wait : probe . wait ,
4447 statusPath,
@@ -75,7 +78,7 @@ export async function stopSessionAudioProbe(
7578 probe . child . kill ( 'SIGTERM' ) ;
7679 await probe . wait . catch ( ( ) => { } ) ;
7780 session . audioProbe = undefined ;
78- return finalizeHostSystemAudioProbeStatus ( beforeStop , probe , session . device , reason ) ;
81+ return finalizeHostSystemAudioProbeStatus ( beforeStop , probe , reason ) ;
7982}
8083
8184async function waitForHostSystemAudioProbeStatus ( session : SessionState ) : Promise < AudioProbeResult > {
@@ -110,7 +113,7 @@ async function readHostSystemAudioProbeStatus(
110113 if ( ! probe ) return undefined ;
111114 try {
112115 const raw = await fs . readFile ( probe . statusPath , 'utf8' ) ;
113- return normalizeHostSystemAudioProbeData ( JSON . parse ( raw ) , probe , session . device ) ;
116+ return normalizeHostSystemAudioProbeData ( JSON . parse ( raw ) , probe ) ;
114117 } catch ( error ) {
115118 if ( ( error as NodeJS . ErrnoException ) . code === 'ENOENT' ) return undefined ;
116119 throw error ;
@@ -120,36 +123,34 @@ async function readHostSystemAudioProbeStatus(
120123function normalizeHostSystemAudioProbeData (
121124 value : unknown ,
122125 probe : NonNullable < SessionState [ 'audioProbe' ] > ,
123- device : SessionState [ 'device' ] ,
124126) : AudioProbeResult {
125127 return normalizeAudioProbeRecord ( value , {
126- source : 'system-audio' ,
127- backend : HOST_AUDIO_BACKEND ,
128+ source : probe . source ,
129+ backend : probe . backend ,
128130 durationMs : probe . durationMs ,
129131 elapsedMs : Date . now ( ) - probe . startedAt ,
130132 bucketMs : probe . bucketMs ,
131133 activeFallback : true ,
132- sourceCount : 1 ,
133- notes : hostSystemAudioProbeNotes ( device ) ,
134+ sourceCount : probe . sourceCount ,
135+ notes : probe . notes ,
134136 } ) ;
135137}
136138
137139function finalizeHostSystemAudioProbeStatus (
138140 status : AudioProbeResult | undefined ,
139141 probe : NonNullable < SessionState [ 'audioProbe' ] > ,
140- device : SessionState [ 'device' ] ,
141142 reason : string ,
142143) : AudioProbeResult {
143144 const elapsedMs = Math . min ( probe . durationMs , Math . max ( 0 , Date . now ( ) - probe . startedAt ) ) ;
144145 const base =
145146 status ??
146147 emptyAudioProbeResult ( {
147- source : 'system-audio' ,
148- backend : HOST_AUDIO_BACKEND ,
148+ source : probe . source ,
149+ backend : probe . backend ,
149150 durationMs : probe . durationMs ,
150151 bucketMs : probe . bucketMs ,
151- sourceCount : 1 ,
152- notes : hostSystemAudioProbeNotes ( device ) ,
152+ sourceCount : probe . sourceCount ,
153+ notes : probe . notes ,
153154 } ) ;
154155 return {
155156 ...base ,
@@ -168,29 +169,15 @@ function buildHostSystemAudioProbeFallback(
168169) : AudioProbeResult {
169170 return emptyAudioProbeResult ( {
170171 state,
171- source : 'system-audio' ,
172- backend : HOST_AUDIO_BACKEND ,
172+ source : request . backend . source ,
173+ backend : request . backend . backend ,
173174 durationMs : request . durationMs ,
174175 bucketMs : request . bucketMs ,
175176 sourceCount : 0 ,
176177 reason,
177178 notes : [
178- ...hostSystemAudioProbeNotes ( request . session . device ) ,
179+ ...request . backend . notes ( request . session . device ) ,
179180 'No active host audio probe is running.' ,
180181 ] ,
181182 } ) ;
182183}
183-
184- function hostSystemAudioProbeNotes ( device : SessionState [ 'device' ] ) : string [ ] {
185- const target =
186- device . platform === 'ios'
187- ? 'iOS simulator'
188- : device . platform === 'android'
189- ? 'Android emulator'
190- : 'macOS session' ;
191- return [
192- `Audio probe samples host system audio through ScreenCaptureKit for this ${ target } ; it is not app-instrumented audio.` ,
193- 'Screen Recording permission is required for host system audio capture.' ,
194- 'Other audible host apps can contribute to the measured buckets.' ,
195- ] ;
196- }
0 commit comments