UNPKG

hap-nodejs

Version:

HAP-NodeJS is a Node.js implementation of HomeKit Accessory Server.

848 lines 60 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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; var tslib_1 = require("tslib"); var assert_1 = tslib_1.__importDefault(require("assert")); var crypto_1 = tslib_1.__importDefault(require("crypto")); var debug_1 = tslib_1.__importDefault(require("debug")); var net_1 = tslib_1.__importDefault(require("net")); var Characteristic_1 = require("../Characteristic"); var controller_1 = require("../controller"); var Service_1 = require("../Service"); var hapStatusError_1 = require("../util/hapStatusError"); var once_1 = require("../util/once"); var tlv = tslib_1.__importStar(require("../util/tlv")); var uuid = tslib_1.__importStar(require("../util/uuid")); // noinspection JSDeprecatedSymbols var Camera_1 = require("./Camera"); var RTPProxy_1 = tslib_1.__importDefault(require("./RTPProxy")); var debug = (0, debug_1.default)("HAP-NodeJS:Camera:RTPStreamManagement"); // ---------------------------------- TLV DEFINITIONS START ---------------------------------- var StreamingStatusTypes; (function (StreamingStatusTypes) { StreamingStatusTypes[StreamingStatusTypes["STATUS"] = 1] = "STATUS"; })(StreamingStatusTypes || (StreamingStatusTypes = {})); var StreamingStatus; (function (StreamingStatus) { StreamingStatus[StreamingStatus["AVAILABLE"] = 0] = "AVAILABLE"; StreamingStatus[StreamingStatus["IN_USE"] = 1] = "IN_USE"; StreamingStatus[StreamingStatus["UNAVAILABLE"] = 2] = "UNAVAILABLE"; })(StreamingStatus || (StreamingStatus = {})); // ---------- var SupportedVideoStreamConfigurationTypes; (function (SupportedVideoStreamConfigurationTypes) { SupportedVideoStreamConfigurationTypes[SupportedVideoStreamConfigurationTypes["VIDEO_CODEC_CONFIGURATION"] = 1] = "VIDEO_CODEC_CONFIGURATION"; })(SupportedVideoStreamConfigurationTypes || (SupportedVideoStreamConfigurationTypes = {})); var VideoCodecConfigurationTypes; (function (VideoCodecConfigurationTypes) { VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE"; VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS"; VideoCodecConfigurationTypes[VideoCodecConfigurationTypes["ATTRIBUTES"] = 3] = "ATTRIBUTES"; })(VideoCodecConfigurationTypes || (VideoCodecConfigurationTypes = {})); var VideoCodecParametersTypes; (function (VideoCodecParametersTypes) { VideoCodecParametersTypes[VideoCodecParametersTypes["PROFILE_ID"] = 1] = "PROFILE_ID"; VideoCodecParametersTypes[VideoCodecParametersTypes["LEVEL"] = 2] = "LEVEL"; VideoCodecParametersTypes[VideoCodecParametersTypes["PACKETIZATION_MODE"] = 3] = "PACKETIZATION_MODE"; VideoCodecParametersTypes[VideoCodecParametersTypes["CVO_ENABLED"] = 4] = "CVO_ENABLED"; VideoCodecParametersTypes[VideoCodecParametersTypes["CVO_ID"] = 5] = "CVO_ID"; })(VideoCodecParametersTypes || (VideoCodecParametersTypes = {})); var VideoAttributesTypes; (function (VideoAttributesTypes) { VideoAttributesTypes[VideoAttributesTypes["IMAGE_WIDTH"] = 1] = "IMAGE_WIDTH"; VideoAttributesTypes[VideoAttributesTypes["IMAGE_HEIGHT"] = 2] = "IMAGE_HEIGHT"; VideoAttributesTypes[VideoAttributesTypes["FRAME_RATE"] = 3] = "FRAME_RATE"; })(VideoAttributesTypes || (VideoAttributesTypes = {})); /** * @group Camera */ var VideoCodecType; (function (VideoCodecType) { VideoCodecType[VideoCodecType["H264"] = 0] = "H264"; // while the namespace is already reserved for H265 it isn't currently supported. // H265 = 0x01, })(VideoCodecType || (exports.VideoCodecType = VideoCodecType = {})); /** * @group Camera */ var H264Profile; (function (H264Profile) { H264Profile[H264Profile["BASELINE"] = 0] = "BASELINE"; H264Profile[H264Profile["MAIN"] = 1] = "MAIN"; H264Profile[H264Profile["HIGH"] = 2] = "HIGH"; })(H264Profile || (exports.H264Profile = H264Profile = {})); /** * @group Camera */ var H264Level; (function (H264Level) { H264Level[H264Level["LEVEL3_1"] = 0] = "LEVEL3_1"; H264Level[H264Level["LEVEL3_2"] = 1] = "LEVEL3_2"; H264Level[H264Level["LEVEL4_0"] = 2] = "LEVEL4_0"; })(H264Level || (exports.H264Level = H264Level = {})); /** * @group Camera */ var VideoCodecPacketizationMode; (function (VideoCodecPacketizationMode) { VideoCodecPacketizationMode[VideoCodecPacketizationMode["NON_INTERLEAVED"] = 0] = "NON_INTERLEAVED"; })(VideoCodecPacketizationMode || (exports.VideoCodecPacketizationMode = VideoCodecPacketizationMode = {})); var VideoCodecCVO; (function (VideoCodecCVO) { VideoCodecCVO[VideoCodecCVO["UNSUPPORTED"] = 0] = "UNSUPPORTED"; VideoCodecCVO[VideoCodecCVO["SUPPORTED"] = 1] = "SUPPORTED"; })(VideoCodecCVO || (VideoCodecCVO = {})); // ---------- var SupportedAudioStreamConfigurationTypes; (function (SupportedAudioStreamConfigurationTypes) { SupportedAudioStreamConfigurationTypes[SupportedAudioStreamConfigurationTypes["AUDIO_CODEC_CONFIGURATION"] = 1] = "AUDIO_CODEC_CONFIGURATION"; SupportedAudioStreamConfigurationTypes[SupportedAudioStreamConfigurationTypes["COMFORT_NOISE_SUPPORT"] = 2] = "COMFORT_NOISE_SUPPORT"; })(SupportedAudioStreamConfigurationTypes || (SupportedAudioStreamConfigurationTypes = {})); var AudioCodecConfigurationTypes; (function (AudioCodecConfigurationTypes) { AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE"; AudioCodecConfigurationTypes[AudioCodecConfigurationTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS"; })(AudioCodecConfigurationTypes || (AudioCodecConfigurationTypes = {})); var AudioCodecTypes; (function (AudioCodecTypes) { AudioCodecTypes[AudioCodecTypes["PCMU"] = 0] = "PCMU"; AudioCodecTypes[AudioCodecTypes["PCMA"] = 1] = "PCMA"; AudioCodecTypes[AudioCodecTypes["AAC_ELD"] = 2] = "AAC_ELD"; AudioCodecTypes[AudioCodecTypes["OPUS"] = 3] = "OPUS"; AudioCodecTypes[AudioCodecTypes["MSBC"] = 4] = "MSBC"; AudioCodecTypes[AudioCodecTypes["AMR"] = 5] = "AMR"; AudioCodecTypes[AudioCodecTypes["AMR_WB"] = 6] = "AMR_WB"; })(AudioCodecTypes || (AudioCodecTypes = {})); var AudioCodecParametersTypes; (function (AudioCodecParametersTypes) { AudioCodecParametersTypes[AudioCodecParametersTypes["CHANNEL"] = 1] = "CHANNEL"; AudioCodecParametersTypes[AudioCodecParametersTypes["BIT_RATE"] = 2] = "BIT_RATE"; AudioCodecParametersTypes[AudioCodecParametersTypes["SAMPLE_RATE"] = 3] = "SAMPLE_RATE"; AudioCodecParametersTypes[AudioCodecParametersTypes["PACKET_TIME"] = 4] = "PACKET_TIME"; // only present in selected audio codec parameters tlv })(AudioCodecParametersTypes || (AudioCodecParametersTypes = {})); /** * @group Camera */ var AudioBitrate; (function (AudioBitrate) { AudioBitrate[AudioBitrate["VARIABLE"] = 0] = "VARIABLE"; AudioBitrate[AudioBitrate["CONSTANT"] = 1] = "CONSTANT"; })(AudioBitrate || (exports.AudioBitrate = AudioBitrate = {})); /** * @group Camera */ var AudioSamplerate; (function (AudioSamplerate) { AudioSamplerate[AudioSamplerate["KHZ_8"] = 0] = "KHZ_8"; AudioSamplerate[AudioSamplerate["KHZ_16"] = 1] = "KHZ_16"; AudioSamplerate[AudioSamplerate["KHZ_24"] = 2] = "KHZ_24"; // 3, 4, 5 are theoretically defined, but no idea to what kHz value they correspond to // probably KHZ_32, KHZ_44_1, KHZ_48 (as supported by Secure Video recordings) })(AudioSamplerate || (exports.AudioSamplerate = AudioSamplerate = {})); // ---------- var SupportedRTPConfigurationTypes; (function (SupportedRTPConfigurationTypes) { SupportedRTPConfigurationTypes[SupportedRTPConfigurationTypes["SRTP_CRYPTO_SUITE"] = 2] = "SRTP_CRYPTO_SUITE"; })(SupportedRTPConfigurationTypes || (SupportedRTPConfigurationTypes = {})); /** * @group Camera */ var SRTPCryptoSuites; (function (SRTPCryptoSuites) { SRTPCryptoSuites[SRTPCryptoSuites["AES_CM_128_HMAC_SHA1_80"] = 0] = "AES_CM_128_HMAC_SHA1_80"; SRTPCryptoSuites[SRTPCryptoSuites["AES_CM_256_HMAC_SHA1_80"] = 1] = "AES_CM_256_HMAC_SHA1_80"; SRTPCryptoSuites[SRTPCryptoSuites["NONE"] = 2] = "NONE"; })(SRTPCryptoSuites || (exports.SRTPCryptoSuites = SRTPCryptoSuites = {})); // ---------- var SetupEndpointsTypes; (function (SetupEndpointsTypes) { SetupEndpointsTypes[SetupEndpointsTypes["SESSION_ID"] = 1] = "SESSION_ID"; SetupEndpointsTypes[SetupEndpointsTypes["CONTROLLER_ADDRESS"] = 3] = "CONTROLLER_ADDRESS"; SetupEndpointsTypes[SetupEndpointsTypes["VIDEO_SRTP_PARAMETERS"] = 4] = "VIDEO_SRTP_PARAMETERS"; SetupEndpointsTypes[SetupEndpointsTypes["AUDIO_SRTP_PARAMETERS"] = 5] = "AUDIO_SRTP_PARAMETERS"; })(SetupEndpointsTypes || (SetupEndpointsTypes = {})); var AddressTypes; (function (AddressTypes) { AddressTypes[AddressTypes["ADDRESS_VERSION"] = 1] = "ADDRESS_VERSION"; AddressTypes[AddressTypes["ADDRESS"] = 2] = "ADDRESS"; AddressTypes[AddressTypes["VIDEO_RTP_PORT"] = 3] = "VIDEO_RTP_PORT"; AddressTypes[AddressTypes["AUDIO_RTP_PORT"] = 4] = "AUDIO_RTP_PORT"; })(AddressTypes || (AddressTypes = {})); var IPAddressVersion; (function (IPAddressVersion) { IPAddressVersion[IPAddressVersion["IPV4"] = 0] = "IPV4"; IPAddressVersion[IPAddressVersion["IPV6"] = 1] = "IPV6"; })(IPAddressVersion || (IPAddressVersion = {})); var SRTPParametersTypes; (function (SRTPParametersTypes) { SRTPParametersTypes[SRTPParametersTypes["SRTP_CRYPTO_SUITE"] = 1] = "SRTP_CRYPTO_SUITE"; SRTPParametersTypes[SRTPParametersTypes["MASTER_KEY"] = 2] = "MASTER_KEY"; SRTPParametersTypes[SRTPParametersTypes["MASTER_SALT"] = 3] = "MASTER_SALT"; // 14 bytes })(SRTPParametersTypes || (SRTPParametersTypes = {})); var SetupEndpointsResponseTypes; (function (SetupEndpointsResponseTypes) { SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["SESSION_ID"] = 1] = "SESSION_ID"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["STATUS"] = 2] = "STATUS"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["ACCESSORY_ADDRESS"] = 3] = "ACCESSORY_ADDRESS"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["VIDEO_SRTP_PARAMETERS"] = 4] = "VIDEO_SRTP_PARAMETERS"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["AUDIO_SRTP_PARAMETERS"] = 5] = "AUDIO_SRTP_PARAMETERS"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["VIDEO_SSRC"] = 6] = "VIDEO_SSRC"; SetupEndpointsResponseTypes[SetupEndpointsResponseTypes["AUDIO_SSRC"] = 7] = "AUDIO_SSRC"; })(SetupEndpointsResponseTypes || (SetupEndpointsResponseTypes = {})); var SetupEndpointsStatus; (function (SetupEndpointsStatus) { SetupEndpointsStatus[SetupEndpointsStatus["SUCCESS"] = 0] = "SUCCESS"; SetupEndpointsStatus[SetupEndpointsStatus["BUSY"] = 1] = "BUSY"; SetupEndpointsStatus[SetupEndpointsStatus["ERROR"] = 2] = "ERROR"; })(SetupEndpointsStatus || (SetupEndpointsStatus = {})); // ---------- var SelectedRTPStreamConfigurationTypes; (function (SelectedRTPStreamConfigurationTypes) { SelectedRTPStreamConfigurationTypes[SelectedRTPStreamConfigurationTypes["SESSION_CONTROL"] = 1] = "SESSION_CONTROL"; SelectedRTPStreamConfigurationTypes[SelectedRTPStreamConfigurationTypes["SELECTED_VIDEO_PARAMETERS"] = 2] = "SELECTED_VIDEO_PARAMETERS"; SelectedRTPStreamConfigurationTypes[SelectedRTPStreamConfigurationTypes["SELECTED_AUDIO_PARAMETERS"] = 3] = "SELECTED_AUDIO_PARAMETERS"; })(SelectedRTPStreamConfigurationTypes || (SelectedRTPStreamConfigurationTypes = {})); var SessionControlTypes; (function (SessionControlTypes) { SessionControlTypes[SessionControlTypes["SESSION_IDENTIFIER"] = 1] = "SESSION_IDENTIFIER"; SessionControlTypes[SessionControlTypes["COMMAND"] = 2] = "COMMAND"; })(SessionControlTypes || (SessionControlTypes = {})); var SessionControlCommand; (function (SessionControlCommand) { SessionControlCommand[SessionControlCommand["END_SESSION"] = 0] = "END_SESSION"; SessionControlCommand[SessionControlCommand["START_SESSION"] = 1] = "START_SESSION"; SessionControlCommand[SessionControlCommand["SUSPEND_SESSION"] = 2] = "SUSPEND_SESSION"; SessionControlCommand[SessionControlCommand["RESUME_SESSION"] = 3] = "RESUME_SESSION"; SessionControlCommand[SessionControlCommand["RECONFIGURE_SESSION"] = 4] = "RECONFIGURE_SESSION"; })(SessionControlCommand || (SessionControlCommand = {})); var SelectedVideoParametersTypes; (function (SelectedVideoParametersTypes) { SelectedVideoParametersTypes[SelectedVideoParametersTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE"; SelectedVideoParametersTypes[SelectedVideoParametersTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS"; SelectedVideoParametersTypes[SelectedVideoParametersTypes["ATTRIBUTES"] = 3] = "ATTRIBUTES"; SelectedVideoParametersTypes[SelectedVideoParametersTypes["RTP_PARAMETERS"] = 4] = "RTP_PARAMETERS"; })(SelectedVideoParametersTypes || (SelectedVideoParametersTypes = {})); var VideoRTPParametersTypes; (function (VideoRTPParametersTypes) { VideoRTPParametersTypes[VideoRTPParametersTypes["PAYLOAD_TYPE"] = 1] = "PAYLOAD_TYPE"; VideoRTPParametersTypes[VideoRTPParametersTypes["SYNCHRONIZATION_SOURCE"] = 2] = "SYNCHRONIZATION_SOURCE"; VideoRTPParametersTypes[VideoRTPParametersTypes["MAX_BIT_RATE"] = 3] = "MAX_BIT_RATE"; VideoRTPParametersTypes[VideoRTPParametersTypes["MIN_RTCP_INTERVAL"] = 4] = "MIN_RTCP_INTERVAL"; VideoRTPParametersTypes[VideoRTPParametersTypes["MAX_MTU"] = 5] = "MAX_MTU"; })(VideoRTPParametersTypes || (VideoRTPParametersTypes = {})); var SelectedAudioParametersTypes; (function (SelectedAudioParametersTypes) { SelectedAudioParametersTypes[SelectedAudioParametersTypes["CODEC_TYPE"] = 1] = "CODEC_TYPE"; SelectedAudioParametersTypes[SelectedAudioParametersTypes["CODEC_PARAMETERS"] = 2] = "CODEC_PARAMETERS"; SelectedAudioParametersTypes[SelectedAudioParametersTypes["RTP_PARAMETERS"] = 3] = "RTP_PARAMETERS"; SelectedAudioParametersTypes[SelectedAudioParametersTypes["COMFORT_NOISE"] = 4] = "COMFORT_NOISE"; })(SelectedAudioParametersTypes || (SelectedAudioParametersTypes = {})); var AudioRTPParametersTypes; (function (AudioRTPParametersTypes) { AudioRTPParametersTypes[AudioRTPParametersTypes["PAYLOAD_TYPE"] = 1] = "PAYLOAD_TYPE"; AudioRTPParametersTypes[AudioRTPParametersTypes["SYNCHRONIZATION_SOURCE"] = 2] = "SYNCHRONIZATION_SOURCE"; AudioRTPParametersTypes[AudioRTPParametersTypes["MAX_BIT_RATE"] = 3] = "MAX_BIT_RATE"; AudioRTPParametersTypes[AudioRTPParametersTypes["MIN_RTCP_INTERVAL"] = 4] = "MIN_RTCP_INTERVAL"; AudioRTPParametersTypes[AudioRTPParametersTypes["COMFORT_NOISE_PAYLOAD_TYPE"] = 6] = "COMFORT_NOISE_PAYLOAD_TYPE"; })(AudioRTPParametersTypes || (AudioRTPParametersTypes = {})); // eslint-disable-next-line @typescript-eslint/no-explicit-any function isLegacySRTPOptions(options) { return "srtp" in options; } /** * @group Camera */ var AudioStreamingCodecType; (function (AudioStreamingCodecType) { AudioStreamingCodecType["PCMU"] = "PCMU"; AudioStreamingCodecType["PCMA"] = "PCMA"; AudioStreamingCodecType["AAC_ELD"] = "AAC-eld"; AudioStreamingCodecType["OPUS"] = "OPUS"; AudioStreamingCodecType["MSBC"] = "mSBC"; AudioStreamingCodecType["AMR"] = "AMR"; AudioStreamingCodecType["AMR_WB"] = "AMR-WB"; })(AudioStreamingCodecType || (exports.AudioStreamingCodecType = AudioStreamingCodecType = {})); /** * @group Camera */ var AudioStreamingSamplerate; (function (AudioStreamingSamplerate) { AudioStreamingSamplerate[AudioStreamingSamplerate["KHZ_8"] = 8] = "KHZ_8"; AudioStreamingSamplerate[AudioStreamingSamplerate["KHZ_16"] = 16] = "KHZ_16"; AudioStreamingSamplerate[AudioStreamingSamplerate["KHZ_24"] = 24] = "KHZ_24"; })(AudioStreamingSamplerate || (exports.AudioStreamingSamplerate = AudioStreamingSamplerate = {})); /** * @group Camera */ var StreamRequestTypes; (function (StreamRequestTypes) { StreamRequestTypes["RECONFIGURE"] = "reconfigure"; StreamRequestTypes["START"] = "start"; StreamRequestTypes["STOP"] = "stop"; })(StreamRequestTypes || (exports.StreamRequestTypes = StreamRequestTypes = {})); /** * @group Camera */ var RTPStreamManagement = /** @class */ (function () { function RTPStreamManagement(id, options, delegate, service, disabledThroughOperatingMode) { this.videoOnly = false; this.sessionIdentifier = undefined; /** * @private private API */ this.streamStatus = 0 /* StreamingStatus.AVAILABLE */; // use _updateStreamStatus to update this property this.selectedConfiguration = ""; // base64 representation of the currently selected configuration this.setupEndpointsResponse = ""; // response of the SetupEndpoints Characteristic this.id = id; this.delegate = delegate; this.requireProxy = options.proxy || false; this.disableAudioProxy = options.disable_audio_proxy || false; if (isLegacySRTPOptions(options)) { this.supportedCryptoSuites = [options.srtp ? 0 /* SRTPCryptoSuites.AES_CM_128_HMAC_SHA1_80 */ : 2 /* SRTPCryptoSuites.NONE */]; } else { this.supportedCryptoSuites = options.supportedCryptoSuites; } if (this.supportedCryptoSuites.length === 0) { this.supportedCryptoSuites.push(2 /* SRTPCryptoSuites.NONE */); } if (!options.video) { throw new Error("Video parameters cannot be undefined in options"); } this.supportedRTPConfiguration = RTPStreamManagement._supportedRTPConfiguration(this.supportedCryptoSuites); this.supportedVideoStreamConfiguration = RTPStreamManagement._supportedVideoStreamConfiguration(options.video); this.supportedAudioStreamConfiguration = this._supportedAudioStreamConfiguration(options.audio); this.activeConnectionClosedListener = this._handleStopStream.bind(this); this.service = service || this.constructService(id); this.setupServiceHandlers(); this.resetSetupEndpointsResponse(); this.resetSelectedStreamConfiguration(); this.disabledThroughOperatingMode = disabledThroughOperatingMode; } RTPStreamManagement.prototype.forceStop = function () { this.handleSessionClosed(); }; RTPStreamManagement.prototype.getService = function () { return this.service; }; // noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols /** * @deprecated */ // eslint-disable-next-line @typescript-eslint/no-unused-vars RTPStreamManagement.prototype.handleCloseConnection = function (connectionID) { // This method is only here for legacy compatibility. It used to be called by legacy style CameraSource // implementations to signal that the associated HAP connection was closed. // This is now handled automatically. Thus, we don't need to do anything anymore. }; RTPStreamManagement.prototype.handleFactoryReset = function () { this.resetSelectedStreamConfiguration(); this.resetSetupEndpointsResponse(); this.service.updateCharacteristic(Characteristic_1.Characteristic.Active, true); // on a factory reset the assumption is that all connections were already terminated and thus "handleStopStream" was already called }; RTPStreamManagement.prototype.destroy = function () { if (this.activeConnection) { this._handleStopStream(); } }; RTPStreamManagement.prototype.constructService = function (id) { var managementService = new Service_1.Service.CameraRTPStreamManagement("", id.toString()); // this service is required only when recording is enabled. We don't really have access to this info here, // so we just add the characteristic. Doesn't really hurt. managementService.setCharacteristic(Characteristic_1.Characteristic.Active, true); return managementService; }; RTPStreamManagement.prototype.setupServiceHandlers = function () { var _this = this; if (!this.service.testCharacteristic(Characteristic_1.Characteristic.Active)) { // the active characteristic might not be present on some older configurations. this.service.setCharacteristic(Characteristic_1.Characteristic.Active, true); } this.service.getCharacteristic(Characteristic_1.Characteristic.Active) .on("change" /* CharacteristicEventTypes.CHANGE */, function () { var _a; return (_a = _this.stateChangeDelegate) === null || _a === void 0 ? void 0 : _a.call(_this); }) .setProps({ adminOnlyAccess: [1 /* Access.WRITE */] }); // ensure that configurations are up-to-date and reflected in the characteristic values this.service.setCharacteristic(Characteristic_1.Characteristic.SupportedRTPConfiguration, this.supportedRTPConfiguration); this.service.setCharacteristic(Characteristic_1.Characteristic.SupportedVideoStreamConfiguration, this.supportedVideoStreamConfiguration); this.service.setCharacteristic(Characteristic_1.Characteristic.SupportedAudioStreamConfiguration, this.supportedAudioStreamConfiguration); this._updateStreamStatus(0 /* StreamingStatus.AVAILABLE */); // reset streaming status to available this.service.setCharacteristic(Characteristic_1.Characteristic.SetupEndpoints, this.setupEndpointsResponse); // reset SetupEndpoints to default this.service.getCharacteristic(Characteristic_1.Characteristic.SelectedRTPStreamConfiguration) .on("get" /* CharacteristicEventTypes.GET */, function (callback) { if (_this.streamingIsDisabled()) { callback(null, tlv.encode(1 /* SelectedRTPStreamConfigurationTypes.SESSION_CONTROL */, tlv.encode(2 /* SessionControlTypes.COMMAND */, SessionControlCommand.SUSPEND_SESSION)).toString("base64")); return; } callback(null, _this.selectedConfiguration); }) .on("set" /* CharacteristicEventTypes.SET */, this._handleSelectedStreamConfigurationWrite.bind(this)); this.service.getCharacteristic(Characteristic_1.Characteristic.SetupEndpoints) .on("get" /* CharacteristicEventTypes.GET */, function (callback) { if (_this.streamingIsDisabled()) { callback(null, tlv.encode(2 /* SetupEndpointsResponseTypes.STATUS */, 2 /* SetupEndpointsStatus.ERROR */).toString("base64")); return; } callback(null, _this.setupEndpointsResponse); }) .on("set" /* CharacteristicEventTypes.SET */, function (value, callback, context, connection) { if (!connection) { debug("Set event handler for SetupEndpoints cannot be called from plugin. Connection undefined!"); callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */); return; } _this.handleSetupEndpoints(value, callback, connection); }); }; RTPStreamManagement.prototype.handleSessionClosed = function () { this.resetSelectedStreamConfiguration(); this.resetSetupEndpointsResponse(); if (this.activeConnection) { this.activeConnection.removeListener("closed" /* HAPConnectionEvent.CLOSED */, this.activeConnectionClosedListener); this.activeConnection.setMaxListeners(this.activeConnection.getMaxListeners() - 1); this.activeConnection = undefined; } this._updateStreamStatus(0 /* StreamingStatus.AVAILABLE */); this.sessionIdentifier = undefined; // noinspection JSDeprecatedSymbols this.connectionID = undefined; this.ipVersion = undefined; if (this.videoProxy) { this.videoProxy.destroy(); this.videoProxy = undefined; } if (this.audioProxy) { this.audioProxy.destroy(); this.audioProxy = undefined; } }; RTPStreamManagement.prototype.streamingIsDisabled = function (callback) { var _a; if (!this.service.getCharacteristic(Characteristic_1.Characteristic.Active).value) { if (callback) { callback(new hapStatusError_1.HapStatusError(-70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */)); } return true; } if ((_a = this.disabledThroughOperatingMode) === null || _a === void 0 ? void 0 : _a.call(this)) { if (callback) { callback(new hapStatusError_1.HapStatusError(-70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */)); } return true; } return false; }; RTPStreamManagement.prototype._handleSelectedStreamConfigurationWrite = function (value, callback) { var _this = this; if (this.streamingIsDisabled(callback)) { return; } var data = Buffer.from(value, "base64"); var objects = tlv.decode(data); var sessionControl = tlv.decode(objects[1 /* SelectedRTPStreamConfigurationTypes.SESSION_CONTROL */]); var sessionIdentifier = uuid.unparse(sessionControl[1 /* SessionControlTypes.SESSION_IDENTIFIER */]); var requestType = sessionControl[2 /* SessionControlTypes.COMMAND */][0]; if (sessionIdentifier !== this.sessionIdentifier) { debug("Received unknown session Identifier with request to ".concat(SessionControlCommand[requestType])); callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */); return; } this.selectedConfiguration = value; // intercept the callback chain to check if an error occurred. var streamCallback = function (error, writeResponse) { callback(error, writeResponse); // does not support writeResponse, but how knows what comes in the future. if (error) { _this.handleSessionClosed(); } }; switch (requestType) { case SessionControlCommand.START_SESSION: { var selectedVideoParameters = tlv.decode(objects[2 /* SelectedRTPStreamConfigurationTypes.SELECTED_VIDEO_PARAMETERS */]); var selectedAudioParameters = tlv.decode(objects[3 /* SelectedRTPStreamConfigurationTypes.SELECTED_AUDIO_PARAMETERS */]); this._handleStartStream(selectedVideoParameters, selectedAudioParameters, streamCallback); break; } case SessionControlCommand.RECONFIGURE_SESSION: { var reconfiguredVideoParameters = tlv.decode(objects[2 /* SelectedRTPStreamConfigurationTypes.SELECTED_VIDEO_PARAMETERS */]); this.handleReconfigureStream(reconfiguredVideoParameters, streamCallback); break; } case SessionControlCommand.END_SESSION: this._handleStopStream(streamCallback); break; case SessionControlCommand.RESUME_SESSION: case SessionControlCommand.SUSPEND_SESSION: default: debug("Unhandled request type ".concat(SessionControlCommand[requestType])); callback(-70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */); return; } }; RTPStreamManagement.prototype._handleStartStream = function (videoConfiguration, audioConfiguration, callback) { // selected video configuration // noinspection JSUnusedLocalSymbols var videoCodec = videoConfiguration[1 /* SelectedVideoParametersTypes.CODEC_TYPE */]; // always 0x00 for h264 var videoParametersTLV = videoConfiguration[2 /* SelectedVideoParametersTypes.CODEC_PARAMETERS */]; var videoAttributesTLV = videoConfiguration[3 /* SelectedVideoParametersTypes.ATTRIBUTES */]; var videoRTPParametersTLV = videoConfiguration[4 /* SelectedVideoParametersTypes.RTP_PARAMETERS */]; // video parameters var videoParameters = tlv.decode(videoParametersTLV); var h264Profile = videoParameters[1 /* VideoCodecParametersTypes.PROFILE_ID */][0]; var h264Level = videoParameters[2 /* VideoCodecParametersTypes.LEVEL */][0]; var packetizationMode = videoParameters[3 /* VideoCodecParametersTypes.PACKETIZATION_MODE */][0]; var cvoEnabled = videoParameters[4 /* VideoCodecParametersTypes.CVO_ENABLED */]; var cvoId = undefined; if (cvoEnabled && cvoEnabled[0] === 1 /* VideoCodecCVO.SUPPORTED */) { cvoId = videoParameters[5 /* VideoCodecParametersTypes.CVO_ID */].readUInt8(0); } // video attributes var videoAttributes = tlv.decode(videoAttributesTLV); var width = videoAttributes[1 /* VideoAttributesTypes.IMAGE_WIDTH */].readUInt16LE(0); var height = videoAttributes[2 /* VideoAttributesTypes.IMAGE_HEIGHT */].readUInt16LE(0); var frameRate = videoAttributes[3 /* VideoAttributesTypes.FRAME_RATE */].readUInt8(0); // video rtp parameters var videoRTPParameters = tlv.decode(videoRTPParametersTLV); var videoPayloadType = videoRTPParameters[1 /* VideoRTPParametersTypes.PAYLOAD_TYPE */].readUInt8(0); // 99 var videoSSRC = videoRTPParameters[2 /* VideoRTPParametersTypes.SYNCHRONIZATION_SOURCE */].readUInt32LE(0); var videoMaximumBitrate = videoRTPParameters[3 /* VideoRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0); var videoRTCPInterval = videoRTPParameters[4 /* VideoRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0); var maxMTU = this.ipVersion === "ipv6" ? 1228 : 1378; // default values ipv4: 1378 bytes; ipv6: 1228 bytes if (videoRTPParameters[5 /* VideoRTPParametersTypes.MAX_MTU */]) { maxMTU = videoRTPParameters[5 /* VideoRTPParametersTypes.MAX_MTU */].readUInt16LE(0); } // selected audio configuration var audioCodec = audioConfiguration[1 /* SelectedAudioParametersTypes.CODEC_TYPE */][0]; var audioParametersTLV = audioConfiguration[2 /* SelectedAudioParametersTypes.CODEC_PARAMETERS */]; var audioRTPParametersTLV = audioConfiguration[3 /* SelectedAudioParametersTypes.RTP_PARAMETERS */]; var comfortNoise = !!audioConfiguration[4 /* SelectedAudioParametersTypes.COMFORT_NOISE */].readUInt8(0); // audio parameters var audioParameters = tlv.decode(audioParametersTLV); var channels = audioParameters[1 /* AudioCodecParametersTypes.CHANNEL */][0]; var audioBitrate = audioParameters[2 /* AudioCodecParametersTypes.BIT_RATE */][0]; var samplerate = audioParameters[3 /* AudioCodecParametersTypes.SAMPLE_RATE */][0]; var rtpPacketTime = audioParameters[4 /* AudioCodecParametersTypes.PACKET_TIME */].readUInt8(0); // audio rtp parameters var audioRTPParameters = tlv.decode(audioRTPParametersTLV); var audioPayloadType = audioRTPParameters[1 /* AudioRTPParametersTypes.PAYLOAD_TYPE */].readUInt8(0); // 110 var audioSSRC = audioRTPParameters[2 /* AudioRTPParametersTypes.SYNCHRONIZATION_SOURCE */].readUInt32LE(0); var audioMaximumBitrate = audioRTPParameters[3 /* AudioRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0); var audioRTCPInterval = audioRTPParameters[4 /* AudioRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0); var comfortNoisePayloadType = audioRTPParameters[6 /* AudioRTPParametersTypes.COMFORT_NOISE_PAYLOAD_TYPE */].readUInt8(0); // 13 if (this.requireProxy) { this.videoProxy.setOutgoingPayloadType(videoPayloadType); if (!this.disableAudioProxy) { this.audioProxy.setOutgoingPayloadType(audioPayloadType); } } var videoInfo = { codec: videoCodec.readUInt8(0), profile: h264Profile, level: h264Level, packetizationMode: packetizationMode, cvoId: cvoId, width: width, height: height, fps: frameRate, pt: videoPayloadType, ssrc: videoSSRC, max_bit_rate: videoMaximumBitrate, rtcp_interval: videoRTCPInterval, mtu: maxMTU, }; var audioCodecName; var samplerateNum; switch (audioCodec) { case 0 /* AudioCodecTypes.PCMU */: audioCodecName = "PCMU" /* AudioStreamingCodecType.PCMU */; break; case 1 /* AudioCodecTypes.PCMA */: audioCodecName = "PCMA" /* AudioStreamingCodecType.PCMA */; break; case 2 /* AudioCodecTypes.AAC_ELD */: audioCodecName = "AAC-eld" /* AudioStreamingCodecType.AAC_ELD */; break; case 3 /* AudioCodecTypes.OPUS */: audioCodecName = "OPUS" /* AudioStreamingCodecType.OPUS */; break; case 4 /* AudioCodecTypes.MSBC */: audioCodecName = "mSBC" /* AudioStreamingCodecType.MSBC */; break; case 5 /* AudioCodecTypes.AMR */: audioCodecName = "AMR" /* AudioStreamingCodecType.AMR */; break; case 6 /* AudioCodecTypes.AMR_WB */: audioCodecName = "AMR-WB" /* AudioStreamingCodecType.AMR_WB */; break; default: throw new Error("Encountered unknown selected audio codec ".concat(audioCodec)); } switch (samplerate) { case 0 /* AudioSamplerate.KHZ_8 */: samplerateNum = 8; break; case 1 /* AudioSamplerate.KHZ_16 */: samplerateNum = 16; break; case 2 /* AudioSamplerate.KHZ_24 */: samplerateNum = 24; break; default: throw new Error("Encountered unknown selected audio samplerate ".concat(samplerate)); } var audioInfo = { codec: audioCodecName, channel: channels, bit_rate: audioBitrate, sample_rate: samplerateNum, packet_time: rtpPacketTime, pt: audioPayloadType, ssrc: audioSSRC, max_bit_rate: audioMaximumBitrate, rtcp_interval: audioRTCPInterval, comfort_pt: comfortNoisePayloadType, comfortNoiseEnabled: comfortNoise, }; var request = { sessionID: this.sessionIdentifier, type: "start" /* StreamRequestTypes.START */, video: videoInfo, audio: audioInfo, }; this.delegate.handleStreamRequest(request, function (error) { return callback(error); }); }; RTPStreamManagement.prototype.handleReconfigureStream = function (videoConfiguration, callback) { // selected video configuration var videoAttributesTLV = videoConfiguration[3 /* SelectedVideoParametersTypes.ATTRIBUTES */]; var videoRTPParametersTLV = videoConfiguration[4 /* SelectedVideoParametersTypes.RTP_PARAMETERS */]; // video attributes var videoAttributes = tlv.decode(videoAttributesTLV); var width = videoAttributes[1 /* VideoAttributesTypes.IMAGE_WIDTH */].readUInt16LE(0); var height = videoAttributes[2 /* VideoAttributesTypes.IMAGE_HEIGHT */].readUInt16LE(0); var frameRate = videoAttributes[3 /* VideoAttributesTypes.FRAME_RATE */].readUInt8(0); // video rtp parameters var videoRTPParameters = tlv.decode(videoRTPParametersTLV); var videoMaximumBitrate = videoRTPParameters[3 /* VideoRTPParametersTypes.MAX_BIT_RATE */].readUInt16LE(0); // seems to be always zero, use default of 0.5 var videoRTCPInterval = videoRTPParameters[4 /* VideoRTPParametersTypes.MIN_RTCP_INTERVAL */].readFloatLE(0) || 0.5; var reconfiguredVideoInfo = { width: width, height: height, fps: frameRate, max_bit_rate: videoMaximumBitrate, rtcp_interval: videoRTCPInterval, }; var request = { sessionID: this.sessionIdentifier, type: "reconfigure" /* StreamRequestTypes.RECONFIGURE */, video: reconfiguredVideoInfo, }; this.delegate.handleStreamRequest(request, function (error) { return callback(error); }); }; RTPStreamManagement.prototype._handleStopStream = function (callback) { var request = { sessionID: this.sessionIdentifier, // save sessionIdentifier before handleSessionClosed is called type: "stop" /* StreamRequestTypes.STOP */, }; this.handleSessionClosed(); this.delegate.handleStreamRequest(request, function (error) { return callback ? callback(error) : undefined; }); }; RTPStreamManagement.prototype.handleSetupEndpoints = function (value, callback, connection) { var _this = this; if (this.streamingIsDisabled(callback)) { return; } var data = Buffer.from(value, "base64"); var objects = tlv.decode(data); var sessionIdentifier = uuid.unparse(objects[1 /* SetupEndpointsTypes.SESSION_ID */]); if (this.streamStatus !== 0 /* StreamingStatus.AVAILABLE */) { this.setupEndpointsResponse = tlv.encode(1 /* SetupEndpointsResponseTypes.SESSION_ID */, uuid.write(sessionIdentifier), 2 /* SetupEndpointsResponseTypes.STATUS */, 1 /* SetupEndpointsStatus.BUSY */).toString("base64"); callback(); return; } (0, assert_1.default)(this.activeConnection == null, "Found non-nil `activeConnection` when trying to setup streaming endpoints, even though streamStatus is reported to be AVAILABLE!"); this.activeConnection = connection; this.activeConnection.setMaxListeners(this.activeConnection.getMaxListeners() + 1); this.activeConnection.on("closed" /* HAPConnectionEvent.CLOSED */, this.activeConnectionClosedListener); // noinspection JSDeprecatedSymbols this.connectionID = connection.sessionID; this.sessionIdentifier = sessionIdentifier; this._updateStreamStatus(1 /* StreamingStatus.IN_USE */); // Address var targetAddressPayload = objects[3 /* SetupEndpointsTypes.CONTROLLER_ADDRESS */]; var processedAddressInfo = tlv.decode(targetAddressPayload); var addressVersion = processedAddressInfo[1 /* AddressTypes.ADDRESS_VERSION */][0]; var controllerAddress = processedAddressInfo[2 /* AddressTypes.ADDRESS */].toString("utf8"); var targetVideoPort = processedAddressInfo[3 /* AddressTypes.VIDEO_RTP_PORT */].readUInt16LE(0); var targetAudioPort = processedAddressInfo[4 /* AddressTypes.AUDIO_RTP_PORT */].readUInt16LE(0); // Video SRTP Params var videoSRTPPayload = objects[4 /* SetupEndpointsTypes.VIDEO_SRTP_PARAMETERS */]; var processedVideoInfo = tlv.decode(videoSRTPPayload); var videoCryptoSuite = processedVideoInfo[1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */][0]; var videoMasterKey = processedVideoInfo[2 /* SRTPParametersTypes.MASTER_KEY */]; var videoMasterSalt = processedVideoInfo[3 /* SRTPParametersTypes.MASTER_SALT */]; // Audio SRTP Params var audioSRTPPayload = objects[5 /* SetupEndpointsTypes.AUDIO_SRTP_PARAMETERS */]; var processedAudioInfo = tlv.decode(audioSRTPPayload); var audioCryptoSuite = processedAudioInfo[1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */][0]; var audioMasterKey = processedAudioInfo[2 /* SRTPParametersTypes.MASTER_KEY */]; var audioMasterSalt = processedAudioInfo[3 /* SRTPParametersTypes.MASTER_SALT */]; 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); var prepareRequest = { sessionID: sessionIdentifier, sourceAddress: connection.localAddress, targetAddress: controllerAddress, addressVersion: addressVersion === 1 /* IPAddressVersion.IPV6 */ ? "ipv6" : "ipv4", video: { port: targetVideoPort, srtpCryptoSuite: videoCryptoSuite, srtp_key: videoMasterKey, srtp_salt: videoMasterSalt, }, audio: { port: targetAudioPort, srtpCryptoSuite: audioCryptoSuite, srtp_key: audioMasterKey, srtp_salt: audioMasterSalt, }, }; var promises = []; if (this.requireProxy) { prepareRequest.targetAddress = connection.getLocalAddress(addressVersion === 1 /* IPAddressVersion.IPV6 */ ? "ipv6" : "ipv4"); // ip versions must be the same this.videoProxy = new RTPProxy_1.default({ outgoingAddress: controllerAddress, outgoingPort: targetVideoPort, outgoingSSRC: crypto_1.default.randomBytes(4).readUInt32LE(0), // videoSSRC disabled: false, }); promises.push(this.videoProxy.setup().then(function () { prepareRequest.video.proxy_rtp = _this.videoProxy.incomingRTPPort(); prepareRequest.video.proxy_rtcp = _this.videoProxy.incomingRTCPPort(); })); if (!this.disableAudioProxy) { this.audioProxy = new RTPProxy_1.default({ outgoingAddress: controllerAddress, outgoingPort: targetAudioPort, outgoingSSRC: crypto_1.default.randomBytes(4).readUInt32LE(0), // audioSSRC disabled: this.videoOnly, }); promises.push(this.audioProxy.setup().then(function () { prepareRequest.audio.proxy_rtp = _this.audioProxy.incomingRTPPort(); prepareRequest.audio.proxy_rtcp = _this.audioProxy.incomingRTCPPort(); })); } } Promise.all(promises).then(function () { _this.delegate.prepareStream(prepareRequest, (0, once_1.once)(function (error, response) { if (error || !response) { debug("PrepareStream request encountered an error: ".concat(error ? error.message : undefined)); _this.setupEndpointsResponse = tlv.encode(1 /* SetupEndpointsResponseTypes.SESSION_ID */, uuid.write(sessionIdentifier), 2 /* SetupEndpointsResponseTypes.STATUS */, 2 /* SetupEndpointsStatus.ERROR */).toString("base64"); _this.handleSessionClosed(); callback(error); } else { _this.generateSetupEndpointResponse(connection, sessionIdentifier, prepareRequest, response, callback); } })); }); }; RTPStreamManagement.prototype.generateSetupEndpointResponse = function (connection, identifier, request, response, callback) { var address; var addressVersion = request.addressVersion; var videoPort; var audioPort; var videoCryptoSuite; var videoSRTPKey; var videoSRTPSalt; var audioCryptoSuite; var audioSRTPKey; var audioSRTPSalt; var videoSSRC; var audioSSRC; if (!this.videoOnly && !response.audio) { throw new Error("Audio was enabled but not supplied in PrepareStreamResponse!"); } // Provide default values if audio was not supplied var audio = response.audio || { port: request.audio.port, ssrc: controller_1.CameraController.generateSynchronisationSource(), srtp_key: request.audio.srtp_key, srtp_salt: request.audio.srtp_salt, }; if (!this.requireProxy) { var videoInfo = response.video; var audioInfo = audio; if (response.addressOverride) { addressVersion = net_1.default.isIPv4(response.addressOverride) ? "ipv4" : "ipv6"; address = response.addressOverride; } else { address = connection.getLocalAddress(addressVersion); } if (request.addressVersion !== addressVersion) { throw new Error("Incoming and outgoing ip address versions must match! Expected ".concat(request.addressVersion, " but got ").concat(addressVersion)); } videoPort = videoInfo.port; audioPort = audioInfo.port; if (request.video.srtpCryptoSuite !== 2 /* SRTPCryptoSuites.NONE */ && (videoInfo.srtp_key === undefined || videoInfo.srtp_salt === undefined)) { throw new Error("SRTP was selected for the prepared video stream, but no 'srtp_key' or 'srtp_salt' was specified!"); } if (request.audio.srtpCryptoSuite !== 2 /* SRTPCryptoSuites.NONE */ && (audioInfo.srtp_key === undefined || audioInfo.srtp_salt === undefined)) { throw new Error("SRTP was selected for the prepared audio stream, but no 'srtp_key' or 'srtp_salt' was specified!"); } videoCryptoSuite = request.video.srtpCryptoSuite; videoSRTPKey = videoInfo.srtp_key || Buffer.alloc(0); // key and salt are zero-length for cryptoSuite = NONE videoSRTPSalt = videoInfo.srtp_salt || Buffer.alloc(0); audioCryptoSuite = request.audio.srtpCryptoSuite; audioSRTPKey = audioInfo.srtp_key || Buffer.alloc(0); // key and salt are zero-length for cryptoSuite = NONE audioSRTPSalt = audioInfo.srtp_salt || Buffer.alloc(0); videoSSRC = videoInfo.ssrc; audioSSRC = audioInfo.ssrc; } else { var videoInfo = response.video; address = connection.getLocalAddress(request.addressVersion); videoCryptoSuite = 2 /* SRTPCryptoSuites.NONE */; videoSRTPKey = Buffer.alloc(0); videoSRTPSalt = Buffer.alloc(0); audioCryptoSuite = 2 /* SRTPCryptoSuites.NONE */; audioSRTPKey = Buffer.alloc(0); audioSRTPSalt = Buffer.alloc(0); this.videoProxy.setIncomingPayloadType(videoInfo.proxy_pt); this.videoProxy.setServerAddress(videoInfo.proxy_server_address); this.videoProxy.setServerRTPPort(videoInfo.proxy_server_rtp); this.videoProxy.setServerRTCPPort(videoInfo.proxy_server_rtcp); videoPort = this.videoProxy.outgoingLocalPort(); videoSSRC = this.videoProxy.outgoingSSRC; if (!this.disableAudioProxy) { var audioInfo = response.audio; this.audioProxy.setIncomingPayloadType(audioInfo.proxy_pt); this.audioProxy.setServerAddress(audioInfo.proxy_server_address); this.audioProxy.setServerRTPPort(audioInfo.proxy_server_rtp); this.audioProxy.setServerRTCPPort(audioInfo.proxy_server_rtcp); audioPort = this.audioProxy.outgoingLocalPort(); audioSSRC = this.audioProxy.outgoingSSRC; } else { var audioInfo = response.audio; audioPort = audioInfo.port; audioSSRC = audioInfo.ssrc; } } this.ipVersion = addressVersion; // we need to save this in order to calculate some default mtu values later var 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)); var videoSRTPParameters = tlv.encode(1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */, videoCryptoSuite, 2 /* SRTPParametersTypes.MASTER_KEY */, videoSRTPKey, 3 /* SRTPParametersTypes.MASTER_SALT */, videoSRTPSalt); var audioSRTPParameters = tlv.encode(1 /* SRTPParametersTypes.SRTP_CRYPTO_SUITE */, audioCryptoSuite, 2 /* SRTPParametersTypes.MASTER_KEY */, audioSRTPKey, 3 /* SRTPParametersTypes.MASTER_SALT */, audioSRTPSalt); 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"); callback(); }; RTPStreamManagement.prototype._updateStreamStatus = function (status) { this.streamStatus = status; this.service.updateCharacteristic(Characteristic_1.Characteristic.StreamingStatus, tlv.encode(1 /* StreamingStatusTypes.STATUS */, this.streamStatus).toString("base64")); }; RTPStreamManagement._supportedRTPConfiguration = function (supportedCryptoSuites) { if (supportedCryptoSuites.length === 1 && supportedCryptoSuites[0] === 2 /* SRTPCryptoSuites.NONE */) { debug("Client claims it doesn't support SRTP. The stream may stops working with future iOS releases."); } return tlv.encode(2 /* SupportedRTPConfigurationTypes.SRTP_CRYPTO_SUITE */,