13
13
#include "https_client.h"
14
14
#include "common.h"
15
15
#include "esp_log.h"
16
+ #include <cJSON.h>
16
17
17
- #define TAG "OPENAI_SIGNALING"
18
+ #define TAG "OPENAI_SIGNALING"
18
19
19
- #define OPENAI_REALTIME_URL "https://api.openai.com/v1/realtime?model=gpt-4o-mini-realtime-preview-2024-12-17"
20
+ // Prefer to use mini model currently
21
+ #define OPENAI_REALTIME_MODEL "gpt-4o-mini-realtime-preview-2024-12-17"
22
+ #define OPENAI_REALTIME_URL "https://api.openai.com/v1/realtime?model=" OPENAI_REALTIME_MODEL
20
23
21
24
#define SAFE_FREE (p ) if (p) { \
22
25
free(p); \
23
26
p = NULL; \
24
27
}
25
28
29
+ #define GET_KEY_END (str , key ) get_key_end(str, key, sizeof(key) - 1)
30
+
26
31
typedef struct {
27
32
esp_peer_signaling_cfg_t cfg ;
28
33
uint8_t * remote_sdp ;
29
34
int remote_sdp_size ;
35
+ char * ephemeral_token ;
30
36
} openai_signaling_t ;
31
37
38
+ static char * get_key_end (char * str , char * key , int len )
39
+ {
40
+ char * p = strstr (str , key );
41
+ if (p == NULL ) {
42
+ return NULL ;
43
+ }
44
+ return p + len ;
45
+ }
46
+
47
+ static void session_answer (http_resp_t * resp , void * ctx )
48
+ {
49
+ openai_signaling_t * sig = (openai_signaling_t * )ctx ;
50
+ char * token = GET_KEY_END ((char * )resp -> data , "\"client_secret\"" );
51
+ if (token == NULL ) {
52
+ return ;
53
+ }
54
+ char * secret = GET_KEY_END (token , "\"value\"" );
55
+ if (secret == NULL ) {
56
+ return ;
57
+ }
58
+ char * s = strchr (secret , '"' );
59
+ if (s == NULL ) {
60
+ return ;
61
+ }
62
+ s ++ ;
63
+ char * e = strchr (s , '"' );
64
+ * e = 0 ;
65
+ sig -> ephemeral_token = strdup (s );
66
+ * e = '"' ;
67
+ }
68
+
69
+ static void get_ephemeral_token (openai_signaling_t * sig , char * token , char * voice )
70
+ {
71
+ char content_type [32 ] = "Content-Type: application/json" ;
72
+ int len = strlen ("Authorization: Bearer " ) + strlen (token ) + 1 ;
73
+ char auth [len ];
74
+ snprintf (auth , len , "Authorization: Bearer %s" , token );
75
+ char * header [] = {
76
+ content_type ,
77
+ auth ,
78
+ NULL ,
79
+ };
80
+ cJSON * root = cJSON_CreateObject ();
81
+ cJSON_AddStringToObject (root , "model" , OPENAI_REALTIME_MODEL );
82
+ cJSON * modalities = cJSON_CreateArray ();
83
+ cJSON_AddItemToArray (modalities , cJSON_CreateString ("text" ));
84
+ cJSON_AddItemToArray (modalities , cJSON_CreateString ("audio" ));
85
+ cJSON_AddItemToObject (root , "modalities" , modalities );
86
+ cJSON_AddStringToObject (root , "voice" , voice );
87
+ char * json_string = cJSON_Print (root );
88
+ if (json_string ) {
89
+ https_post ("https://api.openai.com/v1/realtime/sessions" , header , json_string , NULL , session_answer , sig );
90
+ free (json_string );
91
+ }
92
+ cJSON_Delete (root );
93
+ }
94
+
32
95
static int openai_signaling_start (esp_peer_signaling_cfg_t * cfg , esp_peer_signaling_handle_t * h )
33
96
{
34
97
openai_signaling_t * sig = (openai_signaling_t * )calloc (1 , sizeof (openai_signaling_t ));
35
98
if (sig == NULL ) {
36
99
return ESP_PEER_ERR_NO_MEM ;
37
100
}
101
+ openai_signaling_cfg_t * openai_cfg = (openai_signaling_cfg_t * )cfg -> extra_cfg ;
38
102
sig -> cfg = * cfg ;
103
+ // alloy, ash, ballad, coral, echo sage, shimmer and verse
104
+ get_ephemeral_token (sig , openai_cfg -> token , openai_cfg -> voice ? openai_cfg -> voice : "alloy" );
105
+ if (sig -> ephemeral_token == NULL ) {
106
+ free (sig );
107
+ return ESP_PEER_ERR_NOT_SUPPORT ;
108
+ }
39
109
* h = sig ;
40
110
esp_peer_signaling_ice_info_t ice_info = {
41
111
.is_initiator = true,
@@ -67,9 +137,10 @@ static int openai_signaling_send_msg(esp_peer_signaling_handle_t h, esp_peer_sig
67
137
} else if (msg -> type == ESP_PEER_SIGNALING_MSG_SDP ) {
68
138
printf ("Receive local SDP\n" );
69
139
char content_type [32 ] = "Content-Type: application/sdp" ;
70
- int len = strlen ("Authorization: Bearer " ) + strlen ((char * )sig -> cfg .extra_cfg ) + 1 ;
140
+ char * token = sig -> ephemeral_token ;
141
+ int len = strlen ("Authorization: Bearer " ) + strlen (token ) + 1 ;
71
142
char auth [len ];
72
- snprintf (auth , len , "Authorization: Bearer %s" , ( char * ) sig -> cfg . extra_cfg );
143
+ snprintf (auth , len , "Authorization: Bearer %s" , token );
73
144
char * header [] = {
74
145
content_type ,
75
146
auth ,
@@ -95,6 +166,7 @@ static int openai_signaling_stop(esp_peer_signaling_handle_t h)
95
166
openai_signaling_t * sig = (openai_signaling_t * )h ;
96
167
sig -> cfg .on_close (sig -> cfg .ctx );
97
168
SAFE_FREE (sig -> remote_sdp );
169
+ SAFE_FREE (sig -> ephemeral_token );
98
170
SAFE_FREE (sig );
99
171
return 0 ;
100
172
}
0 commit comments