5
5
//
6
6
// Credit to https://github.com/Brandawg93/homebridge-nest-cam for the work on the Nest Camera comms code on which this is based
7
7
//
8
- // Code version 11 /9/2024
8
+ // Code version 14 /9/2024
9
9
// Mark Hulskamp
10
10
'use strict' ;
11
11
@@ -59,18 +59,19 @@ const PacketType = {
59
59
export default class NexusTalk extends Streamer {
60
60
token = undefined ;
61
61
tokenType = undefined ;
62
- id = undefined ; // Session ID
63
62
pingTimer = undefined ; // Timer object for ping interval
64
63
stalledTimer = undefined ; // Timer object for no received data
65
64
video = { } ; // Video stream details
66
65
audio = { } ; // Audio stream details
66
+ host = '' ; // Host to connect to or connected too
67
67
68
68
// Internal data only for this class
69
69
#protobufNexusTalk = undefined ; // Protobuf for NexusTalk
70
70
#socket = undefined ; // TCP socket object
71
71
#packets = [ ] ; // Incoming packets
72
72
#messages = [ ] ; // Incoming messages
73
73
#authorised = false ; // Have we been authorised
74
+ #id = undefined ; // Session ID
74
75
75
76
constructor ( deviceData , options ) {
76
77
super ( deviceData , options ) ;
@@ -98,7 +99,7 @@ export default class NexusTalk extends Streamer {
98
99
this . pingTimer = clearInterval ( this . pingTimer ) ;
99
100
this . stalledTimer = clearInterval ( this . stalledTimer ) ;
100
101
101
- this . id = undefined ; // No session ID yet
102
+ this . # id = undefined ; // No session ID yet
102
103
103
104
if ( this . online === true && this . videoEnabled === true ) {
104
105
if ( typeof host === 'undefined' || host === null ) {
@@ -134,7 +135,7 @@ export default class NexusTalk extends Streamer {
134
135
this . #authorised = false ; // Since connection close, we can't be authorised anymore
135
136
this . #socket = undefined ; // Clear socket object
136
137
this . connected = false ;
137
- this . id = undefined ; // Not an active session anymore
138
+ this . # id = undefined ; // Not an active session anymore
138
139
139
140
if ( hadError === true && this . haveOutputs ( ) === true ) {
140
141
// We still have either active buffering occuring or output streams running
@@ -147,7 +148,7 @@ export default class NexusTalk extends Streamer {
147
148
148
149
close ( stopStreamFirst ) {
149
150
// Close an authenicated socket stream gracefully
150
- if ( this . #socket !== null ) {
151
+ if ( this . #socket !== undefined ) {
151
152
if ( stopStreamFirst === true ) {
152
153
// Send a notifcation to nexus we're finished playback
153
154
this . #stopNexusData( ) ;
@@ -157,7 +158,7 @@ export default class NexusTalk extends Streamer {
157
158
158
159
this . connected = false ;
159
160
this . #socket = undefined ;
160
- this . id = undefined ; // Not an active session anymore
161
+ this . # id = undefined ; // Not an active session anymore
161
162
this . #packets = [ ] ;
162
163
this . #messages = [ ] ;
163
164
}
@@ -171,24 +172,29 @@ export default class NexusTalk extends Streamer {
171
172
// access token has changed so re-authorise
172
173
this . token = deviceData . apiAccess . token ;
173
174
174
- if ( this . #socket !== null ) {
175
+ if ( this . #socket !== undefined ) {
175
176
this . #Authenticate( true ) ; // Update authorisation only if connected
176
177
}
177
178
}
178
179
180
+ if ( this . host !== deviceData . streaming_host ) {
181
+ this . host = deviceData . streaming_host ;
182
+ this ?. log ?. debug && this . log . debug ( 'New host has been requested for connection. Host requested is "%s"' , this . host ) ;
183
+ }
184
+
179
185
// Let our parent handle the remaining updates
180
186
super . update ( deviceData ) ;
181
187
}
182
188
183
189
talkingAudio ( talkingData ) {
184
190
// Encode audio packet for sending to camera
185
191
if ( typeof talkingData === 'object' && this . #protobufNexusTalk !== undefined ) {
186
- let TraitMap = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.StartPlayback ' ) ;
192
+ let TraitMap = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.AudioPayload ' ) ;
187
193
if ( TraitMap !== null ) {
188
194
let encodedData = TraitMap . encode (
189
195
TraitMap . fromObject ( {
190
196
payload : talkingData ,
191
- sessionId : this . id ,
197
+ sessionId : this . # id,
192
198
codec : 'SPEEX' ,
193
199
sampleRate : 16000 ,
194
200
} ) ,
@@ -227,12 +233,12 @@ export default class NexusTalk extends Streamer {
227
233
}
228
234
229
235
#stopNexusData( ) {
230
- if ( this . id !== undefined && this . #protobufNexusTalk !== undefined ) {
236
+ if ( this . # id !== undefined && this . #protobufNexusTalk !== undefined ) {
231
237
let TraitMap = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.StopPlayback' ) ;
232
238
if ( TraitMap !== null ) {
233
239
let encodedData = TraitMap . encode (
234
240
TraitMap . fromObject ( {
235
- sessionId : this . id ,
241
+ sessionId : this . # id,
236
242
} ) ,
237
243
) . finish ( ) ;
238
244
this . #sendMessage( PacketType . STOP_PLAYBACK , encodedData ) ;
@@ -241,7 +247,7 @@ export default class NexusTalk extends Streamer {
241
247
}
242
248
243
249
#sendMessage( type , data ) {
244
- if ( this . #socket === null || this . #socket . readyState !== 'open' || ( type !== PacketType . HELLO && this . #authorised === false ) ) {
250
+ if ( this . #socket? .readyState !== 'open' || ( type !== PacketType . HELLO && this . #authorised === false ) ) {
245
251
// We're not connect and/or authorised yet, so 'cache' message for processing once this occurs
246
252
this . #messages. push ( { type : type , data : data } ) ;
247
253
return ;
@@ -358,11 +364,11 @@ export default class NexusTalk extends Streamer {
358
364
} ) ;
359
365
360
366
// Since this is the beginning of playback, clear any active buffers contents
361
- this . id = decodedMessage . sessionId ;
367
+ this . # id = decodedMessage . sessionId ;
362
368
this . #packets = [ ] ;
363
369
this . #messages = [ ] ;
364
370
365
- this ?. log ?. debug && this . log . debug ( 'Playback started from "%s" with session ID "%s"' , this . host , this . id ) ;
371
+ this ?. log ?. debug && this . log . debug ( 'Playback started from "%s" with session ID "%s"' , this . host , this . # id) ;
366
372
}
367
373
}
368
374
@@ -381,7 +387,7 @@ export default class NexusTalk extends Streamer {
381
387
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
382
388
this . #socket &&
383
389
this . #socket. on ( 'close' , ( ) => {
384
- this . connect ( this . host ) ; // try reconnection
390
+ this . connect ( ) ; // try reconnection
385
391
} ) ;
386
392
this . close ( false ) ; // Close existing socket
387
393
} , 8000 ) ;
@@ -405,7 +411,7 @@ export default class NexusTalk extends Streamer {
405
411
if ( typeof payload === 'object' && this . #protobufNexusTalk !== undefined ) {
406
412
let decodedMessage = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.PlaybackEnd' ) . decode ( payload ) . toJSON ( ) ;
407
413
408
- if ( this . id !== null && decodedMessage . reason === 'USER_ENDED_SESSION' ) {
414
+ if ( this . # id !== undefined && decodedMessage . reason === 'USER_ENDED_SESSION' ) {
409
415
// Normal playback ended ie: when we stopped playback
410
416
this ?. log ?. debug && this . log . debug ( 'Playback ended on "%s"' , this . host ) ;
411
417
}
@@ -418,7 +424,7 @@ export default class NexusTalk extends Streamer {
418
424
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
419
425
this . #socket &&
420
426
this . #socket. on ( 'close' , ( ) => {
421
- this . connect ( this . host ) ; // try reconnection to existing host
427
+ this . connect ( ) ; // try reconnection to existing host
422
428
} ) ;
423
429
this . close ( false ) ; // Close existing socket
424
430
}
@@ -443,15 +449,15 @@ export default class NexusTalk extends Streamer {
443
449
// Decode talk begin packet
444
450
if ( typeof payload === 'object' && this . #protobufNexusTalk !== undefined ) {
445
451
let decodedMessage = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.TalkbackBegin' ) . decode ( payload ) . toJSON ( ) ;
446
- this ?. log ?. debug && this . log . debug ( 'Talkback started on "%s"' , decodedMessage . deviceId ) ;
452
+ this ?. log ?. debug && this . log . debug ( 'Talkback started to uuid "%s" with id of "%s"' , this . uuid , decodedMessage . deviceId ) ;
447
453
}
448
454
}
449
455
450
456
#handleTalkbackEnd( payload ) {
451
457
// Decode talk end packet
452
458
if ( typeof payload === 'object' && this . #protobufNexusTalk !== undefined ) {
453
459
let decodedMessage = this . #protobufNexusTalk. lookup ( 'nest.nexustalk.v1.TalkbackEnd' ) . decode ( payload ) . toJSON ( ) ;
454
- this ?. log ?. debug && this . log . debug ( 'Talkback ended on "%s"' , decodedMessage . device_id ) ;
460
+ this ?. log ?. debug && this . log . debug ( 'Talkback ended from uuid "%s" with id of "%s" ' , this . uuid , decodedMessage . deviceId ) ;
455
461
}
456
462
}
457
463
0 commit comments