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