From 453876788899faccc2afb74ae81703e492d4e173 Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Thu, 15 Sep 2022 19:30:17 -0700 Subject: [PATCH] homekit: watch for sps/pps parse error. show accessory mode port in settings. --- plugins/homekit/.vscode/settings.json | 2 +- plugins/homekit/package-lock.json | 4 +- plugins/homekit/package.json | 2 +- plugins/homekit/src/hap-utils.ts | 33 ++++++++++++++- plugins/homekit/src/homekit-mixin.ts | 26 ++++-------- plugins/homekit/src/main.ts | 40 ++++++------------- .../src/types/camera/camera-streaming-srtp.ts | 10 ++++- 7 files changed, 64 insertions(+), 53 deletions(-) diff --git a/plugins/homekit/.vscode/settings.json b/plugins/homekit/.vscode/settings.json index f5aba09f8..f1342f03f 100644 --- a/plugins/homekit/.vscode/settings.json +++ b/plugins/homekit/.vscode/settings.json @@ -1,4 +1,4 @@ { - "scrypted.debugHost": "127.0.0.1" + "scrypted.debugHost": "koushik-mac" } \ No newline at end of file diff --git a/plugins/homekit/package-lock.json b/plugins/homekit/package-lock.json index cdf3d96a3..d9c1bb81f 100644 --- a/plugins/homekit/package-lock.json +++ b/plugins/homekit/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/homekit", - "version": "1.1.38", + "version": "1.1.40", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/homekit", - "version": "1.1.38", + "version": "1.1.40", "dependencies": { "@koush/werift-src": "file:../../external/werift", "check-disk-space": "^3.3.0", diff --git a/plugins/homekit/package.json b/plugins/homekit/package.json index 9dadb693b..5185efc57 100644 --- a/plugins/homekit/package.json +++ b/plugins/homekit/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/homekit", - "version": "1.1.38", + "version": "1.1.40", "description": "HomeKit Plugin for Scrypted", "scripts": { "scrypted-setup-project": "scrypted-setup-project", diff --git a/plugins/homekit/src/hap-utils.ts b/plugins/homekit/src/hap-utils.ts index 352a74686..fa336df58 100644 --- a/plugins/homekit/src/hap-utils.ts +++ b/plugins/homekit/src/hap-utils.ts @@ -7,6 +7,8 @@ import { StorageSettingsDict } from '@scrypted/common/src/settings'; import crypto from 'crypto'; import { closeQuiet, createBindZero } from '@scrypted/common/src/listen-cluster'; import { once } from 'events'; +import { randomPinCode } from './pincode'; +import sdk from '@scrypted/sdk'; class HAPLocalStorage { initSync() { @@ -100,7 +102,11 @@ export function getRandomPort() { return Math.round(30000 + Math.random() * 20000); } -export function createHAPUsernameStorageSettingsDict(group?: string): StorageSettingsDict<'mac' | 'qrCode' | 'pincode'> { +export function createHAPUsernameStorageSettingsDict(device: { storage: Storage, name?: string }, group: string, networkGroup = group): StorageSettingsDict<'mac' | 'qrCode' | 'pincode' | 'portOverride' | 'resetAccessory'> { + const alertReload = () => { + sdk.log.a(`You must reload the HomeKit plugin for the changes to ${device.name} to take effect.`); + } + return { qrCode: { group, @@ -109,9 +115,16 @@ export function createHAPUsernameStorageSettingsDict(group?: string): StorageSet readonly: true, description: "Scan with your iOS camera to pair this Scrypted with HomeKit.", }, - pincode: { + portOverride: { + group: networkGroup, + title: 'Bridge Port', + persistedDefaultValue: getRandomPort(), + description: 'Optional: The TCP port used by the Scrypted bridge. If none is specified, a random port will be chosen.', + type: 'number', + }, pincode: { group, title: "Manual Pairing Code", + persistedDefaultValue: randomPinCode(), readonly: true, }, mac: { @@ -120,6 +133,22 @@ export function createHAPUsernameStorageSettingsDict(group?: string): StorageSet title: "Username Override", persistedDefaultValue: createHAPUsername(), }, + resetAccessory: { + group, + title: 'Reset Pairing', + description: 'Resetting the pairing will resync it to HomeKit as a new device. Bridged devices will automatically relink as a new device. Accessory devices must be manually removed from the Home app and re-paired. Enter RESET to reset the pairing.', + placeholder: 'RESET', + mapPut: (oldValue, newValue) => { + if (newValue === 'RESET') { + device.storage.removeItem('mac'); + alertReload(); + // generate a new reset accessory random value. + return crypto.randomBytes(8).toString('hex'); + } + throw new Error('HomeKit Accessory Reset cancelled.'); + }, + mapGet: () => '', + }, } } diff --git a/plugins/homekit/src/homekit-mixin.ts b/plugins/homekit/src/homekit-mixin.ts index 2adcc98d7..c59e99808 100644 --- a/plugins/homekit/src/homekit-mixin.ts +++ b/plugins/homekit/src/homekit-mixin.ts @@ -21,31 +21,19 @@ export class HomekitMixin extends SettingsMixinDeviceBase { // todo: change this at some point. persistedDefaultValue: false, }, - ...createHAPUsernameStorageSettingsDict('HomeKit Pairing'), - resetAccessory: { - group: 'HomeKit Pairing', - title: 'Reset Pairing', - description: 'Resetting the pairing will resync it to HomeKit as a new device. Bridged devices will automatically relink as a new device. Accessory devices must be manually removed from the Home app and re-paired. Enter RESET to reset the pairing.', - placeholder: 'RESET', - mapPut: (oldValue, newValue) => { - if (newValue === 'RESET') { - this.storage.removeItem(this.storageSettings.keys.mac); - this.alertReload(); - // generate a new reset accessory random value. - return crypto.randomBytes(8).toString('hex'); - } - throw new Error('HomeKit Accessory Reset cancelled.'); - }, - mapGet: () => '', - }, + ...createHAPUsernameStorageSettingsDict(this, undefined, 'HomeKit Pairing'), }); constructor(options: SettingsMixinDeviceOptions) { super(options); + + const hideStandalone = !this.storageSettings.values.standalone; // this may only change on reload of plugin. - this.storageSettings.settings.qrCode.hide = !this.storageSettings.values.standalone; - this.storageSettings.settings.pincode.hide = !this.storageSettings.values.standalone; + this.storageSettings.settings.qrCode.hide = hideStandalone; + this.storageSettings.settings.pincode.hide = hideStandalone; + this.storageSettings.settings.resetAccessory.hide = hideStandalone; + this.storageSettings.settings.portOverride.hide = hideStandalone; } alertReload() { diff --git a/plugins/homekit/src/main.ts b/plugins/homekit/src/main.ts index 3ce6686f7..2c2587562 100644 --- a/plugins/homekit/src/main.ts +++ b/plugins/homekit/src/main.ts @@ -28,27 +28,7 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider, videoClipsId: string; cameraMixins = new Map(); storageSettings = new StorageSettings(this, { - ...createHAPUsernameStorageSettingsDict(), - pincode: { - title: "Manual Pairing Code", - persistedDefaultValue: randomPinCode(), - readonly: true, - }, - resetAccessory: { - title: 'Reset Pairing', - description: 'This will reset the Scrypted HomeKit Bridge and all bridged devices. The previous Scrypted HomeKit Bridge must be removed from the Home app, and Scrypted must be paired with HomeKit again.', - placeholder: 'RESET', - mapPut: (oldValue, newValue) => { - if (newValue === 'RESET') { - this.storage.removeItem(this.storageSettings.keys.mac); - this.log.a(`You must reload the HomeKit plugin for the changes to take effect.`); - // generate a new reset accessory random value. - return crypto.randomBytes(8).toString('hex'); - } - throw new Error('HomeKit Accessory Reset cancelled.'); - }, - mapGet: () => '', - }, + ...createHAPUsernameStorageSettingsDict(this, undefined, 'Network'), addressOverride: { group: 'Network', title: 'Scrypted Server Address', @@ -64,9 +44,9 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider, }, portOverride: { group: 'Network', - title: 'Bridge Port', + title: 'Server Port', persistedDefaultValue: createRandomPort(), - description: 'Optional: The TCP port used by the Scrypted bridge. If none is specified, a random port will be chosen.', + description: 'Optional: The TCP port used by the Scrypted Server. If none is specified, a random port will be chosen.', type: 'number', }, advertiserOverride: { @@ -208,7 +188,13 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider, storage: mixinStorage, onDeviceEvent: async () => { } - }, createHAPUsernameStorageSettingsDict()) + }, createHAPUsernameStorageSettingsDict({ + storage: mixinStorage, + get name() { + return device.name + } + }, + 'HomeKit', 'HomeKit Pairing')); storageSettings.settings.pincode.persistedDefaultValue = randomPinCode(); const mixinConsole = deviceManager.getMixinConsole(device.id, this.nativeId); @@ -220,7 +206,7 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider, published = true; mixinConsole.log('Device is in accessory mode and is online. HomeKit services are being published.'); - await this.publishAccessory(accessory, storageSettings.values.mac, storageSettings.values.pincode, standaloneCategory); + await this.publishAccessory(accessory, storageSettings.values.mac, storageSettings.values.pincode, standaloneCategory, storageSettings.values.portOverride); if (!hasPublished) { hasPublished = true; storageSettings.values.qrCode = accessory.setupURI(); @@ -352,10 +338,10 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider, return ret; } - async publishAccessory(accessory: Accessory, username: string, pincode: string, category: Categories) { + async publishAccessory(accessory: Accessory, username: string, pincode: string, category: Categories, port: number) { await accessory.publish({ username, - port: 0, + port, pincode, category, addIdentifyingMaterial: false, diff --git a/plugins/homekit/src/types/camera/camera-streaming-srtp.ts b/plugins/homekit/src/types/camera/camera-streaming-srtp.ts index bf62e230d..343110e85 100644 --- a/plugins/homekit/src/types/camera/camera-streaming-srtp.ts +++ b/plugins/homekit/src/types/camera/camera-streaming-srtp.ts @@ -83,13 +83,21 @@ export async function startCameraStreamSrtp(media: FFmpegInput, console: Console let opusFramesPerPacket = session.startRequest.audio.packet_time / 20; + let spsPps: ReturnType; + try { + spsPps = getSpsPps(video); + } + catch (e) { + console.warn('sps/pps parse error', e); + } + const vs = createCameraStreamSender(console, session.vconfig, session.videoReturn, session.videossrc, session.startRequest.video.pt, session.prepareRequest.video.port, session.prepareRequest.targetAddress, session.startRequest.video.rtcp_interval, { maxPacketSize: session.startRequest.video.mtu, - ...getSpsPps(video), + ...spsPps, }); videoSender = vs.sendRtp; vs.sendRtcp();