@@ -165,6 +165,39 @@ export class RecordingDelegate implements CameraRecordingDelegate {
165
165
closeRecordingStream ( streamId : number , reason : HDSProtocolSpecificErrorReason | undefined ) : void {
166
166
this . log . info ( `Recording stream closed for stream ID: ${ streamId } , reason: ${ reason } ` , this . cameraName )
167
167
168
+ // Enhanced reason code diagnostics for HKSV debugging
169
+ switch ( reason ) {
170
+ case 0 :
171
+ this . log . info ( `✅ HKSV: Recording ended normally (reason 0)` , this . cameraName )
172
+ break
173
+ case 1 :
174
+ this . log . warn ( `⚠️ HKSV: Recording ended due to generic error (reason 1)` , this . cameraName )
175
+ break
176
+ case 2 :
177
+ this . log . warn ( `⚠️ HKSV: Recording ended due to network issues (reason 2)` , this . cameraName )
178
+ break
179
+ case 3 :
180
+ this . log . warn ( `⚠️ HKSV: Recording ended due to insufficient resources (reason 3)` , this . cameraName )
181
+ break
182
+ case 4 :
183
+ this . log . warn ( `⚠️ HKSV: Recording ended due to HomeKit busy (reason 4)` , this . cameraName )
184
+ break
185
+ case 5 :
186
+ this . log . warn ( `⚠️ HKSV: Recording ended due to insufficient buffer space (reason 5)` , this . cameraName )
187
+ break
188
+ case 6 :
189
+ this . log . warn ( `❌ HKSV: Recording ended due to STREAM FORMAT INCOMPATIBILITY (reason 6) - Check H.264 parameters!` , this . cameraName )
190
+ break
191
+ case 7 :
192
+ this . log . warn ( `⚠️ HKSV: Recording ended due to maximum recording time exceeded (reason 7)` , this . cameraName )
193
+ break
194
+ case 8 :
195
+ this . log . warn ( `⚠️ HKSV: Recording ended due to HomeKit storage full (reason 8)` , this . cameraName )
196
+ break
197
+ default :
198
+ this . log . warn ( `❓ HKSV: Unknown reason ${ reason } ` , this . cameraName )
199
+ }
200
+
168
201
// Abort the stream generator
169
202
const abortController = this . streamAbortControllers . get ( streamId )
170
203
if ( abortController ) {
@@ -262,7 +295,7 @@ export class RecordingDelegate implements CameraRecordingDelegate {
262
295
'1' ,
263
296
]
264
297
265
- // Universal encoding for HKSV compatibility - works with any input source
298
+ // Enhanced H.264 encoding for maximum HKSV compatibility
266
299
const videoArgs : Array < string > = [
267
300
// Only disable audio if explicitly disabled in config
268
301
...( this . videoConfig ?. audio === false ? [ '-an' ] : [ ] ) ,
@@ -277,23 +310,29 @@ export class RecordingDelegate implements CameraRecordingDelegate {
277
310
'-level:v' ,
278
311
'3.1' , // Force level 3.1 for HKSV compatibility
279
312
'-preset' ,
280
- 'ultrafast' ,
313
+ 'fast' , // Changed from ultrafast for better quality/compatibility balance
281
314
'-tune' ,
282
315
'zerolatency' ,
316
+ '-x264opts' ,
317
+ 'no-scenecut' , // Disable scene cut detection for consistent GOP
283
318
'-g' ,
284
- '60' ,
319
+ '30' , // Shorter GOP for better HKSV compatibility (was 60)
285
320
'-keyint_min' ,
286
- '60' ,
321
+ '30' , // Match GOP size
287
322
'-sc_threshold' ,
288
- '0' ,
323
+ '0' , // Disable scene change detection
289
324
'-force_key_frames' ,
290
- 'expr:gte(t,n_forced*4)' ,
325
+ 'expr:gte(t,n_forced*2)' , // Every 2 seconds instead of 4
326
+ '-refs' ,
327
+ '1' , // Use single reference frame for baseline
291
328
'-b:v' ,
292
- '800k' ,
329
+ '600k' , // Lower bitrate for better reliability (was 800k)
293
330
'-maxrate' ,
294
- '1000k' ,
331
+ '800k' , // Lower max rate (was 1000k)
295
332
'-bufsize' ,
296
- '1000k' ,
333
+ '600k' , // Match bitrate for consistent rate control
334
+ '-r' ,
335
+ '15' , // Fixed 15fps for more stable recording
297
336
]
298
337
299
338
const ffmpegInput : Array < string > = [ ]
@@ -337,6 +376,9 @@ export class RecordingDelegate implements CameraRecordingDelegate {
337
376
const { header, type, length, data } = box
338
377
339
378
pending . push ( header , data )
379
+
380
+ // Enhanced MP4 box logging for HKSV debugging
381
+ this . log . debug ( `📦 HKSV DEBUG: Received MP4 box type '${ type } ', length: ${ length } ` , this . cameraName )
340
382
341
383
// HKSV requires specific MP4 structure:
342
384
// 1. First packet: ftyp + moov (initialization data)
@@ -348,7 +390,7 @@ export class RecordingDelegate implements CameraRecordingDelegate {
348
390
filebuffer = Buffer . concat ( [ filebuffer , fragment ] )
349
391
pending = [ ]
350
392
isFirstFragment = false
351
- this . log . debug ( ` HKSV: Sending initialization segment (ftyp+moov), size: ${ fragment . length } `, this . cameraName )
393
+ this . log . info ( `🚀 HKSV: Sending initialization segment (ftyp+moov), size: ${ fragment . length } `, this . cameraName )
352
394
yield fragment
353
395
}
354
396
} else {
@@ -357,12 +399,10 @@ export class RecordingDelegate implements CameraRecordingDelegate {
357
399
const fragment = Buffer . concat ( pending )
358
400
filebuffer = Buffer . concat ( [ filebuffer , fragment ] )
359
401
pending = [ ]
360
- this . log . debug ( ` HKSV: Sending media fragment (moof+mdat), size: ${ fragment . length } `, this . cameraName )
402
+ this . log . info ( `📹 HKSV: Sending media fragment (moof+mdat), size: ${ fragment . length } `, this . cameraName )
361
403
yield fragment
362
404
}
363
405
}
364
-
365
- this . log . debug ( `mp4 box type ${ type } and length: ${ length } ` , this . cameraName )
366
406
}
367
407
} catch ( e ) {
368
408
this . log . info ( `Recording completed. ${ e } ` , this . cameraName )
0 commit comments