-
Notifications
You must be signed in to change notification settings - Fork 0
/
libchiaki.h
1056 lines (886 loc) · 30.1 KB
/
libchiaki.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef LIBCHIAKI_H
#define LIBCHIAKI_H
#include "chiaki/common.h"
#include "chiaki/log.h" // This only includes common.h - so the common include is technically redundant but that makes this easier to track
#include "chiaki/controller.h" //This only includes common.h and we want most of the stuff in it
#include "chiaki/orientation.h" // only includes controller and common, it's small, and does get used by the GUI
#include "chiaki/seqnum.h" // Only includes common, and is small
#include <sys/socket.h>
#ifdef __cplusplus
extern "C" {
#endif
//thread.h, only including typedefs depended upon by discovery.h and session.h
typedef struct chiaki_thread_t
{
#ifdef _WIN32
HANDLE thread;
ChiakiThreadFunc func;
void *arg;
void *ret;
#else
pthread_t thread;
#endif
} ChiakiThread;
typedef struct chiaki_mutex_t
{
#ifdef _WIN32
CRITICAL_SECTION cs;
#else
pthread_mutex_t mutex;
#endif
} ChiakiMutex;
typedef struct chiaki_cond_t
{
#ifdef _WIN32
CONDITION_VARIABLE cond;
#else
pthread_cond_t cond;
#endif
} ChiakiCond;
typedef struct chiaki_bool_pred_cond_t
{
ChiakiCond cond;
ChiakiMutex mutex;
bool pred;
} ChiakiBoolPredCond;
//stoppipe.h, only including a single struct that discovery.h depends on
typedef struct chiaki_stop_pipe_t
{
#ifdef _WIN32
WSAEVENT event;
#elif defined(__SWITCH__)
// due to a lack pipe/event/socketpair
// on switch env, we use a physical socket
// to send/trigger the cancel signal
struct sockaddr_in addr;
// local stop socket file descriptor
// this fd is audited by 'select' as
// fd_set *readfds
int fd;
#else
int fds[2];
#endif
} ChiakiStopPipe;
//sock.h - discovery.h depends on this
#ifdef _WIN32
#include <winsock2.h>
typedef SOCKET chiaki_socket_t;
#define CHIAKI_SOCKET_IS_INVALID(s) ((s) == INVALID_SOCKET)
#define CHIAKI_INVALID_SOCKET INVALID_SOCKET
#define CHIAKI_SOCKET_CLOSE(s) closesocket(s)
#define CHIAKI_SOCKET_ERROR_FMT "%d"
#define CHIAKI_SOCKET_ERROR_VALUE (WSAGetLastError())
#define CHIAKI_SOCKET_EINPROGRESS (WSAGetLastError() == WSAEWOULDBLOCK)
#else
#include <unistd.h>
#include <errno.h>
typedef int chiaki_socket_t;
#define CHIAKI_SOCKET_IS_INVALID(s) ((s) < 0)
#define CHIAKI_INVALID_SOCKET (-1)
#define CHIAKI_SOCKET_CLOSE(s) close(s)
#define CHIAKI_SOCKET_ERROR_FMT "%s"
#define CHIAKI_SOCKET_ERROR_VALUE (strerror(errno))
#define CHIAKI_SOCKET_EINPROGRESS (errno == EINPROGRESS)
#endif
//discovery.h, determine how much we can remove later
#define CHIAKI_DISCOVERY_PORT_PS4 987
#define CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS4 "00020020"
#define CHIAKI_DISCOVERY_PORT_PS5 9302
#define CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS5 "00030010"
#define CHIAKI_DISCOVERY_PORT_LOCAL_MIN 9303
#define CHIAKI_DISCOVERY_PORT_LOCAL_MAX 9319
typedef enum chiaki_discovery_cmd_t
{
CHIAKI_DISCOVERY_CMD_SRCH,
CHIAKI_DISCOVERY_CMD_WAKEUP
} ChiakiDiscoveryCmd;
typedef struct chiaki_discovery_packet_t
{
ChiakiDiscoveryCmd cmd;
char *protocol_version;
uint64_t user_credential; // for wakeup, this is just the regist key interpreted as hex
} ChiakiDiscoveryPacket;
typedef enum chiaki_discovery_host_state_t
{
CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN,
CHIAKI_DISCOVERY_HOST_STATE_READY,
CHIAKI_DISCOVERY_HOST_STATE_STANDBY
} ChiakiDiscoveryHostState;
/**
* Apply A on all names of string members in ChiakiDiscoveryHost
*/
#define CHIAKI_DISCOVERY_HOST_STRING_FOREACH(A) \
A(host_addr); \
A(system_version); \
A(device_discovery_protocol_version); \
A(host_name); \
A(host_type); \
A(host_id); \
A(running_app_titleid); \
A(running_app_name);
typedef struct chiaki_discovery_host_t
{
// All string members here must be in sync with CHIAKI_DISCOVERY_HOST_STRING_FOREACH
ChiakiDiscoveryHostState state;
uint16_t host_request_port;
#define STRING_MEMBER(name) const char *name
CHIAKI_DISCOVERY_HOST_STRING_FOREACH(STRING_MEMBER)
#undef STRING_MEMBER
} ChiakiDiscoveryHost;
typedef struct chiaki_discovery_t
{
ChiakiLog *log;
chiaki_socket_t socket;
struct sockaddr local_addr;
} ChiakiDiscovery;
CHIAKI_EXPORT const char *chiaki_discovery_host_state_string(ChiakiDiscoveryHostState state);
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_init(ChiakiDiscovery *discovery, ChiakiLog *log, sa_family_t family);
CHIAKI_EXPORT void chiaki_discovery_fini(ChiakiDiscovery *discovery);
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_send(ChiakiDiscovery *discovery, ChiakiDiscoveryPacket *packet, struct sockaddr *addr, size_t addr_size);
// GUI doesn't use this but CLI does
typedef void (*ChiakiDiscoveryCb)(ChiakiDiscoveryHost *host, void *user);
typedef struct chiaki_discovery_thread_t
{
ChiakiDiscovery *discovery;
ChiakiThread thread;
ChiakiStopPipe stop_pipe;
ChiakiDiscoveryCb cb;
void *cb_user;
} ChiakiDiscoveryThread;
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_thread_start(ChiakiDiscoveryThread *thread, ChiakiDiscovery *discovery, ChiakiDiscoveryCb cb, void *cb_user);
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_thread_stop(ChiakiDiscoveryThread *thread);
/**
* Convenience function to send a wakeup packet
* @param discovery Discovery to send the packet on. May be NULL, in which case a new temporary Discovery will be created
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_wakeup(ChiakiLog *log, ChiakiDiscovery *discovery, const char *host, uint64_t user_credential, bool ps5);
/*
discoveryservice.h - only used by discoverymanager.cpp, determine later if we actually need this for a CLI application.
Most functions are used by discoverymanager so we're including the whole file
*/
typedef void (*ChiakiDiscoveryServiceCb)(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user);
typedef struct chiaki_discovery_service_options_t
{
size_t hosts_max;
uint64_t host_drop_pings;
uint64_t ping_ms;
struct sockaddr *send_addr;
size_t send_addr_size;
ChiakiDiscoveryServiceCb cb;
void *cb_user;
} ChiakiDiscoveryServiceOptions;
typedef struct chiaki_discovery_service_host_discovery_info_t
{
uint64_t last_ping_index;
} ChiakiDiscoveryServiceHostDiscoveryInfo;
typedef struct chiaki_discovery_service_t
{
ChiakiLog *log;
ChiakiDiscoveryServiceOptions options;
ChiakiDiscovery discovery;
uint64_t ping_index;
ChiakiDiscoveryHost *hosts;
ChiakiDiscoveryServiceHostDiscoveryInfo *host_discovery_infos;
size_t hosts_count;
ChiakiMutex state_mutex;
ChiakiThread thread;
ChiakiBoolPredCond stop_cond;
} ChiakiDiscoveryService;
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_service_init(ChiakiDiscoveryService *service, ChiakiDiscoveryServiceOptions *options, ChiakiLog *log);
CHIAKI_EXPORT void chiaki_discovery_service_fini(ChiakiDiscoveryService *service);
//audio.h - only one struct is used by streamsession.cpp, no functions. Basically a placeholder we'll pass to functions that insist on it and then ignore the result
typedef struct chiaki_audio_header_t
{
uint8_t channels;
uint8_t bits;
uint32_t rate;
uint32_t frame_size;
uint32_t unknown;
} ChiakiAudioHeader;
//packetstats.h - ChiakiAudioReceiver needs this typedef
typedef struct chiaki_packet_stats_t
{
ChiakiMutex mutex;
// For generations of packets, i.e. where we know the number of expected packets per generation
uint64_t gen_received;
uint64_t gen_lost;
// For sequential packets, i.e. where packets are identified by a sequence number
ChiakiSeqNum16 seq_min; // sequence number that was max at the last reset
ChiakiSeqNum16 seq_max; // currently maximal sequence number
uint64_t seq_received; // total received packets since the last reset
} ChiakiPacketStats;
//audioreceiver.h - session.h and its dependencies have dependencies on this. Another case of a placeholder struct that we won't do anything with because we plan on just dumping audio on the floor
typedef void (*ChiakiAudioSinkHeader)(ChiakiAudioHeader *header, void *user);
typedef void (*ChiakiAudioSinkFrame)(uint8_t *buf, size_t buf_size, void *user);
typedef struct chiaki_audio_sink_t
{
void *user;
ChiakiAudioSinkHeader header_cb;
ChiakiAudioSinkFrame frame_cb;
} ChiakiAudioSink;
typedef struct chiaki_audio_receiver_t
{
struct chiaki_session_t *session;
ChiakiLog *log;
ChiakiMutex mutex;
ChiakiSeqNum16 frame_index_prev;
bool frame_index_startup; // whether frame_index_prev has definitely not wrapped yet
ChiakiPacketStats *packet_stats;
} ChiakiAudioReceiver;
//rpcrypt.h - we need the key size in session.h
#define CHIAKI_RPCRYPT_KEY_SIZE 0x10
typedef struct chiaki_rpcrypt_t
{
ChiakiTarget target;
uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE];
uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE];
} ChiakiRPCrypt;
//ecdh.h - just the typedefs and a single define
#define CHIAKI_ECDH_SECRET_SIZE 32
typedef struct chiaki_ecdh_t
{
// the following lines may lead to memory corruption
// CHIAKI_LIB_ENABLE_MBEDTLS must be defined
// globally (whole project)
#ifdef CHIAKI_LIB_ENABLE_MBEDTLS
// mbedtls ecdh context
mbedtls_ecdh_context ctx;
// deterministic random bit generator
mbedtls_ctr_drbg_context drbg;
#else
struct ec_group_st *group;
struct ec_key_st *key_local;
#endif
} ChiakiECDH;
//ctrl.h - session.h depends on this typedef
typedef struct chiaki_ctrl_message_queue_t ChiakiCtrlMessageQueue;
struct chiaki_ctrl_message_queue_t
{
ChiakiCtrlMessageQueue *next;
uint16_t type;
uint8_t *payload;
size_t payload_size;
};
typedef struct chiaki_ctrl_t
{
struct chiaki_session_t *session;
ChiakiThread thread;
bool should_stop;
bool login_pin_entered;
uint8_t *login_pin;
size_t login_pin_size;
ChiakiCtrlMessageQueue *msg_queue;
ChiakiStopPipe notif_pipe;
ChiakiMutex notif_mutex;
bool login_pin_requested;
chiaki_socket_t sock;
#ifdef __GNUC__
__attribute__((aligned(__alignof__(uint32_t))))
#endif
uint8_t recv_buf[512];
size_t recv_buf_size;
uint64_t crypt_counter_local;
uint64_t crypt_counter_remote;
uint32_t keyboard_text_counter;
} ChiakiCtrl;
//gkcrypt.h - streamconnection and others depend on this
#define CHIAKI_GKCRYPT_BLOCK_SIZE 0x10
#define CHIAKI_GKCRYPT_KEY_BUF_BLOCKS_DEFAULT 0x20 // 2MB
#define CHIAKI_GKCRYPT_GMAC_SIZE 4
#define CHIAKI_GKCRYPT_GMAC_KEY_REFRESH_KEY_POS 45000
#define CHIAKI_GKCRYPT_GMAC_KEY_REFRESH_IV_OFFSET 44910
typedef struct chiaki_key_state_t
{
uint64_t prev;
} ChiakiKeyState;
typedef struct chiaki_gkcrypt_t {
uint8_t index;
uint8_t *key_buf; // circular buffer of the ctr mode key stream
size_t key_buf_size;
size_t key_buf_populated; // size of key_buf that is already populated (on startup)
uint64_t key_buf_key_pos_min; // minimal key pos currently in key_buf
size_t key_buf_start_offset; // offset in key_buf of the minimal key pos
uint64_t last_key_pos; // last key pos that has been requested
bool key_buf_thread_stop;
ChiakiMutex key_buf_mutex;
ChiakiCond key_buf_cond;
ChiakiThread key_buf_thread;
uint8_t iv[CHIAKI_GKCRYPT_BLOCK_SIZE];
uint8_t key_base[CHIAKI_GKCRYPT_BLOCK_SIZE];
uint8_t key_gmac_base[CHIAKI_GKCRYPT_BLOCK_SIZE];
uint8_t key_gmac_current[CHIAKI_GKCRYPT_BLOCK_SIZE];
uint64_t key_gmac_index_current;
ChiakiLog *log;
} ChiakiGKCrypt;
//reorderqueue.h - takion.h depends on this
typedef enum chiaki_reorder_queue_drop_strategy_t {
CHIAKI_REORDER_QUEUE_DROP_STRATEGY_BEGIN, // drop packet with lowest number
CHIAKI_REORDER_QUEUE_DROP_STRATEGY_END // drop packet with highest number
} ChiakiReorderQueueDropStrategy;
typedef struct chiaki_reorder_queue_entry_t
{
void *user;
bool set;
} ChiakiReorderQueueEntry;
typedef void (*ChiakiReorderQueueDropCb)(uint64_t seq_num, void *elem_user, void *cb_user);
typedef bool (*ChiakiReorderQueueSeqNumGt)(uint64_t a, uint64_t b);
typedef bool (*ChiakiReorderQueueSeqNumLt)(uint64_t a, uint64_t b);
typedef uint64_t (*ChiakiReorderQueueSeqNumAdd)(uint64_t a, uint64_t b);
typedef uint64_t (*ChiakiReorderQueueSeqNumSub)(uint64_t a, uint64_t b);
typedef struct chiaki_reorder_queue_t
{
size_t size_exp; // real size = 2^size * sizeof(ChiakiReorderQueueEntry)
ChiakiReorderQueueEntry *queue;
uint64_t begin;
uint64_t count;
ChiakiReorderQueueSeqNumGt seq_num_gt;
ChiakiReorderQueueSeqNumLt seq_num_lt;
ChiakiReorderQueueSeqNumAdd seq_num_add;
ChiakiReorderQueueSeqNumSub seq_num_sub;
ChiakiReorderQueueDropStrategy drop_strategy;
ChiakiReorderQueueDropCb drop_cb;
void *drop_cb_user;
} ChiakiReorderQueue;
//takionsendbuffer.h - takion depends on this
typedef struct chiaki_takion_t ChiakiTakion;
typedef struct chiaki_takion_send_buffer_packet_t
{
ChiakiSeqNum32 seq_num;
uint64_t tries;
uint64_t last_send_ms; // chiaki_time_now_monotonic_ms()
uint8_t *buf;
size_t buf_size;
} ChiakiTakionSendBufferPacket;
typedef struct chiaki_takion_send_buffer_t
{
ChiakiLog *log;
ChiakiTakion *takion;
ChiakiTakionSendBufferPacket *packets;
size_t packets_size; // allocated size
size_t packets_count; // current count
ChiakiMutex mutex;
ChiakiCond cond;
bool should_stop;
ChiakiThread thread;
} ChiakiTakionSendBuffer;
//takion.h - streamconnection and some other things depend on its typedefs
typedef enum chiaki_takion_message_data_type_t {
CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF = 0,
CHIAKI_TAKION_MESSAGE_DATA_TYPE_RUMBLE = 7,
CHIAKI_TAKION_MESSAGE_DATA_TYPE_9 = 9,
CHIAKI_TAKION_MESSAGE_DATA_TYPE_TRIGGER_EFFECTS = 11,
} ChiakiTakionMessageDataType;
typedef struct chiaki_takion_av_packet_t
{
ChiakiSeqNum16 packet_index;
ChiakiSeqNum16 frame_index;
bool uses_nalu_info_structs;
bool is_video;
bool is_haptics;
ChiakiSeqNum16 unit_index;
uint16_t units_in_frame_total; // source + units_in_frame_fec
uint16_t units_in_frame_fec;
uint8_t codec;
uint16_t word_at_0x18;
uint8_t adaptive_stream_index;
uint8_t byte_at_0x2c;
uint64_t key_pos;
uint8_t *data; // not owned
size_t data_size;
} ChiakiTakionAVPacket;
static inline uint8_t chiaki_takion_av_packet_audio_unit_size(ChiakiTakionAVPacket *packet) { return packet->units_in_frame_fec >> 8; }
static inline uint8_t chiaki_takion_av_packet_audio_source_units_count(ChiakiTakionAVPacket *packet) { return packet->units_in_frame_fec & 0xf; }
static inline uint8_t chiaki_takion_av_packet_audio_fec_units_count(ChiakiTakionAVPacket *packet) { return (packet->units_in_frame_fec >> 4) & 0xf; }
typedef ChiakiErrorCode (*ChiakiTakionAVPacketParse)(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size);
typedef struct chiaki_takion_congestion_packet_t
{
uint16_t word_0;
uint16_t received;
uint16_t lost;
} ChiakiTakionCongestionPacket;
typedef enum {
CHIAKI_TAKION_EVENT_TYPE_CONNECTED,
CHIAKI_TAKION_EVENT_TYPE_DISCONNECT,
CHIAKI_TAKION_EVENT_TYPE_DATA,
CHIAKI_TAKION_EVENT_TYPE_DATA_ACK,
CHIAKI_TAKION_EVENT_TYPE_AV
} ChiakiTakionEventType;
typedef struct chiaki_takion_event_t
{
ChiakiTakionEventType type;
union
{
struct
{
ChiakiTakionMessageDataType data_type;
uint8_t *buf;
size_t buf_size;
} data;
struct
{
ChiakiSeqNum32 seq_num;
} data_ack;
ChiakiTakionAVPacket *av;
};
} ChiakiTakionEvent;
typedef void (*ChiakiTakionCallback)(ChiakiTakionEvent *event, void *user);
typedef struct chiaki_takion_connect_info_t
{
ChiakiLog *log;
struct sockaddr *sa;
size_t sa_len;
bool ip_dontfrag;
ChiakiTakionCallback cb;
void *cb_user;
bool enable_crypt;
bool enable_dualsense;
uint8_t protocol_version;
} ChiakiTakionConnectInfo;
typedef struct chiaki_takion_postponed_packet_t
{
uint8_t *buf;
size_t buf_size;
} ChiakiTakionPostponedPacket;
struct chiaki_takion_t
{
ChiakiLog *log;
uint8_t version;
/**
* Whether encryption should be used.
*
* If false, encryption and MACs are disabled completely.
*
* If true, encryption and MACs will be used depending on whether gkcrypt_local and gkcrypt_remote are non-null, respectively.
* However, if gkcrypt_remote is null, only control data packets are passed to the callback and all other packets are postponed until
* gkcrypt_remote is set, so it has been set, so eventually all MACs will be checked.
*/
bool enable_crypt;
/**
* Array to be temporarily allocated when non-data packets come, enable_crypt is true, but gkcrypt_remote is NULL
* to not ignore any MACs in this period.
*/
struct chiaki_takion_postponed_packet_t *postponed_packets;
size_t postponed_packets_size;
size_t postponed_packets_count;
ChiakiGKCrypt *gkcrypt_local; // if NULL (default), no gmac is calculated and nothing is encrypted
uint64_t key_pos_local;
ChiakiMutex gkcrypt_local_mutex;
ChiakiGKCrypt *gkcrypt_remote; // if NULL (default), remote gmacs are IGNORED (!) and everything is expected to be unencrypted
ChiakiReorderQueue data_queue;
ChiakiTakionSendBuffer send_buffer;
ChiakiTakionCallback cb;
void *cb_user;
chiaki_socket_t sock;
ChiakiThread thread;
ChiakiStopPipe stop_pipe;
uint32_t tag_local;
uint32_t tag_remote;
ChiakiSeqNum32 seq_num_local;
ChiakiMutex seq_num_local_mutex;
/**
* Advertised Receiver Window Credit
*/
uint32_t a_rwnd;
ChiakiTakionAVPacketParse av_packet_parse;
ChiakiKeyState key_state;
bool enable_dualsense;
};
//videoprofile.h - videoreceiveer.h depends on this typedef
typedef struct chiaki_video_profile_t
{
unsigned int width;
unsigned int height;
size_t header_sz;
uint8_t *header;
} ChiakiVideoProfile;
//frameprocessor.h - videoreceiver.h depends on these typedefs
typedef struct chiaki_stream_stats_t
{
uint64_t frames;
uint64_t bytes;
} ChiakiStreamStats;
struct chiaki_frame_unit_t;
typedef struct chiaki_frame_unit_t ChiakiFrameUnit;
typedef struct chiaki_frame_processor_t
{
ChiakiLog *log;
uint8_t *frame_buf;
size_t frame_buf_size;
size_t buf_size_per_unit;
size_t buf_stride_per_unit;
unsigned int units_source_expected;
unsigned int units_fec_expected;
unsigned int units_source_received;
unsigned int units_fec_received;
ChiakiFrameUnit *unit_slots;
size_t unit_slots_size;
bool flushed; // whether we have already flushed the current frame, i.e. are only interested in stats, not data.
ChiakiStreamStats stream_stats;
} ChiakiFrameProcessor;
//videoreceiver.h - placeholder typedef that we'll just ignore the contents of
#define CHIAKI_VIDEO_PROFILES_MAX 8
typedef struct chiaki_video_receiver_t
{
struct chiaki_session_t *session;
ChiakiLog *log;
ChiakiVideoProfile profiles[CHIAKI_VIDEO_PROFILES_MAX];
size_t profiles_count;
int profile_cur; // < 1 if no profile selected yet, else index in profiles
int32_t frame_index_cur; // frame that is currently being filled
int32_t frame_index_prev; // last frame that has been at least partially decoded
int32_t frame_index_prev_complete; // last frame that has been completely decoded
ChiakiFrameProcessor frame_processor;
ChiakiPacketStats *packet_stats;
} ChiakiVideoReceiver;
//feedback.h - feedbacksender needs a typedef here but we also might want FeedbackState just in case
typedef struct chiaki_feedback_state_t
{
float gyro_x, gyro_y, gyro_z;
float accel_x, accel_y, accel_z;
float orient_x, orient_y, orient_z, orient_w;
int16_t left_x;
int16_t left_y;
int16_t right_x;
int16_t right_y;
} ChiakiFeedbackState;
#define CHIAKI_HISTORY_EVENT_SIZE_MAX 0x5
typedef struct chiaki_feedback_history_event_t
{
uint8_t buf[CHIAKI_HISTORY_EVENT_SIZE_MAX];
size_t len;
} ChiakiFeedbackHistoryEvent;
typedef struct chiaki_feedback_history_buffer_t
{
ChiakiFeedbackHistoryEvent *events;
size_t size;
size_t begin;
size_t len;
} ChiakiFeedbackHistoryBuffer;
//feedbacksender.h - streamconnection.h depends on this typedef
typedef struct chiaki_feedback_sender_t
{
ChiakiLog *log;
ChiakiTakion *takion;
ChiakiThread thread;
ChiakiSeqNum16 state_seq_num;
ChiakiSeqNum16 history_seq_num;
ChiakiFeedbackHistoryBuffer history_buf;
bool should_stop;
ChiakiControllerState controller_state_prev;
ChiakiControllerState controller_state;
bool controller_state_changed;
ChiakiMutex state_mutex;
ChiakiCond state_cond;
} ChiakiFeedbackSender;
//streamconnection.h - session.h depends on this typedef
typedef struct chiaki_stream_connection_t
{
struct chiaki_session_t *session;
ChiakiLog *log;
ChiakiTakion takion;
uint8_t *ecdh_secret;
ChiakiGKCrypt *gkcrypt_local;
ChiakiGKCrypt *gkcrypt_remote;
ChiakiPacketStats packet_stats;
ChiakiAudioReceiver *audio_receiver;
ChiakiVideoReceiver *video_receiver;
ChiakiAudioReceiver *haptics_receiver;
ChiakiFeedbackSender feedback_sender;
/**
* whether feedback_sender is initialized
* only if this is true, feedback_sender may be accessed!
*/
bool feedback_sender_active;
/**
* protects feedback_sender and feedback_sender_active
*/
ChiakiMutex feedback_sender_mutex;
/**
* signaled on change of state_finished or should_stop
*/
ChiakiCond state_cond;
/**
* protects state, state_finished, state_failed and should_stop
*/
ChiakiMutex state_mutex;
int state;
bool state_finished;
bool state_failed;
bool should_stop;
bool remote_disconnected;
char *remote_disconnect_reason;
} ChiakiStreamConnection;
/*
* session.h - this has a MASSIVE include tree, so we'll just include its contents and then add minimal typedefs for its dependencies above. We probably need nearly all of it externally.
* Opportunity to slim it down later
*/
#define CHIAKI_RP_APPLICATION_REASON_REGIST_FAILED 0x80108b09
#define CHIAKI_RP_APPLICATION_REASON_INVALID_PSN_ID 0x80108b02
#define CHIAKI_RP_APPLICATION_REASON_IN_USE 0x80108b10
#define CHIAKI_RP_APPLICATION_REASON_CRASH 0x80108b15
#define CHIAKI_RP_APPLICATION_REASON_RP_VERSION 0x80108b11
#define CHIAKI_RP_APPLICATION_REASON_UNKNOWN 0x80108bff
CHIAKI_EXPORT const char *chiaki_rp_application_reason_string(uint32_t reason);
/**
* @return RP-Version string or NULL
*/
CHIAKI_EXPORT const char *chiaki_rp_version_string(ChiakiTarget target);
CHIAKI_EXPORT ChiakiTarget chiaki_rp_version_parse(const char *rp_version_str, bool is_ps5);
#define CHIAKI_RP_DID_SIZE 32
#define CHIAKI_SESSION_ID_SIZE_MAX 80
#define CHIAKI_HANDSHAKE_KEY_SIZE 0x10
typedef struct chiaki_connect_video_profile_t
{
unsigned int width;
unsigned int height;
unsigned int max_fps;
unsigned int bitrate;
ChiakiCodec codec;
} ChiakiConnectVideoProfile;
typedef enum {
// values must not change
CHIAKI_VIDEO_RESOLUTION_PRESET_360p = 1,
CHIAKI_VIDEO_RESOLUTION_PRESET_540p = 2,
CHIAKI_VIDEO_RESOLUTION_PRESET_720p = 3,
CHIAKI_VIDEO_RESOLUTION_PRESET_1080p = 4
} ChiakiVideoResolutionPreset;
typedef enum {
// values must not change
CHIAKI_VIDEO_FPS_PRESET_30 = 30,
CHIAKI_VIDEO_FPS_PRESET_60 = 60
} ChiakiVideoFPSPreset;
CHIAKI_EXPORT void chiaki_connect_video_profile_preset(ChiakiConnectVideoProfile *profile, ChiakiVideoResolutionPreset resolution, ChiakiVideoFPSPreset fps);
#define CHIAKI_SESSION_AUTH_SIZE 0x10
typedef struct chiaki_connect_info_t
{
bool ps5;
const char *host; // null terminated
char regist_key[CHIAKI_SESSION_AUTH_SIZE]; // must be completely filled (pad with \0)
uint8_t morning[0x10];
ChiakiConnectVideoProfile video_profile;
bool video_profile_auto_downgrade; // Downgrade video_profile if server does not seem to support it.
bool enable_keyboard;
bool enable_dualsense;
} ChiakiConnectInfo;
typedef enum {
CHIAKI_QUIT_REASON_NONE,
CHIAKI_QUIT_REASON_STOPPED,
CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN,
CHIAKI_QUIT_REASON_SESSION_REQUEST_CONNECTION_REFUSED,
CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_IN_USE,
CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_CRASH,
CHIAKI_QUIT_REASON_SESSION_REQUEST_RP_VERSION_MISMATCH,
CHIAKI_QUIT_REASON_CTRL_UNKNOWN,
CHIAKI_QUIT_REASON_CTRL_CONNECT_FAILED,
CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED,
CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN,
CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED,
CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN, // like REMOTE_DISCONNECTED, but because the server shut down
} ChiakiQuitReason;
CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason);
static inline bool chiaki_quit_reason_is_error(ChiakiQuitReason reason)
{
return reason != CHIAKI_QUIT_REASON_STOPPED && reason != CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN;
}
typedef struct chiaki_quit_event_t
{
ChiakiQuitReason reason;
const char *reason_str;
} ChiakiQuitEvent;
typedef struct chiaki_keyboard_event_t
{
const char *text_str;
} ChiakiKeyboardEvent;
typedef struct chiaki_audio_stream_info_event_t
{
ChiakiAudioHeader audio_header;
} ChiakiAudioStreamInfoEvent;
typedef struct chiaki_rumble_event_t
{
uint8_t unknown;
uint8_t left; // low-frequency
uint8_t right; // high-frequency
} ChiakiRumbleEvent;
typedef struct chiaki_trigger_effects_event_t
{
uint8_t type_left;
uint8_t type_right;
uint8_t left[10];
uint8_t right[10];
} ChiakiTriggerEffectsEvent;
typedef enum {
CHIAKI_EVENT_CONNECTED,
CHIAKI_EVENT_LOGIN_PIN_REQUEST,
CHIAKI_EVENT_KEYBOARD_OPEN,
CHIAKI_EVENT_KEYBOARD_TEXT_CHANGE,
CHIAKI_EVENT_KEYBOARD_REMOTE_CLOSE,
CHIAKI_EVENT_RUMBLE,
CHIAKI_EVENT_QUIT,
CHIAKI_EVENT_TRIGGER_EFFECTS,
} ChiakiEventType;
typedef struct chiaki_event_t
{
ChiakiEventType type;
union
{
ChiakiQuitEvent quit;
ChiakiKeyboardEvent keyboard;
ChiakiRumbleEvent rumble;
ChiakiTriggerEffectsEvent trigger_effects;
struct
{
bool pin_incorrect; // false on first request, true if the pin entered before was incorrect
} login_pin_request;
};
} ChiakiEvent;
typedef void (*ChiakiEventCallback)(ChiakiEvent *event, void *user);
/**
* buf will always have an allocated padding of at least CHIAKI_VIDEO_BUFFER_PADDING_SIZE after buf_size
* @return whether the sample was successfully pushed into the decoder. On false, a corrupt frame will be reported to get a new keyframe.
*/
typedef bool (*ChiakiVideoSampleCallback)(uint8_t *buf, size_t buf_size, void *user);
typedef struct chiaki_session_t
{
struct
{
bool ps5;
struct addrinfo *host_addrinfos;
struct addrinfo *host_addrinfo_selected;
char hostname[256];
char regist_key[CHIAKI_RPCRYPT_KEY_SIZE];
uint8_t morning[CHIAKI_RPCRYPT_KEY_SIZE];
uint8_t did[CHIAKI_RP_DID_SIZE];
ChiakiConnectVideoProfile video_profile;
bool video_profile_auto_downgrade;
bool enable_keyboard;
bool enable_dualsense;
} connect_info;
ChiakiTarget target;
uint8_t nonce[CHIAKI_RPCRYPT_KEY_SIZE];
ChiakiRPCrypt rpcrypt;
char session_id[CHIAKI_SESSION_ID_SIZE_MAX]; // zero-terminated
uint8_t handshake_key[CHIAKI_HANDSHAKE_KEY_SIZE];
uint32_t mtu_in;
uint32_t mtu_out;
uint64_t rtt_us;
ChiakiECDH ecdh;
ChiakiQuitReason quit_reason;
char *quit_reason_str; // additional reason string from remote
ChiakiEventCallback event_cb;
void *event_cb_user;
ChiakiVideoSampleCallback video_sample_cb;
void *video_sample_cb_user;
ChiakiAudioSink audio_sink;
ChiakiAudioSink haptics_sink;
ChiakiThread session_thread;
ChiakiCond state_cond;
ChiakiMutex state_mutex;
ChiakiStopPipe stop_pipe;
bool should_stop;
bool ctrl_failed;
bool ctrl_session_id_received;
bool ctrl_login_pin_requested;
bool login_pin_entered;
uint8_t *login_pin;
size_t login_pin_size;
ChiakiCtrl ctrl;
ChiakiLog *log;
ChiakiStreamConnection stream_connection;
ChiakiControllerState controller_state;
} ChiakiSession;
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info, ChiakiLog *log);
CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_start(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_stop(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_set_controller_state(ChiakiSession *session, ChiakiControllerState *state);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_set_login_pin(ChiakiSession *session, const uint8_t *pin, size_t pin_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_goto_bed(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_keyboard_set_text(ChiakiSession *session, const char *text);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_keyboard_reject(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_keyboard_accept(ChiakiSession *session);
static inline void chiaki_session_set_event_cb(ChiakiSession *session, ChiakiEventCallback cb, void *user)
{
session->event_cb = cb;
session->event_cb_user = user;
}
static inline void chiaki_session_set_video_sample_cb(ChiakiSession *session, ChiakiVideoSampleCallback cb, void *user)
{
session->video_sample_cb = cb;
session->video_sample_cb_user = user;
}
/**
* @param sink contents are copied
*/
static inline void chiaki_session_set_audio_sink(ChiakiSession *session, ChiakiAudioSink *sink)
{
session->audio_sink = *sink;
}
/**
* @param sink contents are copied
*/
static inline void chiaki_session_set_haptics_sink(ChiakiSession *session, ChiakiAudioSink *sink)
{
session->haptics_sink = *sink;
}
//regist.h - this has a really deep include tree so we'll include its contents but not include the original header which will pull in a bunch of things we do not want
#define CHIAKI_PSN_ACCOUNT_ID_SIZE 8
typedef struct chiaki_regist_info_t
{
ChiakiTarget target;
const char *host;
bool broadcast;
/**
* may be null, in which case psn_account_id will be used
*/
const char *psn_online_id;
/**
* will be used if psn_online_id is null, for PS4 >= 7.0
*/
uint8_t psn_account_id[CHIAKI_PSN_ACCOUNT_ID_SIZE];