Skip to content

Commit

Permalink
0.0.6 fix for twoway audio
Browse files Browse the repository at this point in the history
  • Loading branch information
n0rt0nthec4t committed Sep 13, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 3b39d80 commit ac6d06f
Showing 6 changed files with 63 additions and 64 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,11 @@ All notable changes to `homebridge-nest-accfactory` will be documented in this f

Currently all releases are considered 'alpha' status, where things may or may not be working. Use at your own risk :-)

## v0.0.5 (2024/09/13)
## v0.0.6 (2024-09-14)

- Fix for two/way audio starting on non-enabled HKSV camera/doorbells

## v0.0.5 (2024-09-13)

- General code cleanup and bug fixes
- External dependancy reductions, dropped pbf and axios libraries
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
"displayName": "Nest Accfactory",
"name": "homebridge-nest-accfactory",
"homepage": "https://github.com/n0rt0nthec4t/homebridge-nest-accfactory",
"version": "0.0.5",
"version": "0.0.6",
"description": "Homebridge support for Nest/Google devices including HomeKit Secure Video (HKSV) support for doorbells and cameras",
"license": "Apache-2.0",
"author": "n0rt0nthec4t",
3 changes: 2 additions & 1 deletion src/camera.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Nest Cameras
// Part of homebridge-nest-accfactory
//
// Code version 12/9/2024
// Code version 13/9/2024
// Mark Hulskamp
'use strict';

@@ -33,6 +33,7 @@ export default class NestCamera extends HomeKitDevice {
controller = undefined; // HomeKit Camera/Doorbell controller service
streamer = undefined; // Streamer object for live/recording stream
motionServices = undefined; // Object of Camera/Doorbell motion sensor(s)
batteryService = undefined; // If a camera has a battery
operatingModeService = undefined; // Link to camera/doorbell operating mode service
personTimer = undefined; // Cooldown timer for person/face events
motionTimer = undefined; // Cooldown timer for motion events
4 changes: 2 additions & 2 deletions src/floodlight.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Nest Cam with Floodlight
// Part of homebridge-nest-accfactory
//
// Code version 12/9/2024
// Code version 13/9/2024
// Mark Hulskamp
'use strict';

@@ -48,7 +48,7 @@ export default class NestFloodlight extends NestCamera {
if (value !== this.deviceData.light_brightness) {
this.set({ light_brightness: value });

this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description);
this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description, value);
}
});

44 changes: 25 additions & 19 deletions src/nexustalk.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
//
// Credit to https://github.com/Brandawg93/homebridge-nest-cam for the work on the Nest Camera comms code on which this is based
//
// Code version 11/9/2024
// Code version 14/9/2024
// Mark Hulskamp
'use strict';

