hap-nodejs 0.12.3-beta.11 → 0.12.3-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BridgedCore.js +14 -14
- package/dist/BridgedCore.js.map +1 -1
- package/dist/Core.js +14 -14
- package/dist/Core.js.map +1 -1
- package/dist/accessories/AirConditioner_accessory.js +24 -24
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +23 -23
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +292 -373
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +15 -21
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +12 -12
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +26 -26
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +45 -48
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +11 -11
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +8 -8
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +10 -10
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +11 -11
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +19 -19
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +17 -17
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +6 -6
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +3 -3
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +4 -4
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +36 -47
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.js +2 -2
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +780 -1093
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/AccessoryLoader.js +40 -40
- package/dist/lib/AccessoryLoader.js.map +1 -1
- package/dist/lib/Advertiser.js +392 -524
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.js +6 -10
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.js +1465 -501
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.js +215 -265
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.js +519 -322
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/Camera.js +14 -14
- package/dist/lib/camera/Camera.js.map +1 -1
- package/dist/lib/camera/RTPProxy.js +112 -104
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +284 -257
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +318 -381
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.js +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +198 -209
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.js +190 -249
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/DoorbellController.js +38 -39
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.js +343 -401
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.js +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +56 -57
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +259 -304
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +252 -269
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.js +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +2089 -2858
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +864 -1096
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +383 -679
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +29 -29
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.js +1 -1
- package/dist/lib/model/AccessoryInfo.js +101 -136
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.js +86 -89
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.js +15 -16
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.js +49 -49
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +40 -44
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +2 -1
- package/dist/lib/util/checkName.d.ts.map +1 -1
- package/dist/lib/util/checkName.js +7 -11
- package/dist/lib/util/checkName.js.map +1 -1
- package/dist/lib/util/clone.js +5 -27
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.js +8 -12
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.js +288 -384
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.js +31 -32
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.js +9 -12
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.js +32 -53
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.js +3 -8
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.js +8 -13
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.js +2 -3
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.js +5 -5
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.js +57 -76
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.js +15 -19
- package/dist/lib/util/uuid.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StreamController = exports.RTPStreamManagement = exports.StreamRequestTypes = exports.AudioStreamingSamplerate = exports.AudioStreamingCodecType = exports.SRTPCryptoSuites = exports.AudioSamplerate = exports.AudioBitrate = exports.VideoCodecPacketizationMode = exports.H264Level = exports.H264Profile = exports.VideoCodecType = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
+
const crypto_1 = tslib_1.__importDefault(require("crypto"));
|
|
7
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
8
|
+
const net_1 = tslib_1.__importDefault(require("net"));
|
|
9
|
+
const Characteristic_1 = require("../Characteristic");
|
|
10
|
+
const controller_1 = require("../controller");
|
|
11
|
+
const Service_1 = require("../Service");
|
|
12
|
+
const hapStatusError_1 = require("../util/hapStatusError");
|
|
13
|
+
const once_1 = require("../util/once");
|
|
14
|
+
const tlv = tslib_1.__importStar(require("../util/tlv"));
|
|
15
|
+
const uuid = tslib_1.__importStar(require("../util/uuid"));
|
|
16
16
|
// noinspection JSDeprecatedSymbols
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const Camera_1 = require("./Camera");
|
|
18
|
+
const RTPProxy_1 = tslib_1.__importDefault(require("./RTPProxy"));
|
|
19
|
+
const debug = (0, debug_1.default)("HAP-NodeJS:Camera:RTPStreamManagement");
|
|
20
20
|
// ---------------------------------- TLV DEFINITIONS START ----------------------------------
|
|
21
21
|
var StreamingStatusTypes;
|
|
22
22
|
(function (StreamingStatusTypes) {
|
|
@@ -283,16 +283,61 @@ var StreamRequestTypes;
|
|
|
283
283
|
/**
|
|
284
284
|
* @group Camera
|
|
285
285
|
*/
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
286
|
+
class RTPStreamManagement {
|
|
287
|
+
/**
|
|
288
|
+
* @deprecated Please use the SRTPCryptoSuites const enum above.
|
|
289
|
+
*/
|
|
290
|
+
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
291
|
+
static SRTPCryptoSuites = SRTPCryptoSuites;
|
|
292
|
+
/**
|
|
293
|
+
* @deprecated Please use the H264Profile const enum above.
|
|
294
|
+
*/
|
|
295
|
+
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
296
|
+
static VideoCodecParamProfileIDTypes = H264Profile;
|
|
297
|
+
/**
|
|
298
|
+
* @deprecated won't be updated anymore. Please use the H264Level const enum above.
|
|
299
|
+
*/
|
|
300
|
+
static VideoCodecParamLevelTypes = Object.freeze({ TYPE3_1: 0, TYPE3_2: 1, TYPE4_0: 2 });
|
|
301
|
+
id;
|
|
302
|
+
delegate;
|
|
303
|
+
service;
|
|
304
|
+
stateChangeDelegate;
|
|
305
|
+
requireProxy;
|
|
306
|
+
disableAudioProxy;
|
|
307
|
+
supportedCryptoSuites;
|
|
308
|
+
videoOnly = false;
|
|
309
|
+
supportedRTPConfiguration;
|
|
310
|
+
supportedVideoStreamConfiguration;
|
|
311
|
+
supportedAudioStreamConfiguration;
|
|
312
|
+
/**
|
|
313
|
+
* @deprecated
|
|
314
|
+
*/
|
|
315
|
+
connectionID;
|
|
316
|
+
activeConnection;
|
|
317
|
+
activeConnectionClosedListener;
|
|
318
|
+
sessionIdentifier = undefined;
|
|
319
|
+
/**
|
|
320
|
+
* @private private API
|
|
321
|
+
*/
|
|
322
|
+
streamStatus = 0 /* StreamingStatus.AVAILABLE */; // use _updateStreamStatus to update this property
|
|
323
|
+
ipVersion; // ip version for the current session
|
|
324
|
+
selectedConfiguration = ""; // base64 representation of the currently selected configuration
|
|
325
|
+
setupEndpointsResponse = ""; // response of the SetupEndpoints Characteristic
|
|
326
|
+
/**
|
|
327
|
+
* @private deprecated API
|
|
328
|
+
*/
|
|
329
|
+
audioProxy;
|
|
330
|
+
/**
|
|
331
|
+
* @private deprecated API
|
|
332
|
+
*/
|
|
333
|
+
videoProxy;
|
|
334
|
+
/**
|
|
335
|
+
* A RTPStreamManagement is considered disabled if `HomeKitCameraActive` is set to false.
|
|
336
|
+
* We use a closure based approach to retrieve the value of this characteristic.
|
|
337
|
+
* The characteristic is managed by the RecordingManagement.
|
|
338
|
+
*/
|
|
339
|
+
disabledThroughOperatingMode;
|
|
340
|
+
constructor(id, options, delegate, service, disabledThroughOperatingMode) {
|
|
296
341
|
this.id = id;
|
|
297
342
|
this.delegate = delegate;
|
|
298
343
|
this.requireProxy = options.proxy || false;
|
|
@@ -319,48 +364,47 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
319
364
|
this.resetSelectedStreamConfiguration();
|
|
320
365
|
this.disabledThroughOperatingMode = disabledThroughOperatingMode;
|
|
321
366
|
}
|
|
322
|
-
|
|
367
|
+
forceStop() {
|
|
323
368
|
this.handleSessionClosed();
|
|
324
|
-
}
|
|
325
|
-
|
|
369
|
+
}
|
|
370
|
+
getService() {
|
|
326
371
|
return this.service;
|
|
327
|
-
}
|
|
372
|
+
}
|
|
328
373
|
// noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols
|
|
329
374
|
/**
|
|
330
375
|
* @deprecated
|
|
331
376
|
*/
|
|
332
377
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
333
|
-
|
|
378
|
+
handleCloseConnection(connectionID) {
|
|
334
379
|
// This method is only here for legacy compatibility. It used to be called by legacy style CameraSource
|
|
335
380
|
// implementations to signal that the associated HAP connection was closed.
|
|
336
381
|
// This is now handled automatically. Thus, we don't need to do anything anymore.
|
|
337
|
-
}
|
|
338
|
-
|
|
382
|
+
}
|
|
383
|
+
handleFactoryReset() {
|
|
339
384
|
this.resetSelectedStreamConfiguration();
|
|
340
385
|
this.resetSetupEndpointsResponse();
|
|
341
386
|
this.service.updateCharacteristic(Characteristic_1.Characteristic.Active, true);
|
|
342
387
|
// on a factory reset the assumption is that all connections were already terminated and thus "handleStopStream" was already called
|
|
343
|
-
}
|
|
344
|
-
|
|
388
|
+
}
|
|
389
|
+
destroy() {
|
|
345
390
|
if (this.activeConnection) {
|
|
346
391
|
this._handleStopStream();
|
|
347
392
|
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
|
|
393
|
+
}
|
|
394
|
+
constructService(id) {
|
|
395
|
+
const managementService = new Service_1.Service.CameraRTPStreamManagement("", id.toString());
|
|
351
396
|
// this service is required only when recording is enabled. We don't really have access to this info here,
|
|
352
397
|
// so we just add the characteristic. Doesn't really hurt.
|
|
353
398
|
managementService.setCharacteristic(Characteristic_1.Characteristic.Active, true);
|
|
354
399
|
return managementService;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
var _this = this;
|
|
400
|
+
}
|
|
401
|
+
setupServiceHandlers() {
|
|
358
402
|
if (!this.service.testCharacteristic(Characteristic_1.Characteristic.Active)) {
|
|
359
403
|
// the active characteristic might not be present on some older configurations.
|
|
360
404
|
this.service.setCharacteristic(Characteristic_1.Characteristic.Active, true);
|
|
361
405
|
}
|
|
362
406
|
this.service.getCharacteristic(Characteristic_1.Characteristic.Active)
|
|
363
|
-
.on("change" /* CharacteristicEventTypes.CHANGE */,
|
|
407
|
+
.on("change" /* CharacteristicEventTypes.CHANGE */, () => this.stateChangeDelegate?.())
|
|
364
408
|
.setProps({ adminOnlyAccess: [1 /* Access.WRITE */] });
|
|
365
409
|
// ensure that configurations are up-to-date and reflected in the characteristic values
|
|
366
410
|
this.service.setCharacteristic(Characteristic_1.Characteristic.SupportedRTPConfiguration, this.supportedRTPConfiguration);
|
|
@@ -369,32 +413,32 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
369
413
|
this._updateStreamStatus(0 /* StreamingStatus.AVAILABLE */); // reset streaming status to available
|
|
370
414
|
this.service.setCharacteristic(Characteristic_1.Characteristic.SetupEndpoints, this.setupEndpointsResponse); // reset SetupEndpoints to default
|
|
371
415
|
this.service.getCharacteristic(Characteristic_1.Characteristic.SelectedRTPStreamConfiguration)
|
|
372
|
-
.on("get" /* CharacteristicEventTypes.GET */,
|
|
373
|
-
if (
|
|
416
|
+
.on("get" /* CharacteristicEventTypes.GET */, callback => {
|
|
417
|
+
if (this.streamingIsDisabled()) {
|
|
374
418
|
callback(null, tlv.encode(1 /* SelectedRTPStreamConfigurationTypes.SESSION_CONTROL */, tlv.encode(2 /* SessionControlTypes.COMMAND */, SessionControlCommand.SUSPEND_SESSION)).toString("base64"));
|
|
375
419
|
return;
|
|
376
420
|
}
|
|
377
|
-
callback(null,
|
|
421
|
+
callback(null, this.selectedConfiguration);
|
|
378
422
|
})
|
|
379
423
|
.on("set" /* CharacteristicEventTypes.SET */, this._handleSelectedStreamConfigurationWrite.bind(this));
|
|
380
424
|
this.service.getCharacteristic(Characteristic_1.Characteristic.SetupEndpoints)
|
|
381
|
-
.on("get" /* CharacteristicEventTypes.GET */,
|
|
382
|
-
if (
|
|
425
|
+
.on("get" /* CharacteristicEventTypes.GET */, callback => {
|
|
426
|
+
if (this.streamingIsDisabled()) {
|
|
383
427
|
callback(null, tlv.encode(2 /* SetupEndpointsResponseTypes.STATUS */, 2 /* SetupEndpointsStatus.ERROR */).toString("base64"));
|
|
384
428
|
return;
|
|
385
429
|
}
|
|
386
|
-
callback(null,
|
|
430
|
+
callback(null, this.setupEndpointsResponse);
|
|
387
431
|
})
|
|
388
|
-
.on("set" /* CharacteristicEventTypes.SET */,
|
|
432
|
+
.on("set" /* CharacteristicEventTypes.SET */, (value, callback, context, connection) => {
|
|
389
433
|
if (!connection) {
|
|
390
434
|
debug("Set event handler for SetupEndpoints cannot be called from plugin. Connection undefined!");
|
|
391
435
|
callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */);
|
|
392
436
|
return;
|
|
393
437
|
}
|
|
394
|
-
|
|
438
|
+
this.handleSetupEndpoints(value, callback, connection);
|
|
395
439
|
});
|
|
396
|
-
}
|
|
397
|
-
|
|
440
|
+
}
|
|
441
|
+
handleSessionClosed() {
|
|
398
442
|
this.resetSelectedStreamConfiguration();
|
|
399
443
|
this.resetSetupEndpointsResponse();
|
|
400
444
|
if (this.activeConnection) {
|
|
@@ -415,51 +459,49 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
415
459
|
this.audioProxy.destroy();
|
|
416
460
|
this.audioProxy = undefined;
|
|
417
461
|
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
var _a;
|
|
462
|
+
}
|
|
463
|
+
streamingIsDisabled(callback) {
|
|
421
464
|
if (!this.service.getCharacteristic(Characteristic_1.Characteristic.Active).value) {
|
|
422
465
|
callback && callback(new hapStatusError_1.HapStatusError(-70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */));
|
|
423
466
|
return true;
|
|
424
467
|
}
|
|
425
|
-
if (
|
|
468
|
+
if (this.disabledThroughOperatingMode?.()) {
|
|
426
469
|
callback && callback(new hapStatusError_1.HapStatusError(-70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */));
|
|
427
470
|
return true;
|
|
428
471
|
}
|
|
429
472
|
return false;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
var _this = this;
|
|
473
|
+
}
|
|
474
|
+
_handleSelectedStreamConfigurationWrite(value, callback) {
|
|
433
475
|
if (this.streamingIsDisabled(callback)) {
|
|
434
476
|
return;
|
|
435
477
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
478
|
+
const data = Buffer.from(value, "base64");
|
|
479
|
+
const objects = tlv.decode(data);
|
|
480
|
+
const sessionControl = tlv.decode(objects[1 /* SelectedRTPStreamConfigurationTypes.SESSION_CONTROL */]);
|
|
481
|
+
const sessionIdentifier = uuid.unparse(sessionControl[1 /* SessionControlTypes.SESSION_IDENTIFIER */]);
|
|
482
|
+
const requestType = sessionControl[2 /* SessionControlTypes.COMMAND */][0];
|
|
441
483
|
if (sessionIdentifier !== this.sessionIdentifier) {
|
|
442
|
-
debug(
|
|
484
|
+
debug(`Received unknown session Identifier with request to ${SessionControlCommand[requestType]}`);
|
|
443
485
|
callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */);
|
|
444
486
|
return;
|
|
445
487
|
}
|
|
446
488
|
this.selectedConfiguration = value;
|
|
447
489
|
// intercept the callback chain to check if an error occurred.
|
|
448
|
-
|
|
490
|
+
const streamCallback = (error, writeResponse) => {
|
|
449
491
|
callback(error, writeResponse); // does not support writeResponse, but how knows what comes in the future.
|
|
450
492
|
if (error) {
|
|
451
|
-
|
|
493
|
+
this.handleSessionClosed();
|
|
452
494
|
}
|
|
453
495
|
};
|
|
454
496
|
switch (requestType) {
|
|
455
497
|
case SessionControlCommand.START_SESSION: {
|
|
456
|
-
|
|
457
|
-
|
|
498
|
+
const selectedVideoParameters = tlv.decode(objects[2 /* SelectedRTPStreamConfigurationTypes.SELECTED_VIDEO_PARAMETERS */]);
|
|
499
|
+
const selectedAudioParameters = tlv.decode(objects[3 /* SelectedRTPStreamConfigurationTypes.SELECTED_AUDIO_PARAMETERS */]);
|
|
458
500
|
this._handleStartStream(selectedVideoParameters, selectedAudioParameters, streamCallback);
|
|
459
501
|
break;
|
|
460
502
|
}
|
|
461
503
|
case SessionControlCommand.RECONFIGURE_SESSION: {
|
|
462
|
-
|
|
504
|
+
const reconfiguredVideoParameters = tlv.decode(objects[2 /* SelectedRTPStreamConfigurationTypes.SELECTED_VIDEO_PARAMETERS */]);
|
|
463
505
|
this.handleReconfigureStream(reconfiguredVideoParameters, streamCallback);
|
|
464
506
|
break;
|
|
465
507
|
}
|
|
@@ -469,68 +511,68 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
469
511
|
case SessionControlCommand.RESUME_SESSION:
|
|
470
512
|
case SessionControlCommand.SUSPEND_SESSION:
|
|
471
513
|
default:
|
|
472
|
-
debug(
|
|
514
|
+
debug(`Unhandled request type ${SessionControlCommand[requestType]}`);
|
|
473
515
|
callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */);
|
|
474
516
|
return;
|
|
475
517
|
}
|
|
476
|
-
}
|
|
477
|
-
|
|
518
|
+
}
|
|
519
|
+
_handleStartStream(videoConfiguration, audioConfiguration, callback) {
|
|
478
520
|
// selected video configuration
|
|
479
521
|
// noinspection JSUnusedLocalSymbols
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
522
|
+
const videoCodec = videoConfiguration[1 /* SelectedVideoParametersTypes.CODEC_TYPE */]; // always 0x00 for h264
|
|
523
|
+
const videoParametersTLV = videoConfiguration[2 /* SelectedVideoParametersTypes.CODEC_PARAMETERS */];
|
|
524
|
+
const videoAttributesTLV = videoConfiguration[3 /* SelectedVideoParametersTypes.ATTRIBUTES */];
|
|
525
|
+
const videoRTPParametersTLV = videoConfiguration[4 /* SelectedVideoParametersTypes.RTP_PARAMETERS */];
|
|
484
526
|
// video parameters
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
527
|
+
const videoParameters = tlv.decode(videoParametersTLV);
|
|
528
|
+
const h264Profile = videoParameters[1 /* VideoCodecParametersTypes.PROFILE_ID */][0];
|
|
529
|
+
const h264Level = videoParameters[2 /* VideoCodecParametersTypes.LEVEL */][0];
|
|
530
|
+
const packetizationMode = videoParameters[3 /* VideoCodecParametersTypes.PACKETIZATION_MODE */][0];
|
|
531
|
+
const cvoEnabled = videoParameters[4 /* VideoCodecParametersTypes.CVO_ENABLED */];
|
|
532
|
+
let cvoId = undefined;
|
|
491
533
|
if (cvoEnabled && cvoEnabled[0] === 1 /* VideoCodecCVO.SUPPORTED */) {
|
|
492
534
|
cvoId = videoParameters[5 /* VideoCodecParametersTypes.CVO_ID */].readUInt8(0);
|
|
493
535
|
}
|
|
494
536
|
// video attributes
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
537
|
+
const videoAttributes = tlv.decode(videoAttributesTLV);
|
|
538
|
+
const width = videoAttributes[1 /* VideoAttributesTypes.IMAGE_WIDTH */].readUInt16LE(0);
|
|
539
|
+
const height = videoAttributes[2 /* VideoAttributesTypes.IMAGE_HEIGHT */].readUInt16LE(0);
|
|
540
|
+
const frameRate = videoAttributes[3 /* VideoAttributesTypes.FRAME_RATE */].readUInt8(0);
|
|
499
541
|
// video rtp parameters
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
542
|
+
const videoRTPParameters = tlv.decode(videoRTPParametersTLV);
|
|
543
|
+
const videoPayloadType = videoRTPParameters[1 /* VideoRTPParametersTypes.PAYLOAD_TYPE */].readUInt8(0); // 99
|
|
544
|
+
const videoSSRC = videoRTPParameters[2 /* VideoRTPParametersTypes.SYNCHRONIZATION_SOURCE */].readUInt32LE(0);
|
|
545
|
+
const videoMaximumBitrate = videoRTPParameters[3 /* VideoRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0);
|
|
546
|
+
const videoRTCPInterval = videoRTPParameters[4 /* VideoRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0);
|
|
547
|
+
let maxMTU = this.ipVersion === "ipv6" ? 1228 : 1378; // default values ipv4: 1378 bytes; ipv6: 1228 bytes
|
|
506
548
|
if (videoRTPParameters[5 /* VideoRTPParametersTypes.MAX_MTU */]) {
|
|
507
549
|
maxMTU = videoRTPParameters[5 /* VideoRTPParametersTypes.MAX_MTU */].readUInt16LE(0);
|
|
508
550
|
}
|
|
509
551
|
// selected audio configuration
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
552
|
+
const audioCodec = audioConfiguration[1 /* SelectedAudioParametersTypes.CODEC_TYPE */][0];
|
|
553
|
+
const audioParametersTLV = audioConfiguration[2 /* SelectedAudioParametersTypes.CODEC_PARAMETERS */];
|
|
554
|
+
const audioRTPParametersTLV = audioConfiguration[3 /* SelectedAudioParametersTypes.RTP_PARAMETERS */];
|
|
555
|
+
const comfortNoise = !!audioConfiguration[4 /* SelectedAudioParametersTypes.COMFORT_NOISE */].readUInt8(0);
|
|
514
556
|
// audio parameters
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
557
|
+
const audioParameters = tlv.decode(audioParametersTLV);
|
|
558
|
+
const channels = audioParameters[1 /* AudioCodecParametersTypes.CHANNEL */][0];
|
|
559
|
+
const audioBitrate = audioParameters[2 /* AudioCodecParametersTypes.BIT_RATE */][0];
|
|
560
|
+
const samplerate = audioParameters[3 /* AudioCodecParametersTypes.SAMPLE_RATE */][0];
|
|
561
|
+
const rtpPacketTime = audioParameters[4 /* AudioCodecParametersTypes.PACKET_TIME */].readUInt8(0);
|
|
520
562
|
// audio rtp parameters
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
563
|
+
const audioRTPParameters = tlv.decode(audioRTPParametersTLV);
|
|
564
|
+
const audioPayloadType = audioRTPParameters[1 /* AudioRTPParametersTypes.PAYLOAD_TYPE */].readUInt8(0); // 110
|
|
565
|
+
const audioSSRC = audioRTPParameters[2 /* AudioRTPParametersTypes.SYNCHRONIZATION_SOURCE */].readUInt32LE(0);
|
|
566
|
+
const audioMaximumBitrate = audioRTPParameters[3 /* AudioRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0);
|
|
567
|
+
const audioRTCPInterval = audioRTPParameters[4 /* AudioRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0);
|
|
568
|
+
const comfortNoisePayloadType = audioRTPParameters[6 /* AudioRTPParametersTypes.COMFORT_NOISE_PAYLOAD_TYPE */].readUInt8(0); // 13
|
|
527
569
|
if (this.requireProxy) {
|
|
528
570
|
this.videoProxy.setOutgoingPayloadType(videoPayloadType);
|
|
529
571
|
if (!this.disableAudioProxy) {
|
|
530
572
|
this.audioProxy.setOutgoingPayloadType(audioPayloadType);
|
|
531
573
|
}
|
|
532
574
|
}
|
|
533
|
-
|
|
575
|
+
const videoInfo = {
|
|
534
576
|
codec: videoCodec.readUInt8(0),
|
|
535
577
|
profile: h264Profile,
|
|
536
578
|
level: h264Level,
|
|
@@ -545,8 +587,8 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
545
587
|
rtcp_interval: videoRTCPInterval,
|
|
546
588
|
mtu: maxMTU,
|
|
547
589
|
};
|
|
548
|
-
|
|
549
|
-
|
|
590
|
+
let audioCodecName;
|
|
591
|
+
let samplerateNum;
|
|
550
592
|
switch (audioCodec) {
|
|
551
593
|
case 0 /* AudioCodecTypes.PCMU */:
|
|
552
594
|
audioCodecName = "PCMU" /* AudioStreamingCodecType.PCMU */;
|
|
@@ -570,7 +612,7 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
570
612
|
audioCodecName = "AMR-WB" /* AudioStreamingCodecType.AMR_WB */;
|
|
571
613
|
break;
|
|
572
614
|
default:
|
|
573
|
-
throw new Error(
|
|
615
|
+
throw new Error(`Encountered unknown selected audio codec ${audioCodec}`);
|
|
574
616
|
}
|
|
575
617
|
switch (samplerate) {
|
|
576
618
|
case 0 /* AudioSamplerate.KHZ_8 */:
|
|
@@ -583,9 +625,9 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
583
625
|
samplerateNum = 24;
|
|
584
626
|
break;
|
|
585
627
|
default:
|
|
586
|
-
throw new Error(
|
|
628
|
+
throw new Error(`Encountered unknown selected audio samplerate ${samplerate}`);
|
|
587
629
|
}
|
|
588
|
-
|
|
630
|
+
const audioInfo = {
|
|
589
631
|
codec: audioCodecName,
|
|
590
632
|
channel: channels,
|
|
591
633
|
bit_rate: audioBitrate,
|
|
@@ -598,58 +640,57 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
598
640
|
comfort_pt: comfortNoisePayloadType,
|
|
599
641
|
comfortNoiseEnabled: comfortNoise,
|
|
600
642
|
};
|
|
601
|
-
|
|
643
|
+
const request = {
|
|
602
644
|
sessionID: this.sessionIdentifier,
|
|
603
645
|
type: "start" /* StreamRequestTypes.START */,
|
|
604
646
|
video: videoInfo,
|
|
605
647
|
audio: audioInfo,
|
|
606
648
|
};
|
|
607
|
-
this.delegate.handleStreamRequest(request,
|
|
608
|
-
}
|
|
609
|
-
|
|
649
|
+
this.delegate.handleStreamRequest(request, error => callback(error));
|
|
650
|
+
}
|
|
651
|
+
handleReconfigureStream(videoConfiguration, callback) {
|
|
610
652
|
// selected video configuration
|
|
611
|
-
|
|
612
|
-
|
|
653
|
+
const videoAttributesTLV = videoConfiguration[3 /* SelectedVideoParametersTypes.ATTRIBUTES */];
|
|
654
|
+
const videoRTPParametersTLV = videoConfiguration[4 /* SelectedVideoParametersTypes.RTP_PARAMETERS */];
|
|
613
655
|
// video attributes
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
656
|
+
const videoAttributes = tlv.decode(videoAttributesTLV);
|
|
657
|
+
const width = videoAttributes[1 /* VideoAttributesTypes.IMAGE_WIDTH */].readUInt16LE(0);
|
|
658
|
+
const height = videoAttributes[2 /* VideoAttributesTypes.IMAGE_HEIGHT */].readUInt16LE(0);
|
|
659
|
+
const frameRate = videoAttributes[3 /* VideoAttributesTypes.FRAME_RATE */].readUInt8(0);
|
|
618
660
|
// video rtp parameters
|
|
619
|
-
|
|
620
|
-
|
|
661
|
+
const videoRTPParameters = tlv.decode(videoRTPParametersTLV);
|
|
662
|
+
const videoMaximumBitrate = videoRTPParameters[3 /* VideoRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0);
|
|
621
663
|
// seems to be always zero, use default of 0.5
|
|
622
|
-
|
|
623
|
-
|
|
664
|
+
const videoRTCPInterval = videoRTPParameters[4 /* VideoRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0) || 0.5;
|
|
665
|
+
const reconfiguredVideoInfo = {
|
|
624
666
|
width: width,
|
|
625
667
|
height: height,
|
|
626
668
|
fps: frameRate,
|
|
627
669
|
max_bit_rate: videoMaximumBitrate,
|
|
628
670
|
rtcp_interval: videoRTCPInterval,
|
|
629
671
|
};
|
|
630
|
-
|
|
672
|
+
const request = {
|
|
631
673
|
sessionID: this.sessionIdentifier,
|
|
632
674
|
type: "reconfigure" /* StreamRequestTypes.RECONFIGURE */,
|
|
633
675
|
video: reconfiguredVideoInfo,
|
|
634
676
|
};
|
|
635
|
-
this.delegate.handleStreamRequest(request,
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
|
|
677
|
+
this.delegate.handleStreamRequest(request, error => callback(error));
|
|
678
|
+
}
|
|
679
|
+
_handleStopStream(callback) {
|
|
680
|
+
const request = {
|
|
639
681
|
sessionID: this.sessionIdentifier, // save sessionIdentifier before handleSessionClosed is called
|
|
640
682
|
type: "stop" /* StreamRequestTypes.STOP */,
|
|
641
683
|
};
|
|
642
684
|
this.handleSessionClosed();
|
|
643
|
-
this.delegate.handleStreamRequest(request,
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
var _this = this;
|
|
685
|
+
this.delegate.handleStreamRequest(request, error => callback ? callback(error) : undefined);
|
|
686
|
+
}
|
|
687
|
+
handleSetupEndpoints(value, callback, connection) {
|
|
647
688
|
if (this.streamingIsDisabled(callback)) {
|
|
648
689
|
return;
|
|
649
690
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
691
|
+
const data = Buffer.from(value, "base64");
|
|
692
|
+
const objects = tlv.decode(data);
|
|
693
|
+
const sessionIdentifier = uuid.unparse(objects[1 /* SetupEndpointsTypes.SESSION_ID */]);
|
|
653
694
|
if (this.streamStatus !== 0 /* StreamingStatus.AVAILABLE */) {
|
|
654
695
|
this.setupEndpointsResponse = tlv.encode(1 /* SetupEndpointsResponseTypes.SESSION_ID */, uuid.write(sessionIdentifier), 2 /* SetupEndpointsResponseTypes.STATUS */, 1 /* SetupEndpointsStatus.BUSY */).toString("base64");
|
|
655
696
|
callback();
|
|
@@ -664,26 +705,26 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
664
705
|
this.sessionIdentifier = sessionIdentifier;
|
|
665
706
|
this._updateStreamStatus(1 /* StreamingStatus.IN_USE */);
|
|
666
707
|
// Address
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
708
|
+
const targetAddressPayload = objects[3 /* SetupEndpointsTypes.CONTROLLER_ADDRESS */];
|
|
709
|
+
const processedAddressInfo = tlv.decode(targetAddressPayload);
|
|
710
|
+
const addressVersion = processedAddressInfo[1 /* AddressTypes.ADDRESS_VERSION */][0];
|
|
711
|
+
const controllerAddress = processedAddressInfo[2 /* AddressTypes.ADDRESS */].toString("utf8");
|
|
712
|
+
const targetVideoPort = processedAddressInfo[3 /* AddressTypes.VIDEO_RTP_PORT */].readUInt16LE(0);
|
|
713
|
+
const targetAudioPort = processedAddressInfo[4 /* AddressTypes.AUDIO_RTP_PORT */].readUInt16LE(0);
|
|
673
714
|
// Video SRTP Params
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
715
|
+
const videoSRTPPayload = objects[4 /* SetupEndpointsTypes.VIDEO_SRTP_PARAMETERS */];
|
|
716
|
+
const processedVideoInfo = tlv.decode(videoSRTPPayload);
|
|
717
|
+
const videoCryptoSuite = processedVideoInfo[1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */][0];
|
|
718
|
+
const videoMasterKey = processedVideoInfo[2 /* SRTPParametersTypes.MASTER_KEY */];
|
|
719
|
+
const videoMasterSalt = processedVideoInfo[3 /* SRTPParametersTypes.MASTER_SALT */];
|
|
679
720
|
// Audio SRTP Params
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
721
|
+
const audioSRTPPayload = objects[5 /* SetupEndpointsTypes.AUDIO_SRTP_PARAMETERS */];
|
|
722
|
+
const processedAudioInfo = tlv.decode(audioSRTPPayload);
|
|
723
|
+
const audioCryptoSuite = processedAudioInfo[1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */][0];
|
|
724
|
+
const audioMasterKey = processedAudioInfo[2 /* SRTPParametersTypes.MASTER_KEY */];
|
|
725
|
+
const audioMasterSalt = processedAudioInfo[3 /* SRTPParametersTypes.MASTER_SALT */];
|
|
685
726
|
debug("Session: ", sessionIdentifier, "\nControllerAddress: ", controllerAddress, "\nVideoPort: ", targetVideoPort, "\nAudioPort: ", targetAudioPort, "\nVideo Crypto: ", videoCryptoSuite, "\nVideo Master Key: ", videoMasterKey, "\nVideo Master Salt: ", videoMasterSalt, "\nAudio Crypto: ", audioCryptoSuite, "\nAudio Master Key: ", audioMasterKey, "\nAudio Master Salt: ", audioMasterSalt);
|
|
686
|
-
|
|
727
|
+
const prepareRequest = {
|
|
687
728
|
sessionID: sessionIdentifier,
|
|
688
729
|
sourceAddress: connection.localAddress,
|
|
689
730
|
targetAddress: controllerAddress,
|
|
@@ -701,7 +742,7 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
701
742
|
srtp_salt: audioMasterSalt,
|
|
702
743
|
},
|
|
703
744
|
};
|
|
704
|
-
|
|
745
|
+
const promises = [];
|
|
705
746
|
if (this.requireProxy) {
|
|
706
747
|
prepareRequest.targetAddress = connection.getLocalAddress(addressVersion === 1 /* IPAddressVersion.IPV6 */ ? "ipv6" : "ipv4"); // ip versions must be the same
|
|
707
748
|
this.videoProxy = new RTPProxy_1.default({
|
|
@@ -710,9 +751,9 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
710
751
|
outgoingSSRC: crypto_1.default.randomBytes(4).readUInt32LE(0), // videoSSRC
|
|
711
752
|
disabled: false,
|
|
712
753
|
});
|
|
713
|
-
promises.push(this.videoProxy.setup().then(
|
|
714
|
-
prepareRequest.video.proxy_rtp =
|
|
715
|
-
prepareRequest.video.proxy_rtcp =
|
|
754
|
+
promises.push(this.videoProxy.setup().then(() => {
|
|
755
|
+
prepareRequest.video.proxy_rtp = this.videoProxy.incomingRTPPort();
|
|
756
|
+
prepareRequest.video.proxy_rtcp = this.videoProxy.incomingRTCPPort();
|
|
716
757
|
}));
|
|
717
758
|
if (!this.disableAudioProxy) {
|
|
718
759
|
this.audioProxy = new RTPProxy_1.default({
|
|
@@ -721,52 +762,52 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
721
762
|
outgoingSSRC: crypto_1.default.randomBytes(4).readUInt32LE(0), // audioSSRC
|
|
722
763
|
disabled: this.videoOnly,
|
|
723
764
|
});
|
|
724
|
-
promises.push(this.audioProxy.setup().then(
|
|
725
|
-
prepareRequest.audio.proxy_rtp =
|
|
726
|
-
prepareRequest.audio.proxy_rtcp =
|
|
765
|
+
promises.push(this.audioProxy.setup().then(() => {
|
|
766
|
+
prepareRequest.audio.proxy_rtp = this.audioProxy.incomingRTPPort();
|
|
767
|
+
prepareRequest.audio.proxy_rtcp = this.audioProxy.incomingRTCPPort();
|
|
727
768
|
}));
|
|
728
769
|
}
|
|
729
770
|
}
|
|
730
|
-
Promise.all(promises).then(
|
|
731
|
-
|
|
771
|
+
Promise.all(promises).then(() => {
|
|
772
|
+
this.delegate.prepareStream(prepareRequest, (0, once_1.once)((error, response) => {
|
|
732
773
|
if (error || !response) {
|
|
733
|
-
debug(
|
|
734
|
-
|
|
735
|
-
|
|
774
|
+
debug(`PrepareStream request encountered an error: ${error ? error.message : undefined}`);
|
|
775
|
+
this.setupEndpointsResponse = tlv.encode(1 /* SetupEndpointsResponseTypes.SESSION_ID */, uuid.write(sessionIdentifier), 2 /* SetupEndpointsResponseTypes.STATUS */, 2 /* SetupEndpointsStatus.ERROR */).toString("base64");
|
|
776
|
+
this.handleSessionClosed();
|
|
736
777
|
callback(error);
|
|
737
778
|
}
|
|
738
779
|
else {
|
|
739
|
-
|
|
780
|
+
this.generateSetupEndpointResponse(connection, sessionIdentifier, prepareRequest, response, callback);
|
|
740
781
|
}
|
|
741
782
|
}));
|
|
742
783
|
});
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
784
|
+
}
|
|
785
|
+
generateSetupEndpointResponse(connection, identifier, request, response, callback) {
|
|
786
|
+
let address;
|
|
787
|
+
let addressVersion = request.addressVersion;
|
|
788
|
+
let videoPort;
|
|
789
|
+
let audioPort;
|
|
790
|
+
let videoCryptoSuite;
|
|
791
|
+
let videoSRTPKey;
|
|
792
|
+
let videoSRTPSalt;
|
|
793
|
+
let audioCryptoSuite;
|
|
794
|
+
let audioSRTPKey;
|
|
795
|
+
let audioSRTPSalt;
|
|
796
|
+
let videoSSRC;
|
|
797
|
+
let audioSSRC;
|
|
757
798
|
if (!this.videoOnly && !response.audio) {
|
|
758
799
|
throw new Error("Audio was enabled but not supplied in PrepareStreamResponse!");
|
|
759
800
|
}
|
|
760
801
|
// Provide default values if audio was not supplied
|
|
761
|
-
|
|
802
|
+
const audio = response.audio || {
|
|
762
803
|
port: request.audio.port,
|
|
763
804
|
ssrc: controller_1.CameraController.generateSynchronisationSource(),
|
|
764
805
|
srtp_key: request.audio.srtp_key,
|
|
765
806
|
srtp_salt: request.audio.srtp_salt,
|
|
766
807
|
};
|
|
767
808
|
if (!this.requireProxy) {
|
|
768
|
-
|
|
769
|
-
|
|
809
|
+
const videoInfo = response.video;
|
|
810
|
+
const audioInfo = audio;
|
|
770
811
|
if (response.addressOverride) {
|
|
771
812
|
addressVersion = net_1.default.isIPv4(response.addressOverride) ? "ipv4" : "ipv6";
|
|
772
813
|
address = response.addressOverride;
|
|
@@ -775,7 +816,7 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
775
816
|
address = connection.getLocalAddress(addressVersion);
|
|
776
817
|
}
|
|
777
818
|
if (request.addressVersion !== addressVersion) {
|
|
778
|
-
throw new Error(
|
|
819
|
+
throw new Error(`Incoming and outgoing ip address versions must match! Expected ${request.addressVersion} but got ${addressVersion}`);
|
|
779
820
|
}
|
|
780
821
|
videoPort = videoInfo.port;
|
|
781
822
|
audioPort = audioInfo.port;
|
|
@@ -797,7 +838,7 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
797
838
|
audioSSRC = audioInfo.ssrc;
|
|
798
839
|
}
|
|
799
840
|
else {
|
|
800
|
-
|
|
841
|
+
const videoInfo = response.video;
|
|
801
842
|
address = connection.getLocalAddress(request.addressVersion);
|
|
802
843
|
videoCryptoSuite = 2 /* SRTPCryptoSuites.NONE */;
|
|
803
844
|
videoSRTPKey = Buffer.alloc(0);
|
|
@@ -812,7 +853,7 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
812
853
|
videoPort = this.videoProxy.outgoingLocalPort();
|
|
813
854
|
videoSSRC = this.videoProxy.outgoingSSRC;
|
|
814
855
|
if (!this.disableAudioProxy) {
|
|
815
|
-
|
|
856
|
+
const audioInfo = response.audio;
|
|
816
857
|
this.audioProxy.setIncomingPayloadType(audioInfo.proxy_pt);
|
|
817
858
|
this.audioProxy.setServerAddress(audioInfo.proxy_server_address);
|
|
818
859
|
this.audioProxy.setServerRTPPort(audioInfo.proxy_server_rtp);
|
|
@@ -821,66 +862,66 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
821
862
|
audioSSRC = this.audioProxy.outgoingSSRC;
|
|
822
863
|
}
|
|
823
864
|
else {
|
|
824
|
-
|
|
865
|
+
const audioInfo = response.audio;
|
|
825
866
|
audioPort = audioInfo.port;
|
|
826
867
|
audioSSRC = audioInfo.ssrc;
|
|
827
868
|
}
|
|
828
869
|
}
|
|
829
870
|
this.ipVersion = addressVersion; // we need to save this in order to calculate some default mtu values later
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
871
|
+
const accessoryAddress = tlv.encode(1 /* AddressTypes.ADDRESS_VERSION */, addressVersion === "ipv4" ? 0 /* IPAddressVersion.IPV4 */ : 1 /* IPAddressVersion.IPV6 */, 2 /* AddressTypes.ADDRESS */, address, 3 /* AddressTypes.VIDEO_RTP_PORT */, tlv.writeUInt16(videoPort), 4 /* AddressTypes.AUDIO_RTP_PORT */, tlv.writeUInt16(audioPort));
|
|
872
|
+
const videoSRTPParameters = tlv.encode(1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */, videoCryptoSuite, 2 /* SRTPParametersTypes.MASTER_KEY */, videoSRTPKey, 3 /* SRTPParametersTypes.MASTER_SALT */, videoSRTPSalt);
|
|
873
|
+
const audioSRTPParameters = tlv.encode(1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */, audioCryptoSuite, 2 /* SRTPParametersTypes.MASTER_KEY */, audioSRTPKey, 3 /* SRTPParametersTypes.MASTER_SALT */, audioSRTPSalt);
|
|
833
874
|
this.setupEndpointsResponse = tlv.encode(1 /* SetupEndpointsResponseTypes.SESSION_ID */, uuid.write(identifier), 2 /* SetupEndpointsResponseTypes.STATUS */, 0 /* SetupEndpointsStatus.SUCCESS */, 3 /* SetupEndpointsResponseTypes.ACCESSORY_ADDRESS */, accessoryAddress, 4 /* SetupEndpointsResponseTypes.VIDEO_SRTP_PARAMETERS */, videoSRTPParameters, 5 /* SetupEndpointsResponseTypes.AUDIO_SRTP_PARAMETERS */, audioSRTPParameters, 6 /* SetupEndpointsResponseTypes.VIDEO_SSRC */, tlv.writeUInt32(videoSSRC), 7 /* SetupEndpointsResponseTypes.AUDIO_SSRC */, tlv.writeUInt32(audioSSRC)).toString("base64");
|
|
834
875
|
callback();
|
|
835
|
-
}
|
|
836
|
-
|
|
876
|
+
}
|
|
877
|
+
_updateStreamStatus(status) {
|
|
837
878
|
this.streamStatus = status;
|
|
838
879
|
this.service.updateCharacteristic(Characteristic_1.Characteristic.StreamingStatus, tlv.encode(1 /* StreamingStatusTypes.STATUS */, this.streamStatus).toString("base64"));
|
|
839
|
-
}
|
|
840
|
-
|
|
880
|
+
}
|
|
881
|
+
static _supportedRTPConfiguration(supportedCryptoSuites) {
|
|
841
882
|
if (supportedCryptoSuites.length === 1 && supportedCryptoSuites[0] === 2 /* SRTPCryptoSuites.NONE */) {
|
|
842
883
|
debug("Client claims it doesn't support SRTP. The stream may stops working with future iOS releases.");
|
|
843
884
|
}
|
|
844
885
|
return tlv.encode(2 /* SupportedRTPConfigurationTypes.SRTP_CRYPTO_SUITE */, supportedCryptoSuites).toString("base64");
|
|
845
|
-
}
|
|
846
|
-
|
|
886
|
+
}
|
|
887
|
+
static _supportedVideoStreamConfiguration(videoOptions) {
|
|
847
888
|
if (!videoOptions.codec) {
|
|
848
889
|
throw new Error("Video codec cannot be undefined");
|
|
849
890
|
}
|
|
850
891
|
if (!videoOptions.resolutions) {
|
|
851
892
|
throw new Error("Video resolutions cannot be undefined");
|
|
852
893
|
}
|
|
853
|
-
|
|
894
|
+
let codecParameters = tlv.encode(1 /* VideoCodecParametersTypes.PROFILE_ID */, videoOptions.codec.profiles, 2 /* VideoCodecParametersTypes.LEVEL */, videoOptions.codec.levels, 3 /* VideoCodecParametersTypes.PACKETIZATION_MODE */, 0 /* VideoCodecPacketizationMode.NON_INTERLEAVED */);
|
|
854
895
|
if (videoOptions.cvoId != null) {
|
|
855
896
|
codecParameters = Buffer.concat([
|
|
856
897
|
codecParameters,
|
|
857
898
|
tlv.encode(4 /* VideoCodecParametersTypes.CVO_ENABLED */, 1 /* VideoCodecCVO.SUPPORTED */, 5 /* VideoCodecParametersTypes.CVO_ID */, videoOptions.cvoId),
|
|
858
899
|
]);
|
|
859
900
|
}
|
|
860
|
-
|
|
901
|
+
const videoStreamConfiguration = tlv.encode(1 /* VideoCodecConfigurationTypes.CODEC_TYPE */, 0 /* VideoCodecType.H264 */, 2 /* VideoCodecConfigurationTypes.CODEC_PARAMETERS */, codecParameters, 3 /* VideoCodecConfigurationTypes.ATTRIBUTES */, videoOptions.resolutions.map(resolution => {
|
|
861
902
|
if (resolution.length !== 3) {
|
|
862
903
|
throw new Error("Unexpected video resolution");
|
|
863
904
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
905
|
+
const width = Buffer.alloc(2);
|
|
906
|
+
const height = Buffer.alloc(2);
|
|
907
|
+
const frameRate = Buffer.alloc(1);
|
|
867
908
|
width.writeUInt16LE(resolution[0], 0);
|
|
868
909
|
height.writeUInt16LE(resolution[1], 0);
|
|
869
910
|
frameRate.writeUInt8(resolution[2], 0);
|
|
870
911
|
return tlv.encode(1 /* VideoAttributesTypes.IMAGE_WIDTH */, width, 2 /* VideoAttributesTypes.IMAGE_HEIGHT */, height, 3 /* VideoAttributesTypes.FRAME_RATE */, frameRate);
|
|
871
912
|
}));
|
|
872
913
|
return tlv.encode(1 /* SupportedVideoStreamConfigurationTypes.VIDEO_CODEC_CONFIGURATION */, videoStreamConfiguration).toString("base64");
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
codecs.slice().forEach(
|
|
877
|
-
|
|
914
|
+
}
|
|
915
|
+
checkForLegacyAudioCodecRepresentation(codecs) {
|
|
916
|
+
const codecMap = {};
|
|
917
|
+
codecs.slice().forEach(codec => {
|
|
918
|
+
const previous = codecMap[codec.type];
|
|
878
919
|
if (previous) {
|
|
879
920
|
if (typeof previous.samplerate === "number") {
|
|
880
921
|
previous.samplerate = [previous.samplerate];
|
|
881
922
|
}
|
|
882
923
|
previous.samplerate = previous.samplerate.concat(codec.samplerate);
|
|
883
|
-
|
|
924
|
+
const index = codecs.indexOf(codec);
|
|
884
925
|
if (index >= 0) {
|
|
885
926
|
codecs.splice(index, 1);
|
|
886
927
|
}
|
|
@@ -889,12 +930,12 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
889
930
|
codecMap[codec.type] = codec;
|
|
890
931
|
}
|
|
891
932
|
});
|
|
892
|
-
}
|
|
893
|
-
|
|
933
|
+
}
|
|
934
|
+
_supportedAudioStreamConfiguration(audioOptions) {
|
|
894
935
|
// Only AAC-ELD and OPUS are accepted by iOS currently, and we need to give it something it will accept
|
|
895
936
|
// for it to start the video stream.
|
|
896
|
-
|
|
897
|
-
|
|
937
|
+
const comfortNoise = audioOptions && !!audioOptions.comfort_noise;
|
|
938
|
+
const supportedCodecs = (audioOptions && audioOptions.codecs) || [];
|
|
898
939
|
this.checkForLegacyAudioCodecRepresentation(supportedCodecs);
|
|
899
940
|
if (supportedCodecs.length === 0) { // Fake a Codec if we haven't got anything
|
|
900
941
|
debug("Client doesn't support any audio codec that HomeKit supports.");
|
|
@@ -904,8 +945,8 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
904
945
|
samplerate: [16 /* AudioStreamingSamplerate.KHZ_16 */, 24 /* AudioStreamingSamplerate.KHZ_24 */], // 16 and 24 must be supported
|
|
905
946
|
});
|
|
906
947
|
}
|
|
907
|
-
|
|
908
|
-
|
|
948
|
+
const codecConfigurations = supportedCodecs.map(codec => {
|
|
949
|
+
let type;
|
|
909
950
|
switch (codec.type) {
|
|
910
951
|
case "OPUS" /* AudioStreamingCodecType.OPUS */:
|
|
911
952
|
type = 3 /* AudioCodecTypes.OPUS */;
|
|
@@ -931,8 +972,8 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
931
972
|
default:
|
|
932
973
|
throw new Error("Unsupported codec: " + codec.type);
|
|
933
974
|
}
|
|
934
|
-
|
|
935
|
-
|
|
975
|
+
const providedSamplerates = (typeof codec.samplerate === "number" ? [codec.samplerate] : codec.samplerate).map(rate => {
|
|
976
|
+
let samplerate;
|
|
936
977
|
switch (rate) {
|
|
937
978
|
case 8 /* AudioStreamingSamplerate.KHZ_8 */:
|
|
938
979
|
samplerate = 0 /* AudioSamplerate.KHZ_8 */;
|
|
@@ -948,28 +989,28 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
948
989
|
samplerate = -1;
|
|
949
990
|
}
|
|
950
991
|
return samplerate;
|
|
951
|
-
}).filter(
|
|
992
|
+
}).filter(rate => rate !== -1);
|
|
952
993
|
if (providedSamplerates.length === 0) {
|
|
953
994
|
throw new Error("Audio samplerate cannot be empty!");
|
|
954
995
|
}
|
|
955
|
-
|
|
996
|
+
const audioParameters = tlv.encode(1 /* AudioCodecParametersTypes.CHANNEL */, Math.max(1, codec.audioChannels || 1), 2 /* AudioCodecParametersTypes.BIT_RATE */, codec.bitrate || 0 /* AudioBitrate.VARIABLE */, 3 /* AudioCodecParametersTypes.SAMPLE_RATE */, providedSamplerates);
|
|
956
997
|
return tlv.encode(1 /* AudioCodecConfigurationTypes.CODEC_TYPE */, type, 2 /* AudioCodecConfigurationTypes.CODEC_PARAMETERS */, audioParameters);
|
|
957
998
|
});
|
|
958
999
|
return tlv.encode(1 /* SupportedAudioStreamConfigurationTypes.AUDIO_CODEC_CONFIGURATION */, codecConfigurations, 2 /* SupportedAudioStreamConfigurationTypes.COMFORT_NOISE_SUPPORT */, comfortNoise ? 1 : 0).toString("base64");
|
|
959
|
-
}
|
|
960
|
-
|
|
1000
|
+
}
|
|
1001
|
+
resetSetupEndpointsResponse() {
|
|
961
1002
|
this.setupEndpointsResponse = tlv.encode(2 /* SetupEndpointsResponseTypes.STATUS */, 2 /* SetupEndpointsStatus.ERROR */).toString("base64");
|
|
962
1003
|
this.service.updateCharacteristic(Characteristic_1.Characteristic.SetupEndpoints, this.setupEndpointsResponse);
|
|
963
|
-
}
|
|
964
|
-
|
|
1004
|
+
}
|
|
1005
|
+
resetSelectedStreamConfiguration() {
|
|
965
1006
|
this.selectedConfiguration = tlv.encode(1 /* SelectedRTPStreamConfigurationTypes.SESSION_CONTROL */, tlv.encode(2 /* SessionControlTypes.COMMAND */, SessionControlCommand.SUSPEND_SESSION)).toString("base64");
|
|
966
1007
|
this.service.updateCharacteristic(Characteristic_1.Characteristic.SelectedRTPStreamConfiguration, this.selectedConfiguration);
|
|
967
|
-
}
|
|
1008
|
+
}
|
|
968
1009
|
/**
|
|
969
1010
|
* @private
|
|
970
1011
|
*/
|
|
971
|
-
|
|
972
|
-
|
|
1012
|
+
serialize() {
|
|
1013
|
+
const characteristicValue = this.service.getCharacteristic(Characteristic_1.Characteristic.Active).value;
|
|
973
1014
|
if (characteristicValue === true) {
|
|
974
1015
|
return undefined;
|
|
975
1016
|
}
|
|
@@ -977,50 +1018,36 @@ var RTPStreamManagement = /** @class */ (function () {
|
|
|
977
1018
|
id: this.id,
|
|
978
1019
|
active: !!characteristicValue,
|
|
979
1020
|
};
|
|
980
|
-
}
|
|
1021
|
+
}
|
|
981
1022
|
/**
|
|
982
1023
|
* @private
|
|
983
1024
|
*/
|
|
984
|
-
|
|
985
|
-
(0, assert_1.default)(serialized.id === this.id,
|
|
1025
|
+
deserialize(serialized) {
|
|
1026
|
+
(0, assert_1.default)(serialized.id === this.id, `Tried to initialize RTPStreamManagement ${this.id} with data from management with id ${serialized.id}!`);
|
|
986
1027
|
this.service.updateCharacteristic(Characteristic_1.Characteristic.Active, serialized.active);
|
|
987
|
-
}
|
|
1028
|
+
}
|
|
988
1029
|
/**
|
|
989
1030
|
* @private
|
|
990
1031
|
*/
|
|
991
|
-
|
|
1032
|
+
setupStateChangeDelegate(delegate) {
|
|
992
1033
|
this.stateChangeDelegate = delegate;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
* @deprecated Please use the SRTPCryptoSuites const enum above.
|
|
996
|
-
*/
|
|
997
|
-
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
998
|
-
RTPStreamManagement.SRTPCryptoSuites = SRTPCryptoSuites;
|
|
999
|
-
/**
|
|
1000
|
-
* @deprecated Please use the H264Profile const enum above.
|
|
1001
|
-
*/
|
|
1002
|
-
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
1003
|
-
RTPStreamManagement.VideoCodecParamProfileIDTypes = H264Profile;
|
|
1004
|
-
/**
|
|
1005
|
-
* @deprecated won't be updated anymore. Please use the H264Level const enum above.
|
|
1006
|
-
*/
|
|
1007
|
-
RTPStreamManagement.VideoCodecParamLevelTypes = Object.freeze({ TYPE3_1: 0, TYPE3_2: 1, TYPE4_0: 2 });
|
|
1008
|
-
return RTPStreamManagement;
|
|
1009
|
-
}());
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1010
1036
|
exports.RTPStreamManagement = RTPStreamManagement;
|
|
1011
1037
|
/**
|
|
1012
1038
|
* @group Camera
|
|
1013
1039
|
* @deprecated - only there for backwards compatibility, please use {@link RTPStreamManagement} directly
|
|
1014
1040
|
*/
|
|
1015
|
-
|
|
1016
|
-
|
|
1041
|
+
class StreamController extends RTPStreamManagement {
|
|
1042
|
+
/**
|
|
1043
|
+
* options get saved so we can still support {@link Accessory.configureCameraSource}
|
|
1044
|
+
*/
|
|
1045
|
+
options;
|
|
1017
1046
|
// noinspection JSDeprecatedSymbols
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
return _this;
|
|
1047
|
+
constructor(id, options, delegate, service) {
|
|
1048
|
+
super(id, options, new Camera_1.LegacyCameraSourceAdapter(delegate), service);
|
|
1049
|
+
this.options = options;
|
|
1022
1050
|
}
|
|
1023
|
-
|
|
1024
|
-
}(RTPStreamManagement));
|
|
1051
|
+
}
|
|
1025
1052
|
exports.StreamController = StreamController;
|
|
1026
1053
|
//# sourceMappingURL=RTPStreamManagement.js.map
|