Skip to content

Commit 5ecb92a

Browse files
authored
Merge branch 'beta-4.1.0' into hksv-recording-fix
2 parents e303bb2 + 8e4c838 commit 5ecb92a

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

src/recordingDelegate.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class RecordingDelegate implements CameraRecordingDelegate {
197197
default:
198198
this.log.warn(`❓ HKSV: Unknown reason ${reason}`, this.cameraName)
199199
}
200-
200+
201201
// Abort the stream generator
202202
const abortController = this.streamAbortControllers.get(streamId)
203203
if (abortController) {
@@ -273,14 +273,35 @@ export class RecordingDelegate implements CameraRecordingDelegate {
273273
let fragmentCount = 0
274274

275275
this.log.debug('HKSV: Starting recording request', this.cameraName)
276+
const audioArgs: Array<string> = [
277+
'-acodec',
278+
'aac',
279+
...(configuration.audioCodec.type === AudioRecordingCodecType.AAC_LC
280+
? ['-profile:a', 'aac_low']
281+
: ['-profile:a', 'aac_eld']),
282+
'-ar', '32000',
283+
//`${configuration.audioCodec.samplerate * 1000}`, // i see 3k here before, 3000 also will not work
284+
'-b:a',
285+
`${configuration.audioCodec.bitrate}k`,
286+
'-ac',
287+
`${configuration.audioCodec.audioChannels}`,
288+
]
289+
290+
const profile = configuration.videoCodec.parameters.profile === H264Profile.HIGH
291+
? 'high'
292+
: configuration.videoCodec.parameters.profile === H264Profile.MAIN ? 'main' : 'baseline'
293+
294+
const level = configuration.videoCodec.parameters.level === H264Level.LEVEL4_0
295+
? '4.0'
296+
: configuration.videoCodec.parameters.level === H264Level.LEVEL3_2 ? '3.2' : '3.1'
276297

277298
// Clean H.264 parameters for HKSV compatibility
278299
const videoArgs: Array<string> = [
279300
'-an', '-sn', '-dn', // Disable audio/subtitles/data (audio handled separately)
280301
'-vcodec', 'libx264',
281302
'-pix_fmt', 'yuv420p',
282-
'-profile:v', 'baseline',
283-
'-level:v', '3.1',
303+
'-profile:v', profile, // 'baseline' tested
304+
'-level:v', level, // '3.1' tested
284305
'-preset', 'ultrafast',
285306
'-tune', 'zerolatency',
286307
'-b:v', '600k',
@@ -292,6 +313,14 @@ export class RecordingDelegate implements CameraRecordingDelegate {
292313
'-force_key_frames', 'expr:gte(t,n_forced*1)'
293314
]
294315

316+
if (configuration?.audioCodec) {
317+
// Remove the '-an' flag to enable audio
318+
const anIndex = videoArgs.indexOf('-an')
319+
if (anIndex !== -1) {
320+
videoArgs.splice(anIndex, 1, ...audioArgs)
321+
}
322+
}
323+
295324
// Get input configuration
296325
const ffmpegInput: Array<string> = []
297326
if (this.videoConfig?.prebuffer) {
@@ -302,7 +331,7 @@ export class RecordingDelegate implements CameraRecordingDelegate {
302331
if (!this.videoConfig?.source) {
303332
throw new Error('No video source configured')
304333
}
305-
ffmpegInput.push(...this.videoConfig.source.split(' '))
334+
ffmpegInput.push(...this.videoConfig.source.trim().split(/\s+/).filter(arg => arg.length > 0))
306335
}
307336

308337
if (ffmpegInput.length === 0) {
@@ -361,14 +390,12 @@ export class RecordingDelegate implements CameraRecordingDelegate {
361390
cp: import('node:child_process').ChildProcess;
362391
}> {
363392
return new Promise((resolve, reject) => {
364-
const args: string[] = [...ffmpegInput]
393+
const args: string[] = ['-hide_banner', ...ffmpegInput]
365394

366395
// Add dummy audio for HKSV compatibility if needed
367396
if (this.videoConfig?.audio === false) {
368397
args.push(
369-
'-f', 'lavfi', '-i', 'anullsrc=cl=mono:r=16000',
370-
'-c:a', 'aac', '-profile:a', 'aac_low',
371-
'-ac', '1', '-ar', '16000', '-b:a', '32k', '-shortest'
398+
'-f', 'lavfi', '-i', 'anullsrc=cl=mono:r=32000',
372399
)
373400
}
374401

@@ -428,13 +455,25 @@ export class RecordingDelegate implements CameraRecordingDelegate {
428455
cp.on('spawn', () => {
429456
resolve({ generator: generator(), cp })
430457
})
431-
458+
432459
cp.on('error', reject)
433460

434461
cp.on('exit', (code, signal) => {
435462
if (code !== 0 && !processKilledIntentionally && code !== 255) {
436463
this.log.warn(`FFmpeg exited with code ${code}`, this.cameraName)
437464
}
465+
466+
// Enhanced process cleanup and error handling
467+
cp.on('exit', (code, signal) => {
468+
this.log.debug(`DEBUG: FFmpeg process ${cp.pid} exited with code ${code}, signal ${signal}`, this.cameraName)
469+
if (code !== 0 && code !== null) {
470+
this.log.warn(`HKSV: FFmpeg exited with non-zero code ${code}, this may indicate stream issues`, this.cameraName)
471+
}
472+
})
473+
474+
cp.on('error', (error) => {
475+
this.log.error(`DEBUG: FFmpeg process error: ${error}`, this.cameraName)
476+
})
438477
})
439478

440479
// Fast cleanup

src/streamingDelegate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export class StreamingDelegate implements CameraStreamingDelegate {
114114
],
115115
},
116116
},
117-
recording: /*! this.recording ? undefined : */ {
117+
recording: !this.recording ? undefined : {
118118
options: {
119119
prebufferLength: PREBUFFER_LENGTH,
120120
overrideEventTriggerOptions: [hap.EventTriggerOption.MOTION, hap.EventTriggerOption.DOORBELL],

0 commit comments

Comments
 (0)