1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-secure-streams-avs 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2019-2020 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * This sends a canned WAV and received (and discards) the mp3 response. 10d4afb5ceSopenharmony_ci * However it rate-limits the response reception to manage a small ringbuffer 11d4afb5ceSopenharmony_ci * using ss / h2 flow control apis, reflecting consumption at 64kbps and only 12d4afb5ceSopenharmony_ci * and 8KB buffer, indtended to model optimizing rx buffering on mp3 playback 13d4afb5ceSopenharmony_ci * on a constrained device. 14d4afb5ceSopenharmony_ci */ 15d4afb5ceSopenharmony_ci 16d4afb5ceSopenharmony_ci#include <libwebsockets.h> 17d4afb5ceSopenharmony_ci#include <string.h> 18d4afb5ceSopenharmony_ci#include <sys/types.h> 19d4afb5ceSopenharmony_ci#include <sys/stat.h> 20d4afb5ceSopenharmony_ci#if !defined(WIN32) 21d4afb5ceSopenharmony_ci#include <unistd.h> 22d4afb5ceSopenharmony_ci#endif 23d4afb5ceSopenharmony_ci#include <assert.h> 24d4afb5ceSopenharmony_ci#include <fcntl.h> 25d4afb5ceSopenharmony_ci 26d4afb5ceSopenharmony_ciextern int interrupted, bad; 27d4afb5ceSopenharmony_cistatic struct lws_ss_handle *hss_avs_event, *hss_avs_sync; 28d4afb5ceSopenharmony_cistatic uint8_t *wav; 29d4afb5ceSopenharmony_cistatic size_t wav_len; 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_citypedef struct ss_avs_event { 32d4afb5ceSopenharmony_ci struct lws_ss_handle *ss; 33d4afb5ceSopenharmony_ci void *opaque_data; 34d4afb5ceSopenharmony_ci /* ... application specific state ... */ 35d4afb5ceSopenharmony_ci struct lejp_ctx jctx; 36d4afb5ceSopenharmony_ci} ss_avs_event_t; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_citypedef struct ss_avs_metadata { 39d4afb5ceSopenharmony_ci struct lws_ss_handle *ss; 40d4afb5ceSopenharmony_ci void *opaque_data; 41d4afb5ceSopenharmony_ci /* ... application specific state ... */ 42d4afb5ceSopenharmony_ci struct lejp_ctx jctx; 43d4afb5ceSopenharmony_ci size_t pos; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci /* 46d4afb5ceSopenharmony_ci * We simulate a ringbuffer that is used up by a sul at 64Kbit/sec 47d4afb5ceSopenharmony_ci * rate, and managed at the same rate using tx credit 48d4afb5ceSopenharmony_ci */ 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul; 51d4afb5ceSopenharmony_ci uint8_t buf[256 * 1024]; /* to test rate-limiting, set to 8 * 1024 */ 52d4afb5ceSopenharmony_ci int head; 53d4afb5ceSopenharmony_ci int tail; 54d4afb5ceSopenharmony_ci 55d4afb5ceSopenharmony_ci char filled; 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci} ss_avs_metadata_t; 58d4afb5ceSopenharmony_ci 59d4afb5ceSopenharmony_cistatic const char *metadata = "{" 60d4afb5ceSopenharmony_ci "\"event\": {" 61d4afb5ceSopenharmony_ci "\"header\": {" 62d4afb5ceSopenharmony_ci "\"namespace\": \"SpeechRecognizer\"," 63d4afb5ceSopenharmony_ci "\"name\": \"Recognize\"," 64d4afb5ceSopenharmony_ci "\"messageId\": \"message-123\"," 65d4afb5ceSopenharmony_ci "\"dialogRequestId\": \"dialog-request-321\"" 66d4afb5ceSopenharmony_ci "}," 67d4afb5ceSopenharmony_ci "\"payload\": {" 68d4afb5ceSopenharmony_ci "\"profile\":" "\"CLOSE_TALK\"," 69d4afb5ceSopenharmony_ci "\"format\":" "\"AUDIO_L16_RATE_16000_CHANNELS_1\"" 70d4afb5ceSopenharmony_ci "}" 71d4afb5ceSopenharmony_ci "}" 72d4afb5ceSopenharmony_ci"}"; 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci/* 75d4afb5ceSopenharmony_ci * avs metadata 76d4afb5ceSopenharmony_ci */ 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_cistatic void 79d4afb5ceSopenharmony_ciuse_buffer_50ms(lws_sorted_usec_list_t *sul) 80d4afb5ceSopenharmony_ci{ 81d4afb5ceSopenharmony_ci ss_avs_metadata_t *m = lws_container_of(sul, ss_avs_metadata_t, sul); 82d4afb5ceSopenharmony_ci struct lws_context *context = (struct lws_context *)m->opaque_data; 83d4afb5ceSopenharmony_ci size_t n; 84d4afb5ceSopenharmony_ci int e; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci /* 87d4afb5ceSopenharmony_ci * Use up 50ms-worth (8KB / 20) == 401 bytes of buffered data 88d4afb5ceSopenharmony_ci */ 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_ci /* remaining data in buffer */ 91d4afb5ceSopenharmony_ci n = ((size_t)(m->head - m->tail) % sizeof(m->buf)); 92d4afb5ceSopenharmony_ci lwsl_info("%s: avail %d\n", __func__, (int)n); 93d4afb5ceSopenharmony_ci 94d4afb5ceSopenharmony_ci if (n < 401) 95d4afb5ceSopenharmony_ci lwsl_err("%s: underrun\n", __func__); 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci m->tail = ((size_t)m->tail + 401) % sizeof(m->buf); 98d4afb5ceSopenharmony_ci n = ((size_t)(m->head - m->tail) % sizeof(m->buf)); 99d4afb5ceSopenharmony_ci 100d4afb5ceSopenharmony_ci e = lws_ss_get_est_peer_tx_credit(m->ss); 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci lwsl_info("%s: avail after: %d, curr est %d\n", __func__, (int)n, e); 103d4afb5ceSopenharmony_ci 104d4afb5ceSopenharmony_ci if (n < (sizeof(m->buf) * 2) / 3 && e < (int)(sizeof(m->buf) - 1 - n)) { 105d4afb5ceSopenharmony_ci lwsl_info("%s: requesting additional %d\n", __func__, 106d4afb5ceSopenharmony_ci (int)sizeof(m->buf) - 1 - e - (int)n); 107d4afb5ceSopenharmony_ci lws_ss_add_peer_tx_credit(m->ss, (int32_t)((int)sizeof(m->buf) - 1 - e - (int)n)); 108d4afb5ceSopenharmony_ci } 109d4afb5ceSopenharmony_ci 110d4afb5ceSopenharmony_ci lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms, 111d4afb5ceSopenharmony_ci 50 * LWS_US_PER_MS); 112d4afb5ceSopenharmony_ci} 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 115d4afb5ceSopenharmony_ciss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 116d4afb5ceSopenharmony_ci{ 117d4afb5ceSopenharmony_ci ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj; 118d4afb5ceSopenharmony_ci struct lws_context *context = (struct lws_context *)m->opaque_data; 119d4afb5ceSopenharmony_ci size_t n, n1; 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci lwsl_notice("%s: rideshare %s, len %d, flags 0x%x\n", __func__, 122d4afb5ceSopenharmony_ci lws_ss_rideshare(m->ss), (int)len, flags); 123d4afb5ceSopenharmony_ci#if 0 124d4afb5ceSopenharmony_ci lwsl_hexdump_warn(buf, len); 125d4afb5ceSopenharmony_ci#endif 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci n = sizeof(m->buf) - ((size_t)(m->head - m->tail) % sizeof(m->buf)); 128d4afb5ceSopenharmony_ci lwsl_info("%s: len %d, buf h %d, t %d, space %d\n", __func__, 129d4afb5ceSopenharmony_ci (int)len, (int)m->head, (int)m->tail, (int)n); 130d4afb5ceSopenharmony_ci lws_ss_get_est_peer_tx_credit(m->ss); 131d4afb5ceSopenharmony_ci if (len > n) { 132d4afb5ceSopenharmony_ci lwsl_err("%s: bad len: len %d, n %d\n", __func__, (int)len, (int)n); 133d4afb5ceSopenharmony_ci assert(0); 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci return 1; 136d4afb5ceSopenharmony_ci } 137d4afb5ceSopenharmony_ci 138d4afb5ceSopenharmony_ci if (m->head < m->tail) /* |****h-------t**| */ 139d4afb5ceSopenharmony_ci memcpy(&m->buf[m->head], buf, len); 140d4afb5ceSopenharmony_ci else { /* |---t*****h-----| */ 141d4afb5ceSopenharmony_ci n1 = sizeof(m->buf) - (size_t)m->head; 142d4afb5ceSopenharmony_ci if (len < n1) 143d4afb5ceSopenharmony_ci n1 = len; 144d4afb5ceSopenharmony_ci memcpy(&m->buf[m->head], buf, n1); 145d4afb5ceSopenharmony_ci if (n1 != len) 146d4afb5ceSopenharmony_ci memcpy(m->buf, buf, len - n1); 147d4afb5ceSopenharmony_ci } 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci m->head = (((size_t)m->head) + len) % sizeof(m->buf); 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms, 152d4afb5ceSopenharmony_ci 50 * LWS_US_PER_MS); 153d4afb5ceSopenharmony_ci 154d4afb5ceSopenharmony_ci return 0; 155d4afb5ceSopenharmony_ci} 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 158d4afb5ceSopenharmony_ciss_avs_metadata_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, 159d4afb5ceSopenharmony_ci size_t *len, int *flags) 160d4afb5ceSopenharmony_ci{ 161d4afb5ceSopenharmony_ci ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj; 162d4afb5ceSopenharmony_ci //struct lws_context *context = (struct lws_context *)m->opaque_data; 163d4afb5ceSopenharmony_ci size_t tot; 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci if ((long)m->pos < 0) { 166d4afb5ceSopenharmony_ci *len = 0; 167d4afb5ceSopenharmony_ci lwsl_debug("%s: skip tx\n", __func__); 168d4afb5ceSopenharmony_ci return 1; 169d4afb5ceSopenharmony_ci } 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci// lwsl_notice("%s: rideshare '%s'\n", __func__, lws_ss_rideshare(m->ss)); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci if (!strcmp(lws_ss_rideshare(m->ss), "avs_audio")) { 174d4afb5ceSopenharmony_ci /* audio rideshare */ 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci if (!m->pos) 177d4afb5ceSopenharmony_ci *flags |= LWSSS_FLAG_SOM; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci if (*len > wav_len - m->pos) 180d4afb5ceSopenharmony_ci *len = wav_len - m->pos; 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci memcpy(buf, wav + m->pos, *len); 183d4afb5ceSopenharmony_ci m->pos += *len; 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci if (m->pos == wav_len) { 186d4afb5ceSopenharmony_ci *flags |= LWSSS_FLAG_EOM; 187d4afb5ceSopenharmony_ci lwsl_info("%s: tx done\n", __func__); 188d4afb5ceSopenharmony_ci m->pos = (size_t)-1l; /* ban subsequent until new stream */ 189d4afb5ceSopenharmony_ci } else 190d4afb5ceSopenharmony_ci return lws_ss_request_tx(m->ss); 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci lwsl_hexdump_info(buf, *len); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci return 0; 195d4afb5ceSopenharmony_ci } 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci /* metadata part */ 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci tot = strlen(metadata); 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci if (!m->pos) 202d4afb5ceSopenharmony_ci *flags |= LWSSS_FLAG_SOM; 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci if (*len > tot - m->pos) 205d4afb5ceSopenharmony_ci *len = tot - m->pos; 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci memcpy(buf, metadata + m->pos, *len); 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci m->pos += *len; 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci if (m->pos == tot) { 212d4afb5ceSopenharmony_ci *flags |= LWSSS_FLAG_EOM; 213d4afb5ceSopenharmony_ci m->pos = 0; /* for next time */ 214d4afb5ceSopenharmony_ci return lws_ss_request_tx(m->ss); 215d4afb5ceSopenharmony_ci } 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci lwsl_hexdump_info(buf, *len); 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_ci return 0; 220d4afb5ceSopenharmony_ci} 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 223d4afb5ceSopenharmony_ciss_avs_metadata_state(void *userobj, void *sh, 224d4afb5ceSopenharmony_ci lws_ss_constate_t state, lws_ss_tx_ordinal_t ack) 225d4afb5ceSopenharmony_ci{ 226d4afb5ceSopenharmony_ci 227d4afb5ceSopenharmony_ci ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj; 228d4afb5ceSopenharmony_ci // struct lws_context *context = (struct lws_context *)m->opaque_data; 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state), 231d4afb5ceSopenharmony_ci (unsigned int)ack); 232d4afb5ceSopenharmony_ci 233d4afb5ceSopenharmony_ci switch (state) { 234d4afb5ceSopenharmony_ci case LWSSSCS_CREATING: 235d4afb5ceSopenharmony_ci lwsl_user("%s: CREATING\n", __func__); 236d4afb5ceSopenharmony_ci m->pos = 0; 237d4afb5ceSopenharmony_ci return lws_ss_client_connect(m->ss); 238d4afb5ceSopenharmony_ci 239d4afb5ceSopenharmony_ci case LWSSSCS_CONNECTING: 240d4afb5ceSopenharmony_ci break; 241d4afb5ceSopenharmony_ci case LWSSSCS_CONNECTED: 242d4afb5ceSopenharmony_ci return lws_ss_request_tx(m->ss); 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci case LWSSSCS_ALL_RETRIES_FAILED: 245d4afb5ceSopenharmony_ci /* for this demo app, we want to exit on fail to connect */ 246d4afb5ceSopenharmony_ci case LWSSSCS_DISCONNECTED: 247d4afb5ceSopenharmony_ci /* for this demo app, we want to exit after complete flow */ 248d4afb5ceSopenharmony_ci lws_sul_cancel(&m->sul); 249d4afb5ceSopenharmony_ci interrupted = 1; 250d4afb5ceSopenharmony_ci break; 251d4afb5ceSopenharmony_ci case LWSSSCS_DESTROYING: 252d4afb5ceSopenharmony_ci lws_sul_cancel(&m->sul); 253d4afb5ceSopenharmony_ci break; 254d4afb5ceSopenharmony_ci default: 255d4afb5ceSopenharmony_ci break; 256d4afb5ceSopenharmony_ci } 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci return 0; 259d4afb5ceSopenharmony_ci} 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci/* 262d4afb5ceSopenharmony_ci * avs event 263d4afb5ceSopenharmony_ci */ 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 266d4afb5ceSopenharmony_ciss_avs_event_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 267d4afb5ceSopenharmony_ci{ 268d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_NO_LOGS) 269d4afb5ceSopenharmony_ci ss_avs_event_t *m = (ss_avs_event_t *)userobj; 270d4afb5ceSopenharmony_ci // struct lws_context *context = (struct lws_context *)m->opaque_data; 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci lwsl_notice("%s: rideshare %s, len %d, flags 0x%x\n", __func__, 273d4afb5ceSopenharmony_ci lws_ss_rideshare(m->ss), (int)len, flags); 274d4afb5ceSopenharmony_ci#endif 275d4afb5ceSopenharmony_ci// lwsl_hexdump_warn(buf, len); 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci bad = 0; /* for this demo, receiving something here == success */ 278d4afb5ceSopenharmony_ci 279d4afb5ceSopenharmony_ci return 0; 280d4afb5ceSopenharmony_ci} 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 283d4afb5ceSopenharmony_ciss_avs_event_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, 284d4afb5ceSopenharmony_ci size_t *len, int *flags) 285d4afb5ceSopenharmony_ci{ 286d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_NO_LOGS) 287d4afb5ceSopenharmony_ci ss_avs_event_t *m = (ss_avs_event_t *)userobj; 288d4afb5ceSopenharmony_ci lwsl_notice("%s: rideshare %s\n", __func__, lws_ss_rideshare(m->ss)); 289d4afb5ceSopenharmony_ci#endif 290d4afb5ceSopenharmony_ci return 1; /* don't transmit anything */ 291d4afb5ceSopenharmony_ci} 292d4afb5ceSopenharmony_ci 293d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 294d4afb5ceSopenharmony_ciss_avs_event_state(void *userobj, void *sh, 295d4afb5ceSopenharmony_ci lws_ss_constate_t state, lws_ss_tx_ordinal_t ack) 296d4afb5ceSopenharmony_ci{ 297d4afb5ceSopenharmony_ci ss_avs_event_t *m = (ss_avs_event_t *)userobj; 298d4afb5ceSopenharmony_ci struct lws_context *context = (struct lws_context *)m->opaque_data; 299d4afb5ceSopenharmony_ci lws_ss_info_t ssi; 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state), 302d4afb5ceSopenharmony_ci (unsigned int)ack); 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci switch (state) { 305d4afb5ceSopenharmony_ci case LWSSSCS_CREATING: 306d4afb5ceSopenharmony_ci case LWSSSCS_CONNECTING: 307d4afb5ceSopenharmony_ci break; 308d4afb5ceSopenharmony_ci case LWSSSCS_CONNECTED: 309d4afb5ceSopenharmony_ci if (hss_avs_sync) 310d4afb5ceSopenharmony_ci break; 311d4afb5ceSopenharmony_ci 312d4afb5ceSopenharmony_ci lwsl_notice("%s: starting the second avs stream\n", __func__); 313d4afb5ceSopenharmony_ci 314d4afb5ceSopenharmony_ci /* 315d4afb5ceSopenharmony_ci * When we have established the event stream, we must POST 316d4afb5ceSopenharmony_ci * on another stream within 10s 317d4afb5ceSopenharmony_ci */ 318d4afb5ceSopenharmony_ci 319d4afb5ceSopenharmony_ci memset(&ssi, 0, sizeof(ssi)); 320d4afb5ceSopenharmony_ci ssi.handle_offset = offsetof(ss_avs_metadata_t, ss); 321d4afb5ceSopenharmony_ci ssi.opaque_user_data_offset = offsetof(ss_avs_metadata_t, 322d4afb5ceSopenharmony_ci opaque_data); 323d4afb5ceSopenharmony_ci ssi.rx = ss_avs_metadata_rx; 324d4afb5ceSopenharmony_ci ssi.tx = ss_avs_metadata_tx; 325d4afb5ceSopenharmony_ci ssi.state = ss_avs_metadata_state; 326d4afb5ceSopenharmony_ci ssi.user_alloc = sizeof(ss_avs_metadata_t); 327d4afb5ceSopenharmony_ci ssi.streamtype = "avs_metadata"; 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci /* 330d4afb5ceSopenharmony_ci * We want to allow the other side to fill our buffer, but no 331d4afb5ceSopenharmony_ci * more. But it's a bit tricky when the payload is inside 332d4afb5ceSopenharmony_ci * framing like multipart MIME and contains other parts 333d4afb5ceSopenharmony_ci */ 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci /* uncomment to test rate-limiting, doesn't work with AVS servers */ 336d4afb5ceSopenharmony_ci// ssi.manual_initial_tx_credit = 337d4afb5ceSopenharmony_ci// sizeof(((ss_avs_metadata_t *)0)->buf) / 2; 338d4afb5ceSopenharmony_ci 339d4afb5ceSopenharmony_ci if (lws_ss_create(context, 0, &ssi, context, &hss_avs_sync, 340d4afb5ceSopenharmony_ci NULL, NULL)) { 341d4afb5ceSopenharmony_ci lwsl_err("%s: failed to create avs metadata secstream\n", 342d4afb5ceSopenharmony_ci __func__); 343d4afb5ceSopenharmony_ci } 344d4afb5ceSopenharmony_ci break; 345d4afb5ceSopenharmony_ci case LWSSSCS_ALL_RETRIES_FAILED: 346d4afb5ceSopenharmony_ci /* for this demo app, we want to exit on fail to connect */ 347d4afb5ceSopenharmony_ci interrupted = 1; 348d4afb5ceSopenharmony_ci break; 349d4afb5ceSopenharmony_ci case LWSSSCS_DISCONNECTED: 350d4afb5ceSopenharmony_ci break; 351d4afb5ceSopenharmony_ci case LWSSSCS_DESTROYING: 352d4afb5ceSopenharmony_ci lwsl_notice("%s: DESTROYING\n", __func__); 353d4afb5ceSopenharmony_ci if (wav) { 354d4afb5ceSopenharmony_ci free(wav); 355d4afb5ceSopenharmony_ci wav = NULL; 356d4afb5ceSopenharmony_ci } 357d4afb5ceSopenharmony_ci break; 358d4afb5ceSopenharmony_ci default: 359d4afb5ceSopenharmony_ci break; 360d4afb5ceSopenharmony_ci } 361d4afb5ceSopenharmony_ci 362d4afb5ceSopenharmony_ci return 0; 363d4afb5ceSopenharmony_ci} 364d4afb5ceSopenharmony_ci 365d4afb5ceSopenharmony_ciint 366d4afb5ceSopenharmony_ciavs_example_start(struct lws_context *context) 367d4afb5ceSopenharmony_ci{ 368d4afb5ceSopenharmony_ci lws_ss_info_t ssi; 369d4afb5ceSopenharmony_ci struct stat stat; 370d4afb5ceSopenharmony_ci int fd; 371d4afb5ceSopenharmony_ci 372d4afb5ceSopenharmony_ci if (hss_avs_event) 373d4afb5ceSopenharmony_ci return 0; 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci fd = open("./year.wav", O_RDONLY); 376d4afb5ceSopenharmony_ci if (fd < 0) { 377d4afb5ceSopenharmony_ci lwsl_err("%s: failed to open wav file\n", __func__); 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci return 1; 380d4afb5ceSopenharmony_ci } 381d4afb5ceSopenharmony_ci if (fstat(fd, &stat) < 0) { 382d4afb5ceSopenharmony_ci lwsl_err("%s: failed to stat wav file\n", __func__); 383d4afb5ceSopenharmony_ci 384d4afb5ceSopenharmony_ci goto bail; 385d4afb5ceSopenharmony_ci } 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci wav_len = (size_t)stat.st_size; 388d4afb5ceSopenharmony_ci wav = malloc(wav_len); 389d4afb5ceSopenharmony_ci if (!wav) { 390d4afb5ceSopenharmony_ci lwsl_err("%s: failed to alloc wav buffer", __func__); 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci goto bail; 393d4afb5ceSopenharmony_ci } 394d4afb5ceSopenharmony_ci if (read(fd, wav, 395d4afb5ceSopenharmony_ci#if defined(WIN32) 396d4afb5ceSopenharmony_ci (unsigned int) 397d4afb5ceSopenharmony_ci#endif 398d4afb5ceSopenharmony_ci wav_len) != (int)wav_len) { 399d4afb5ceSopenharmony_ci lwsl_err("%s: failed to read wav\n", __func__); 400d4afb5ceSopenharmony_ci 401d4afb5ceSopenharmony_ci goto bail; 402d4afb5ceSopenharmony_ci } 403d4afb5ceSopenharmony_ci close(fd); 404d4afb5ceSopenharmony_ci 405d4afb5ceSopenharmony_ci lwsl_user("%s: Starting AVS stream\n", __func__); 406d4afb5ceSopenharmony_ci 407d4afb5ceSopenharmony_ci /* AVS wants us to establish the long poll event stream first */ 408d4afb5ceSopenharmony_ci 409d4afb5ceSopenharmony_ci memset(&ssi, 0, sizeof(ssi)); 410d4afb5ceSopenharmony_ci ssi.handle_offset = offsetof(ss_avs_event_t, ss); 411d4afb5ceSopenharmony_ci ssi.opaque_user_data_offset = offsetof(ss_avs_event_t, opaque_data); 412d4afb5ceSopenharmony_ci ssi.rx = ss_avs_event_rx; 413d4afb5ceSopenharmony_ci ssi.tx = ss_avs_event_tx; 414d4afb5ceSopenharmony_ci ssi.state = ss_avs_event_state; 415d4afb5ceSopenharmony_ci ssi.user_alloc = sizeof(ss_avs_event_t); 416d4afb5ceSopenharmony_ci ssi.streamtype = "avs_event"; 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci if (lws_ss_create(context, 0, &ssi, context, &hss_avs_event, NULL, NULL)) { 419d4afb5ceSopenharmony_ci lwsl_err("%s: failed to create avs event secure stream\n", 420d4afb5ceSopenharmony_ci __func__); 421d4afb5ceSopenharmony_ci free(wav); 422d4afb5ceSopenharmony_ci wav = NULL; 423d4afb5ceSopenharmony_ci return 1; 424d4afb5ceSopenharmony_ci } 425d4afb5ceSopenharmony_ci 426d4afb5ceSopenharmony_ci return 0; 427d4afb5ceSopenharmony_ci 428d4afb5ceSopenharmony_cibail: 429d4afb5ceSopenharmony_ci close(fd); 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci return 1; 432d4afb5ceSopenharmony_ci} 433