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