@@ -59,18 +59,19 @@ const PacketType = {
export default class NexusTalk extends Streamer {
token = undefined;
tokenType = undefined;
id = undefined; // Session ID
pingTimer = undefined; // Timer object for ping interval
stalledTimer = undefined; // Timer object for no received data
video = {}; // Video stream details
audio = {}; // Audio stream details
host = ''; // Host to connect to or connected too

// Internal data only for this class
#protobufNexusTalk = undefined; // Protobuf for NexusTalk
#socket = undefined; // TCP socket object
#packets = []; // Incoming packets
#messages = []; // Incoming messages
#authorised = false; // Have we been authorised
#id = undefined; // Session ID

constructor(deviceData, options) {
super(deviceData, options);
@@ -98,7 +99,7 @@ export default class NexusTalk extends Streamer {
this.pingTimer = clearInterval(this.pingTimer);
this.stalledTimer = clearInterval(this.stalledTimer);

this.id = undefined; // No session ID yet
this.#id = undefined; // No session ID yet

if (this.online === true && this.videoEnabled === true) {
if (typeof host === 'undefined' || host === null) {
@@ -134,7 +135,7 @@ export default class NexusTalk extends Streamer {
this.#authorised = false; // Since connection close, we can't be authorised anymore
this.#socket = undefined; // Clear socket object
this.connected = false;
this.id = undefined; // Not an active session anymore
this.#id = undefined; // Not an active session anymore

if (hadError === true && this.haveOutputs() === true) {
// We still have either active buffering occuring or output streams running
@@ -147,7 +148,7 @@ export default class NexusTalk extends Streamer {

close(stopStreamFirst) {
// Close an authenicated socket stream gracefully
if (this.#socket !== null) {
if (this.#socket !== undefined) {
if (stopStreamFirst === true) {
// Send a notifcation to nexus we're finished playback
this.#stopNexusData();
@@ -157,7 +158,7 @@ export default class NexusTalk extends Streamer {

this.connected = false;
this.#socket = undefined;
this.id = undefined; // Not an active session anymore
this.#id = undefined; // Not an active session anymore
this.#packets = [];
this.#messages = [];
}
@@ -171,24 +172,29 @@ export default class NexusTalk extends Streamer {
// access token has changed so re-authorise
this.token = deviceData.apiAccess.token;

if (this.#socket !== null) {
if (this.#socket !== undefined) {
this.#Authenticate(true); // Update authorisation only if connected
}
}

if (this.host !== deviceData.streaming_host) {
this.host = deviceData.streaming_host;
this?.log?.debug && this.log.debug('New host has been requested for connection. Host requested is "%s"', this.host);
}

// Let our parent handle the remaining updates
super.update(deviceData);
}

talkingAudio(talkingData) {
// Encode audio packet for sending to camera
if (typeof talkingData === 'object' && this.#protobufNexusTalk !== undefined) {
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.StartPlayback');
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.AudioPayload');
if (TraitMap !== null) {
let encodedData = TraitMap.encode(
TraitMap.fromObject({
payload: talkingData,
sessionId: this.id,
sessionId: this.#id,
codec: 'SPEEX',
sampleRate: 16000,
}),
@@ -227,12 +233,12 @@ export default class NexusTalk extends Streamer {
}

#stopNexusData() {
if (this.id !== undefined && this.#protobufNexusTalk !== undefined) {
if (this.#id !== undefined && this.#protobufNexusTalk !== undefined) {
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.StopPlayback');
if (TraitMap !== null) {
let encodedData = TraitMap.encode(
TraitMap.fromObject({
sessionId: this.id,
sessionId: this.#id,
}),
).finish();
this.#sendMessage(PacketType.STOP_PLAYBACK, encodedData);
@@ -241,7 +247,7 @@ export default class NexusTalk extends Streamer {
}

#sendMessage(type, data) {
if (this.#socket === null || this.#socket.readyState !== 'open' || (type !== PacketType.HELLO && this.#authorised === false)) {
if (this.#socket?.readyState !== 'open' || (type !== PacketType.HELLO && this.#authorised === false)) {
// We're not connect and/or authorised yet, so 'cache' message for processing once this occurs
this.#messages.push({ type: type, data: data });
return;
@@ -358,11 +364,11 @@ export default class NexusTalk extends Streamer {
});

// Since this is the beginning of playback, clear any active buffers contents
this.id = decodedMessage.sessionId;
this.#id = decodedMessage.sessionId;
this.#packets = [];
this.#messages = [];

this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this.id);
this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this.#id);
}
}

@@ -381,7 +387,7 @@ export default class NexusTalk extends Streamer {
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
this.#socket &&
this.#socket.on('close', () => {
this.connect(this.host); // try reconnection
this.connect(); // try reconnection
});
this.close(false); // Close existing socket
}, 8000);
@@ -405,7 +411,7 @@ export default class NexusTalk extends Streamer {
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.PlaybackEnd').decode(payload).toJSON();

if (this.id !== null && decodedMessage.reason === 'USER_ENDED_SESSION') {
if (this.#id !== undefined && decodedMessage.reason === 'USER_ENDED_SESSION') {
// Normal playback ended ie: when we stopped playback
this?.log?.debug && this.log.debug('Playback ended on "%s"', this.host);
}
@@ -418,7 +424,7 @@ export default class NexusTalk extends Streamer {
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
this.#socket &&
this.#socket.on('close', () => {
this.connect(this.host); // try reconnection to existing host
this.connect(); // try reconnection to existing host
});
this.close(false); // Close existing socket
}
@@ -443,15 +449,15 @@ export default class NexusTalk extends Streamer {
// Decode talk begin packet
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
this?.log?.debug && this.log.debug('Talkback started on "%s"', decodedMessage.deviceId);
this?.log?.debug && this.log.debug('Talkback started to uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
}
}

#handleTalkbackEnd(payload) {
// Decode talk end packet
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
this?.log?.debug && this.log.debug('Talkback ended on "%s"', decodedMessage.device_id);
this?.log?.debug && this.log.debug('Talkback ended from uuid "%s" with id of "%s"', this.uuid, decodedMessage.deviceId);
}
}

Loading

0 comments on commit ac6d06f

Please sign in to comment.