1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-secure-streams-alexa
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
5*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
6*1c60b9acSAndroid Build Coastguard Worker  */
7*1c60b9acSAndroid Build Coastguard Worker 
8*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
9*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
10*1c60b9acSAndroid Build Coastguard Worker #include <sys/types.h>
11*1c60b9acSAndroid Build Coastguard Worker #include <sys/stat.h>
12*1c60b9acSAndroid Build Coastguard Worker #include <unistd.h>
13*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
14*1c60b9acSAndroid Build Coastguard Worker 
15*1c60b9acSAndroid Build Coastguard Worker #include <mpg123.h>
16*1c60b9acSAndroid Build Coastguard Worker 
17*1c60b9acSAndroid Build Coastguard Worker #include "private.h"
18*1c60b9acSAndroid Build Coastguard Worker 
19*1c60b9acSAndroid Build Coastguard Worker struct lws_ss_handle *hss_avs_event, *hss_avs_sync;
20*1c60b9acSAndroid Build Coastguard Worker 
21*1c60b9acSAndroid Build Coastguard Worker /* this is the type for the long poll event channel */
22*1c60b9acSAndroid Build Coastguard Worker 
23*1c60b9acSAndroid Build Coastguard Worker typedef struct ss_avs_event {
24*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ss_handle 	*ss;
25*1c60b9acSAndroid Build Coastguard Worker 	void			*opaque_data;
26*1c60b9acSAndroid Build Coastguard Worker 	/* ... application specific state ... */
27*1c60b9acSAndroid Build Coastguard Worker 
28*1c60b9acSAndroid Build Coastguard Worker 	struct lejp_ctx		jctx;
29*1c60b9acSAndroid Build Coastguard Worker } ss_avs_event_t;
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker enum {
32*1c60b9acSAndroid Build Coastguard Worker 	LAMP3STATE_IDLE,
33*1c60b9acSAndroid Build Coastguard Worker 	LAMP3STATE_SPOOLING,
34*1c60b9acSAndroid Build Coastguard Worker 	LAMP3STATE_DRAINING,
35*1c60b9acSAndroid Build Coastguard Worker };
36*1c60b9acSAndroid Build Coastguard Worker 
37*1c60b9acSAndroid Build Coastguard Worker /* this is the type for the utterance metadata (and audio rideshares) */
38*1c60b9acSAndroid Build Coastguard Worker 
39*1c60b9acSAndroid Build Coastguard Worker typedef struct ss_avs_metadata {
40*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ss_handle 	*ss;
41*1c60b9acSAndroid Build Coastguard Worker 	void			*opaque_data;
42*1c60b9acSAndroid Build Coastguard Worker 	/* ... application specific state ... */
43*1c60b9acSAndroid Build Coastguard Worker 
44*1c60b9acSAndroid Build Coastguard Worker 	struct lws_buflist	*dribble; /* next mp3 data while draining last */
45*1c60b9acSAndroid Build Coastguard Worker 
46*1c60b9acSAndroid Build Coastguard Worker 	struct lejp_ctx		jctx;
47*1c60b9acSAndroid Build Coastguard Worker 	size_t			pos;
48*1c60b9acSAndroid Build Coastguard Worker 	size_t			mp3_in;
49*1c60b9acSAndroid Build Coastguard Worker 	mpg123_handle		*mh;
50*1c60b9acSAndroid Build Coastguard Worker 
51*1c60b9acSAndroid Build Coastguard Worker 	lws_sorted_usec_list_t	sul;
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			stash_eom[16];
54*1c60b9acSAndroid Build Coastguard Worker 
55*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			se_head;
56*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			se_tail;
57*1c60b9acSAndroid Build Coastguard Worker 
58*1c60b9acSAndroid Build Coastguard Worker 	char			mp3_state;
59*1c60b9acSAndroid Build Coastguard Worker 	char			first_mp3;
60*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			mp3_mime_match;
61*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			seen;
62*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			inside_mp3;
63*1c60b9acSAndroid Build Coastguard Worker 
64*1c60b9acSAndroid Build Coastguard Worker } ss_avs_metadata_t;
65*1c60b9acSAndroid Build Coastguard Worker 
66*1c60b9acSAndroid Build Coastguard Worker /*
67*1c60b9acSAndroid Build Coastguard Worker  * The remote server only seems to give us a budget of 10s to consume the
68*1c60b9acSAndroid Build Coastguard Worker  * results, after that it doesn't drop the stream, but doesn't send us anything
69*1c60b9acSAndroid Build Coastguard Worker  * further on it.
70*1c60b9acSAndroid Build Coastguard Worker  *
71*1c60b9acSAndroid Build Coastguard Worker  * This makes it impossible to optimize buffering for incoming mp3 since we
72*1c60b9acSAndroid Build Coastguard Worker  * have to go ahead and take it before the 10s is up.
73*1c60b9acSAndroid Build Coastguard Worker  */
74*1c60b9acSAndroid Build Coastguard Worker 
75*1c60b9acSAndroid Build Coastguard Worker #define MAX_MP3_IN_BUFFERING_BYTES 32768
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker /*
78*1c60b9acSAndroid Build Coastguard Worker  * Structure of JSON metadata for utterance handling
79*1c60b9acSAndroid Build Coastguard Worker  */
80*1c60b9acSAndroid Build Coastguard Worker 
81*1c60b9acSAndroid Build Coastguard Worker static const char *metadata = "{"
82*1c60b9acSAndroid Build Coastguard Worker 	"\"event\": {"
83*1c60b9acSAndroid Build Coastguard Worker 		"\"header\": {"
84*1c60b9acSAndroid Build Coastguard Worker 			"\"namespace\": \"SpeechRecognizer\","
85*1c60b9acSAndroid Build Coastguard Worker 			"\"name\": \"Recognize\","
86*1c60b9acSAndroid Build Coastguard Worker 			"\"messageId\": \"message-123\","
87*1c60b9acSAndroid Build Coastguard Worker 			"\"dialogRequestId\": \"dialog-request-321\""
88*1c60b9acSAndroid Build Coastguard Worker 		"},"
89*1c60b9acSAndroid Build Coastguard Worker 		"\"payload\": {"
90*1c60b9acSAndroid Build Coastguard Worker 			"\"profile\":"	"\"CLOSE_TALK\","
91*1c60b9acSAndroid Build Coastguard Worker 			"\"format\":"	"\"AUDIO_L16_RATE_16000_CHANNELS_1\""
92*1c60b9acSAndroid Build Coastguard Worker 		"}"
93*1c60b9acSAndroid Build Coastguard Worker 	"}"
94*1c60b9acSAndroid Build Coastguard Worker "}";
95*1c60b9acSAndroid Build Coastguard Worker 
96*1c60b9acSAndroid Build Coastguard Worker /*
97*1c60b9acSAndroid Build Coastguard Worker  * avs metadata
98*1c60b9acSAndroid Build Coastguard Worker  */
99*1c60b9acSAndroid Build Coastguard Worker 
100*1c60b9acSAndroid Build Coastguard Worker static void
use_buffer_250ms(lws_sorted_usec_list_t * sul)101*1c60b9acSAndroid Build Coastguard Worker use_buffer_250ms(lws_sorted_usec_list_t *sul)
102*1c60b9acSAndroid Build Coastguard Worker {
103*1c60b9acSAndroid Build Coastguard Worker 	ss_avs_metadata_t *m = lws_container_of(sul, ss_avs_metadata_t, sul);
104*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context = (struct lws_context *)m->opaque_data;
105*1c60b9acSAndroid Build Coastguard Worker 	int est = lws_ss_get_est_peer_tx_credit(m->ss);
106*1c60b9acSAndroid Build Coastguard Worker 
107*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: est txcr %d\n", __func__, est);
108*1c60b9acSAndroid Build Coastguard Worker 
109*1c60b9acSAndroid Build Coastguard Worker 	if (est < MAX_MP3_IN_BUFFERING_BYTES - (MAX_MP3_IN_BUFFERING_BYTES / 4)) {
110*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("   adding %d\n", MAX_MP3_IN_BUFFERING_BYTES / 4);
111*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_add_peer_tx_credit(m->ss, MAX_MP3_IN_BUFFERING_BYTES / 4);
112*1c60b9acSAndroid Build Coastguard Worker 	}
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms,
115*1c60b9acSAndroid Build Coastguard Worker 			 250 * LWS_US_PER_MS);
116*1c60b9acSAndroid Build Coastguard Worker }
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker static const char *mp3_mimetype = "application/octet-stream",
119*1c60b9acSAndroid Build Coastguard Worker 		  *match2 = "\x0d\x0a\x0d\x0a";
120*1c60b9acSAndroid Build Coastguard Worker 
121*1c60b9acSAndroid Build Coastguard Worker static int
ss_avs_mp3_open(ss_avs_metadata_t * m)122*1c60b9acSAndroid Build Coastguard Worker ss_avs_mp3_open(ss_avs_metadata_t *m)
123*1c60b9acSAndroid Build Coastguard Worker {
124*1c60b9acSAndroid Build Coastguard Worker 	int r;
125*1c60b9acSAndroid Build Coastguard Worker 
126*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s\n", __func__);
127*1c60b9acSAndroid Build Coastguard Worker 
128*1c60b9acSAndroid Build Coastguard Worker 	m->first_mp3 = 1;
129*1c60b9acSAndroid Build Coastguard Worker 	m->mh = mpg123_new(NULL, NULL);
130*1c60b9acSAndroid Build Coastguard Worker 	if (!m->mh) {
131*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: unable to make new mp3\n",
132*1c60b9acSAndroid Build Coastguard Worker 				__func__);
133*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
134*1c60b9acSAndroid Build Coastguard Worker 	}
135*1c60b9acSAndroid Build Coastguard Worker 	mpg123_format_none(m->mh);
136*1c60b9acSAndroid Build Coastguard Worker 	r = mpg123_format(m->mh, 16000, MPG123_M_MONO,
137*1c60b9acSAndroid Build Coastguard Worker 			  MPG123_ENC_SIGNED_16);
138*1c60b9acSAndroid Build Coastguard Worker 	if (r) {
139*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: mpg123 format failed %d\n",
140*1c60b9acSAndroid Build Coastguard Worker 				__func__, r);
141*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
142*1c60b9acSAndroid Build Coastguard Worker 	}
143*1c60b9acSAndroid Build Coastguard Worker 	r = mpg123_open_feed(m->mh);
144*1c60b9acSAndroid Build Coastguard Worker 	if (r) {
145*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: mpg123 open feed failed %d\n",
146*1c60b9acSAndroid Build Coastguard Worker 				__func__, r);
147*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
148*1c60b9acSAndroid Build Coastguard Worker 	}
149*1c60b9acSAndroid Build Coastguard Worker 
150*1c60b9acSAndroid Build Coastguard Worker 	return 0;
151*1c60b9acSAndroid Build Coastguard Worker 
152*1c60b9acSAndroid Build Coastguard Worker bail1:
153*1c60b9acSAndroid Build Coastguard Worker 	mpg123_delete(m->mh);
154*1c60b9acSAndroid Build Coastguard Worker 	m->mh = NULL;
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker bail:
157*1c60b9acSAndroid Build Coastguard Worker 	return 1;
158*1c60b9acSAndroid Build Coastguard Worker }
159*1c60b9acSAndroid Build Coastguard Worker 
160*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
161*1c60b9acSAndroid Build Coastguard Worker ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags);
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker /*
164*1c60b9acSAndroid Build Coastguard Worker  * This is called when the mp3 has drained it's input buffer and destroyed
165*1c60b9acSAndroid Build Coastguard Worker  * itself.
166*1c60b9acSAndroid Build Coastguard Worker  */
167*1c60b9acSAndroid Build Coastguard Worker 
168*1c60b9acSAndroid Build Coastguard Worker static int
drain_end_cb(void * v)169*1c60b9acSAndroid Build Coastguard Worker drain_end_cb(void *v)
170*1c60b9acSAndroid Build Coastguard Worker {
171*1c60b9acSAndroid Build Coastguard Worker 	ss_avs_metadata_t *m = (ss_avs_metadata_t *)v;
172*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context = (struct lws_context *)m->opaque_data;
173*1c60b9acSAndroid Build Coastguard Worker 	int tot = 0;
174*1c60b9acSAndroid Build Coastguard Worker 
175*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("%s\n", __func__);
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker 	/*
178*1c60b9acSAndroid Build Coastguard Worker 	 * We have drained and destroyed the existing mp3 session.  Is there
179*1c60b9acSAndroid Build Coastguard Worker 	 * a new one pending?
180*1c60b9acSAndroid Build Coastguard Worker 	 */
181*1c60b9acSAndroid Build Coastguard Worker 
182*1c60b9acSAndroid Build Coastguard Worker 	m->first_mp3 = 1;
183*1c60b9acSAndroid Build Coastguard Worker 	m->mp3_state = LAMP3STATE_IDLE;
184*1c60b9acSAndroid Build Coastguard Worker 
185*1c60b9acSAndroid Build Coastguard Worker 	if (lws_buflist_total_len(&m->dribble)) {
186*1c60b9acSAndroid Build Coastguard Worker 		/* we started another one */
187*1c60b9acSAndroid Build Coastguard Worker 
188*1c60b9acSAndroid Build Coastguard Worker 		/* resume tx credit top up */
189*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms, 1);
190*1c60b9acSAndroid Build Coastguard Worker 
191*1c60b9acSAndroid Build Coastguard Worker 		if (ss_avs_mp3_open(m))
192*1c60b9acSAndroid Build Coastguard Worker 			return 1;
193*1c60b9acSAndroid Build Coastguard Worker 
194*1c60b9acSAndroid Build Coastguard Worker 		m->mp3_state = LAMP3STATE_SPOOLING;
195*1c60b9acSAndroid Build Coastguard Worker 
196*1c60b9acSAndroid Build Coastguard Worker 		/*
197*1c60b9acSAndroid Build Coastguard Worker 		 * Dump what we stashed from draining into the new mp3
198*1c60b9acSAndroid Build Coastguard Worker 		 */
199*1c60b9acSAndroid Build Coastguard Worker 
200*1c60b9acSAndroid Build Coastguard Worker 		while (lws_buflist_total_len(&m->dribble)) {
201*1c60b9acSAndroid Build Coastguard Worker 			size_t s;
202*1c60b9acSAndroid Build Coastguard Worker 			uint8_t *u, t;
203*1c60b9acSAndroid Build Coastguard Worker 
204*1c60b9acSAndroid Build Coastguard Worker 			s = lws_buflist_next_segment_len(&m->dribble, &u);
205*1c60b9acSAndroid Build Coastguard Worker 			t = m->stash_eom[m->se_tail];
206*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: preload %d: %d\n", __func__, (int)s, t);
207*1c60b9acSAndroid Build Coastguard Worker 
208*1c60b9acSAndroid Build Coastguard Worker 			mpg123_feed(m->mh, u, s);
209*1c60b9acSAndroid Build Coastguard Worker 			lws_buflist_use_segment(&m->dribble, s);
210*1c60b9acSAndroid Build Coastguard Worker 			if (m->first_mp3) {
211*1c60b9acSAndroid Build Coastguard Worker 				play_mp3(m->mh, NULL, NULL);
212*1c60b9acSAndroid Build Coastguard Worker 				m->first_mp3 = 0;
213*1c60b9acSAndroid Build Coastguard Worker 			}
214*1c60b9acSAndroid Build Coastguard Worker 
215*1c60b9acSAndroid Build Coastguard Worker 			tot += s;
216*1c60b9acSAndroid Build Coastguard Worker 
217*1c60b9acSAndroid Build Coastguard Worker 			m->se_tail = (m->se_tail + 1) % sizeof(m->stash_eom);
218*1c60b9acSAndroid Build Coastguard Worker 			if (t) {
219*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("%s: preloaded EOM\n", __func__);
220*1c60b9acSAndroid Build Coastguard Worker 
221*1c60b9acSAndroid Build Coastguard Worker 				/*
222*1c60b9acSAndroid Build Coastguard Worker 				 * We stashed the whole of the message, we need
223*1c60b9acSAndroid Build Coastguard Worker 				 * to also do the EOM processing.  We will come
224*1c60b9acSAndroid Build Coastguard Worker 				 * back here if there's another message in the
225*1c60b9acSAndroid Build Coastguard Worker 				 * stash.
226*1c60b9acSAndroid Build Coastguard Worker 				 */
227*1c60b9acSAndroid Build Coastguard Worker 
228*1c60b9acSAndroid Build Coastguard Worker 				m->mp3_state = LAMP3STATE_DRAINING;
229*1c60b9acSAndroid Build Coastguard Worker 				if (m->mh)
230*1c60b9acSAndroid Build Coastguard Worker 					play_mp3(NULL, drain_end_cb, m);
231*1c60b9acSAndroid Build Coastguard Worker 
232*1c60b9acSAndroid Build Coastguard Worker 				lws_ss_add_peer_tx_credit(m->ss, tot);
233*1c60b9acSAndroid Build Coastguard Worker #if 0
234*1c60b9acSAndroid Build Coastguard Worker 				/*
235*1c60b9acSAndroid Build Coastguard Worker 				 * Put a hold on bringing in any more data
236*1c60b9acSAndroid Build Coastguard Worker 				 */
237*1c60b9acSAndroid Build Coastguard Worker 				lws_sul_cancel(&m->sul);
238*1c60b9acSAndroid Build Coastguard Worker #endif
239*1c60b9acSAndroid Build Coastguard Worker 				/* destroy our copy of the handle */
240*1c60b9acSAndroid Build Coastguard Worker 				m->mh = NULL;
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 				break;
243*1c60b9acSAndroid Build Coastguard Worker 			}
244*1c60b9acSAndroid Build Coastguard Worker 		}
245*1c60b9acSAndroid Build Coastguard Worker 
246*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_add_peer_tx_credit(m->ss, tot);
247*1c60b9acSAndroid Build Coastguard Worker 	}
248*1c60b9acSAndroid Build Coastguard Worker 
249*1c60b9acSAndroid Build Coastguard Worker 	return 0;
250*1c60b9acSAndroid Build Coastguard Worker }
251*1c60b9acSAndroid Build Coastguard Worker 
252*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_metadata_rx(void * userobj,const uint8_t * buf,size_t len,int flags)253*1c60b9acSAndroid Build Coastguard Worker ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
254*1c60b9acSAndroid Build Coastguard Worker {
255*1c60b9acSAndroid Build Coastguard Worker 	ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
256*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context = (struct lws_context *)m->opaque_data;
257*1c60b9acSAndroid Build Coastguard Worker 	int n = 0, hit = 0;
258*1c60b9acSAndroid Build Coastguard Worker 
259*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: len %d, flags %d (est peer txcr %d)\n", __func__,
260*1c60b9acSAndroid Build Coastguard Worker 		    (int)len, flags, lws_ss_get_est_peer_tx_credit(m->ss));
261*1c60b9acSAndroid Build Coastguard Worker 
262*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_hexdump_warn(buf, len);
263*1c60b9acSAndroid Build Coastguard Worker 
264*1c60b9acSAndroid Build Coastguard Worker 	if ((flags & LWSSS_FLAG_SOM) && !m->mh && !m->seen) {
265*1c60b9acSAndroid Build Coastguard Worker 		m->mp3_mime_match = 0;
266*1c60b9acSAndroid Build Coastguard Worker 		m->seen = 0;
267*1c60b9acSAndroid Build Coastguard Worker 		m->inside_mp3 = 0;
268*1c60b9acSAndroid Build Coastguard Worker 	}
269*1c60b9acSAndroid Build Coastguard Worker 
270*1c60b9acSAndroid Build Coastguard Worker 	if (!m->inside_mp3) {
271*1c60b9acSAndroid Build Coastguard Worker 		/*
272*1c60b9acSAndroid Build Coastguard Worker 		 * Identify the part with the mp3 in, if any
273*1c60b9acSAndroid Build Coastguard Worker 		 */
274*1c60b9acSAndroid Build Coastguard Worker 
275*1c60b9acSAndroid Build Coastguard Worker 		while (n < (int)len - 24) {
276*1c60b9acSAndroid Build Coastguard Worker 			if (!m->seen) {
277*1c60b9acSAndroid Build Coastguard Worker 				if (buf[n] == mp3_mimetype[m->mp3_mime_match]) {
278*1c60b9acSAndroid Build Coastguard Worker 					m->mp3_mime_match++;
279*1c60b9acSAndroid Build Coastguard Worker 					if (m->mp3_mime_match == 24) {
280*1c60b9acSAndroid Build Coastguard Worker 						m->mp3_mime_match = 0;
281*1c60b9acSAndroid Build Coastguard Worker 						m->seen = 1;
282*1c60b9acSAndroid Build Coastguard Worker 						n++;
283*1c60b9acSAndroid Build Coastguard Worker 						continue;
284*1c60b9acSAndroid Build Coastguard Worker 					}
285*1c60b9acSAndroid Build Coastguard Worker 				} else
286*1c60b9acSAndroid Build Coastguard Worker 					m->mp3_mime_match = 0;
287*1c60b9acSAndroid Build Coastguard Worker 			} else {
288*1c60b9acSAndroid Build Coastguard Worker 				if (buf[n] == match2[m->mp3_mime_match]) {
289*1c60b9acSAndroid Build Coastguard Worker 					m->mp3_mime_match++;
290*1c60b9acSAndroid Build Coastguard Worker 					if (m->mp3_mime_match == 4) {
291*1c60b9acSAndroid Build Coastguard Worker 						m->seen = 0;
292*1c60b9acSAndroid Build Coastguard Worker 						m->mp3_mime_match = 0;
293*1c60b9acSAndroid Build Coastguard Worker 						hit = 1;
294*1c60b9acSAndroid Build Coastguard Worker 						n++;
295*1c60b9acSAndroid Build Coastguard Worker 						buf += n;
296*1c60b9acSAndroid Build Coastguard Worker 						len -= n;
297*1c60b9acSAndroid Build Coastguard Worker 						lwsl_notice("identified reply...\n");
298*1c60b9acSAndroid Build Coastguard Worker 						m->inside_mp3 = 1;
299*1c60b9acSAndroid Build Coastguard Worker 						break;
300*1c60b9acSAndroid Build Coastguard Worker 					}
301*1c60b9acSAndroid Build Coastguard Worker 				} else
302*1c60b9acSAndroid Build Coastguard Worker 					m->mp3_mime_match = 0;
303*1c60b9acSAndroid Build Coastguard Worker 			}
304*1c60b9acSAndroid Build Coastguard Worker 
305*1c60b9acSAndroid Build Coastguard Worker 			n++;
306*1c60b9acSAndroid Build Coastguard Worker 		}
307*1c60b9acSAndroid Build Coastguard Worker 
308*1c60b9acSAndroid Build Coastguard Worker 		if (!hit) {
309*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_add_peer_tx_credit(m->ss, len);
310*1c60b9acSAndroid Build Coastguard Worker 			return 0;
311*1c60b9acSAndroid Build Coastguard Worker 		}
312*1c60b9acSAndroid Build Coastguard Worker 	}
313*1c60b9acSAndroid Build Coastguard Worker 
314*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_notice("%s: state %d\n", __func__, m->mp3_state);
315*1c60b9acSAndroid Build Coastguard Worker 
316*1c60b9acSAndroid Build Coastguard Worker 	switch (m->mp3_state) {
317*1c60b9acSAndroid Build Coastguard Worker 	case LAMP3STATE_IDLE:
318*1c60b9acSAndroid Build Coastguard Worker 
319*1c60b9acSAndroid Build Coastguard Worker 		if (hit) {
320*1c60b9acSAndroid Build Coastguard Worker 
321*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_add_peer_tx_credit(m->ss, n);
322*1c60b9acSAndroid Build Coastguard Worker 
323*1c60b9acSAndroid Build Coastguard Worker 			if (ss_avs_mp3_open(m))
324*1c60b9acSAndroid Build Coastguard Worker 				goto bail;
325*1c60b9acSAndroid Build Coastguard Worker 
326*1c60b9acSAndroid Build Coastguard Worker 			lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms, 1);
327*1c60b9acSAndroid Build Coastguard Worker 			m->mp3_state = LAMP3STATE_SPOOLING;
328*1c60b9acSAndroid Build Coastguard Worker 			break;
329*1c60b9acSAndroid Build Coastguard Worker 		}
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_add_peer_tx_credit(m->ss, len);
332*1c60b9acSAndroid Build Coastguard Worker 
333*1c60b9acSAndroid Build Coastguard Worker 		if (!m->inside_mp3)
334*1c60b9acSAndroid Build Coastguard Worker 			break;
335*1c60b9acSAndroid Build Coastguard Worker 
336*1c60b9acSAndroid Build Coastguard Worker 		/* fallthru */
337*1c60b9acSAndroid Build Coastguard Worker 
338*1c60b9acSAndroid Build Coastguard Worker 	case LAMP3STATE_SPOOLING:
339*1c60b9acSAndroid Build Coastguard Worker 
340*1c60b9acSAndroid Build Coastguard Worker 		if (m->dribble)
341*1c60b9acSAndroid Build Coastguard Worker 			goto draining;
342*1c60b9acSAndroid Build Coastguard Worker 
343*1c60b9acSAndroid Build Coastguard Worker 		if (len) {
344*1c60b9acSAndroid Build Coastguard Worker 			/*
345*1c60b9acSAndroid Build Coastguard Worker 			 * We are shoving encoded mp3 into mpg123-allocated heap
346*1c60b9acSAndroid Build Coastguard Worker 			 * buffers... unfortunately mpg123 doesn't seem to
347*1c60b9acSAndroid Build Coastguard Worker 			 * expose where it is in its allocated input so we can
348*1c60b9acSAndroid Build Coastguard Worker 			 * track how much is stashed.  Instead while in playback
349*1c60b9acSAndroid Build Coastguard Worker 			 * mode, we assume 64kbps mp3 encoding, ie, 8KB/s, and
350*1c60b9acSAndroid Build Coastguard Worker 			 * run a sul that allows an additional 2KB tx credit
351*1c60b9acSAndroid Build Coastguard Worker 			 * every 250ms, with 4KB initial credit.
352*1c60b9acSAndroid Build Coastguard Worker 			 */
353*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: SPOOL %d\n", __func__, (int)len);
354*1c60b9acSAndroid Build Coastguard Worker 			mpg123_feed(m->mh, buf, len);
355*1c60b9acSAndroid Build Coastguard Worker 
356*1c60b9acSAndroid Build Coastguard Worker 			if (m->first_mp3) {
357*1c60b9acSAndroid Build Coastguard Worker 				lws_sul_schedule(context, 0, &m->sul,
358*1c60b9acSAndroid Build Coastguard Worker 						 use_buffer_250ms, 1);
359*1c60b9acSAndroid Build Coastguard Worker 		//		lws_ss_add_peer_tx_credit(m->ss,
360*1c60b9acSAndroid Build Coastguard Worker 		//			len + (MAX_MP3_IN_BUFFERING_BYTES / 2));
361*1c60b9acSAndroid Build Coastguard Worker 				play_mp3(m->mh, NULL, NULL);
362*1c60b9acSAndroid Build Coastguard Worker 			} //else
363*1c60b9acSAndroid Build Coastguard Worker 		//		lws_ss_add_peer_tx_credit(m->ss, len);
364*1c60b9acSAndroid Build Coastguard Worker 			m->first_mp3 = 0;
365*1c60b9acSAndroid Build Coastguard Worker 		}
366*1c60b9acSAndroid Build Coastguard Worker 
367*1c60b9acSAndroid Build Coastguard Worker 		if (flags & LWSSS_FLAG_EOM) {
368*1c60b9acSAndroid Build Coastguard Worker 			/*
369*1c60b9acSAndroid Build Coastguard Worker 			 * This means one "message" / mime part with mp3 data
370*1c60b9acSAndroid Build Coastguard Worker 			 * has finished coming in.  But there may be whole other
371*1c60b9acSAndroid Build Coastguard Worker 			 * parts with other mp3s following, with potentially
372*1c60b9acSAndroid Build Coastguard Worker 			 * different mp3 parameters.  So we want to tell this
373*1c60b9acSAndroid Build Coastguard Worker 			 * one to drain and finish and destroy the current mp3
374*1c60b9acSAndroid Build Coastguard Worker 			 * object before we go on.
375*1c60b9acSAndroid Build Coastguard Worker 			 *
376*1c60b9acSAndroid Build Coastguard Worker 			 * But not knowing the length of the current one, there
377*1c60b9acSAndroid Build Coastguard Worker 			 * will already be outstanding tx credit at the server,
378*1c60b9acSAndroid Build Coastguard Worker 			 * so it's going to spam us with the next part before we
379*1c60b9acSAndroid Build Coastguard Worker 			 * have the new mp3 sink for it.
380*1c60b9acSAndroid Build Coastguard Worker 			 */
381*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: EOM\n", __func__);
382*1c60b9acSAndroid Build Coastguard Worker 			m->mp3_mime_match = 0;
383*1c60b9acSAndroid Build Coastguard Worker 			m->seen = 0;
384*1c60b9acSAndroid Build Coastguard Worker 			m->mp3_state = LAMP3STATE_DRAINING;
385*1c60b9acSAndroid Build Coastguard Worker 			/* from input POV, we're no longer inside an mp3 */
386*1c60b9acSAndroid Build Coastguard Worker 			m->inside_mp3 = 0;
387*1c60b9acSAndroid Build Coastguard Worker 			if (m->mh)
388*1c60b9acSAndroid Build Coastguard Worker 				play_mp3(NULL, drain_end_cb, m);
389*1c60b9acSAndroid Build Coastguard Worker #if 0
390*1c60b9acSAndroid Build Coastguard Worker 			/*
391*1c60b9acSAndroid Build Coastguard Worker 			 * Put a hold on bringing in any more data
392*1c60b9acSAndroid Build Coastguard Worker 			 */
393*1c60b9acSAndroid Build Coastguard Worker 			lws_sul_cancel(&m->sul);
394*1c60b9acSAndroid Build Coastguard Worker #endif
395*1c60b9acSAndroid Build Coastguard Worker 			/* destroy our copy of the handle */
396*1c60b9acSAndroid Build Coastguard Worker 			m->mh = NULL;
397*1c60b9acSAndroid Build Coastguard Worker 		}
398*1c60b9acSAndroid Build Coastguard Worker 		break;
399*1c60b9acSAndroid Build Coastguard Worker 
400*1c60b9acSAndroid Build Coastguard Worker 	case LAMP3STATE_DRAINING:
401*1c60b9acSAndroid Build Coastguard Worker 
402*1c60b9acSAndroid Build Coastguard Worker draining:
403*1c60b9acSAndroid Build Coastguard Worker 		if (buf && len && m->inside_mp3) {
404*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: DRAINING: stashing %d: %d %d %d\n",
405*1c60b9acSAndroid Build Coastguard Worker 				    __func__, (int)len, !!(flags & LWSSS_FLAG_EOM),
406*1c60b9acSAndroid Build Coastguard Worker 				    m->se_head, m->se_tail);
407*1c60b9acSAndroid Build Coastguard Worker 			lwsl_hexdump_notice(buf, len);
408*1c60b9acSAndroid Build Coastguard Worker 			if (lws_buflist_append_segment(&m->dribble, buf, len) < 0)
409*1c60b9acSAndroid Build Coastguard Worker 				goto bail;
410*1c60b9acSAndroid Build Coastguard Worker 
411*1c60b9acSAndroid Build Coastguard Worker 			m->stash_eom[m->se_head] = !!(flags & LWSSS_FLAG_EOM);
412*1c60b9acSAndroid Build Coastguard Worker 			m->se_head = (m->se_head + 1) % sizeof(m->stash_eom);
413*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: next head %d\n", __func__, m->se_head);
414*1c60b9acSAndroid Build Coastguard Worker 
415*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_add_peer_tx_credit(m->ss, len);
416*1c60b9acSAndroid Build Coastguard Worker 		}
417*1c60b9acSAndroid Build Coastguard Worker 
418*1c60b9acSAndroid Build Coastguard Worker 		if (flags & LWSSS_FLAG_EOM) {
419*1c60b9acSAndroid Build Coastguard Worker 			if (!len && m->se_head != m->se_tail) {
420*1c60b9acSAndroid Build Coastguard Worker 				/* 0-len EOM... retrospectively mark last stash */
421*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("%s: retro EOM\n", __func__);
422*1c60b9acSAndroid Build Coastguard Worker 				m->stash_eom[(m->se_head - 1) % sizeof(m->stash_eom)] = 1;
423*1c60b9acSAndroid Build Coastguard Worker 			}
424*1c60b9acSAndroid Build Coastguard Worker 
425*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: Draining EOM\n", __func__);
426*1c60b9acSAndroid Build Coastguard Worker 			m->inside_mp3 = 0;
427*1c60b9acSAndroid Build Coastguard Worker 		}
428*1c60b9acSAndroid Build Coastguard Worker 		/*
429*1c60b9acSAndroid Build Coastguard Worker 		 * Don't provide any additional tx credit... we're just
430*1c60b9acSAndroid Build Coastguard Worker 		 * mopping up the overspill from the previous mp3 credit
431*1c60b9acSAndroid Build Coastguard Worker 		 */
432*1c60b9acSAndroid Build Coastguard Worker 		break;
433*1c60b9acSAndroid Build Coastguard Worker 	}
434*1c60b9acSAndroid Build Coastguard Worker 
435*1c60b9acSAndroid Build Coastguard Worker 	return 0;
436*1c60b9acSAndroid Build Coastguard Worker 
437*1c60b9acSAndroid Build Coastguard Worker bail:
438*1c60b9acSAndroid Build Coastguard Worker 	return -1;
439*1c60b9acSAndroid Build Coastguard Worker }
440*1c60b9acSAndroid Build Coastguard Worker 
441*1c60b9acSAndroid Build Coastguard Worker /*
442*1c60b9acSAndroid Build Coastguard Worker  * Because this is multipart mime in h2 currently, use a "rideshare" to handle
443*1c60b9acSAndroid Build Coastguard Worker  * first the native metadata on this secure stream, then the "rideshare" audio
444*1c60b9acSAndroid Build Coastguard Worker  * stream mentioned in the policy.
445*1c60b9acSAndroid Build Coastguard Worker  *
446*1c60b9acSAndroid Build Coastguard Worker  * Lws takes care of interleaving the multipart mime pieces since the policy
447*1c60b9acSAndroid Build Coastguard Worker  * calls for it.
448*1c60b9acSAndroid Build Coastguard Worker  */
449*1c60b9acSAndroid Build Coastguard Worker 
450*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_metadata_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)451*1c60b9acSAndroid Build Coastguard Worker ss_avs_metadata_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
452*1c60b9acSAndroid Build Coastguard Worker 		   size_t *len, int *flags)
453*1c60b9acSAndroid Build Coastguard Worker {
454*1c60b9acSAndroid Build Coastguard Worker 	ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
455*1c60b9acSAndroid Build Coastguard Worker 	size_t tot;
456*1c60b9acSAndroid Build Coastguard Worker 	int n;
457*1c60b9acSAndroid Build Coastguard Worker 
458*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_notice("%s %d\n", __func__, (int)m->pos);
459*1c60b9acSAndroid Build Coastguard Worker 
460*1c60b9acSAndroid Build Coastguard Worker 	if ((long)m->pos < 0) {
461*1c60b9acSAndroid Build Coastguard Worker 		*len = 0;
462*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: skip\n", __func__);
463*1c60b9acSAndroid Build Coastguard Worker 		return 1;
464*1c60b9acSAndroid Build Coastguard Worker 	}
465*1c60b9acSAndroid Build Coastguard Worker 
466*1c60b9acSAndroid Build Coastguard Worker 	if (!strcmp(lws_ss_rideshare(m->ss), "avs_audio")) {
467*1c60b9acSAndroid Build Coastguard Worker 
468*1c60b9acSAndroid Build Coastguard Worker 		/* audio rideshare part */
469*1c60b9acSAndroid Build Coastguard Worker 
470*1c60b9acSAndroid Build Coastguard Worker 		if (!m->pos)
471*1c60b9acSAndroid Build Coastguard Worker 			*flags |= LWSSS_FLAG_SOM;
472*1c60b9acSAndroid Build Coastguard Worker 
473*1c60b9acSAndroid Build Coastguard Worker 		n = spool_capture(buf, *len);
474*1c60b9acSAndroid Build Coastguard Worker 		if (n > 0)
475*1c60b9acSAndroid Build Coastguard Worker 			*len = n;
476*1c60b9acSAndroid Build Coastguard Worker 		else
477*1c60b9acSAndroid Build Coastguard Worker 			*len = 0;
478*1c60b9acSAndroid Build Coastguard Worker 		if (!n) {
479*1c60b9acSAndroid Build Coastguard Worker 			lwsl_info("%s: trying to skip tx\n", __func__);
480*1c60b9acSAndroid Build Coastguard Worker 			return 1;
481*1c60b9acSAndroid Build Coastguard Worker 		}
482*1c60b9acSAndroid Build Coastguard Worker 
483*1c60b9acSAndroid Build Coastguard Worker 		m->pos += *len;
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 		if (n < 0) {
486*1c60b9acSAndroid Build Coastguard Worker 			*flags |= LWSSS_FLAG_EOM;
487*1c60b9acSAndroid Build Coastguard Worker 			m->pos = (long)-1l; /* ban subsequent until new stream */
488*1c60b9acSAndroid Build Coastguard Worker 		}
489*1c60b9acSAndroid Build Coastguard Worker 
490*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: tx audio %d\n", __func__, (int)*len);
491*1c60b9acSAndroid Build Coastguard Worker 
492*1c60b9acSAndroid Build Coastguard Worker #if 0
493*1c60b9acSAndroid Build Coastguard Worker 		{
494*1c60b9acSAndroid Build Coastguard Worker 			int ff = open("/tmp/z1", O_RDWR | O_CREAT | O_APPEND, 0666);
495*1c60b9acSAndroid Build Coastguard Worker 			if (ff == -1)
496*1c60b9acSAndroid Build Coastguard Worker 				lwsl_err("%s: errno %d\n", __func__, errno);
497*1c60b9acSAndroid Build Coastguard Worker 			write(ff, buf, *len);
498*1c60b9acSAndroid Build Coastguard Worker 			close(ff);
499*1c60b9acSAndroid Build Coastguard Worker 		}
500*1c60b9acSAndroid Build Coastguard Worker #endif
501*1c60b9acSAndroid Build Coastguard Worker 
502*1c60b9acSAndroid Build Coastguard Worker 		return 0;
503*1c60b9acSAndroid Build Coastguard Worker 	}
504*1c60b9acSAndroid Build Coastguard Worker 
505*1c60b9acSAndroid Build Coastguard Worker 	/* metadata part */
506*1c60b9acSAndroid Build Coastguard Worker 
507*1c60b9acSAndroid Build Coastguard Worker 	tot = strlen(metadata);
508*1c60b9acSAndroid Build Coastguard Worker 
509*1c60b9acSAndroid Build Coastguard Worker 	if (!m->pos)
510*1c60b9acSAndroid Build Coastguard Worker 		*flags |= LWSSS_FLAG_SOM;
511*1c60b9acSAndroid Build Coastguard Worker 
512*1c60b9acSAndroid Build Coastguard Worker 	if (*len > tot - m->pos)
513*1c60b9acSAndroid Build Coastguard Worker 		*len = tot - m->pos;
514*1c60b9acSAndroid Build Coastguard Worker 
515*1c60b9acSAndroid Build Coastguard Worker 	memcpy(buf, metadata + m->pos, *len);
516*1c60b9acSAndroid Build Coastguard Worker 
517*1c60b9acSAndroid Build Coastguard Worker 	m->pos += *len;
518*1c60b9acSAndroid Build Coastguard Worker 
519*1c60b9acSAndroid Build Coastguard Worker 	if (m->pos == tot) {
520*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("metadata done\n");
521*1c60b9acSAndroid Build Coastguard Worker 		*flags |= LWSSS_FLAG_EOM;
522*1c60b9acSAndroid Build Coastguard Worker 		m->pos = 0; /* for next time */
523*1c60b9acSAndroid Build Coastguard Worker 	}
524*1c60b9acSAndroid Build Coastguard Worker 
525*1c60b9acSAndroid Build Coastguard Worker 	return 0;
526*1c60b9acSAndroid Build Coastguard Worker }
527*1c60b9acSAndroid Build Coastguard Worker 
528*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_metadata_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)529*1c60b9acSAndroid Build Coastguard Worker ss_avs_metadata_state(void *userobj, void *sh,
530*1c60b9acSAndroid Build Coastguard Worker 		      lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
531*1c60b9acSAndroid Build Coastguard Worker {
532*1c60b9acSAndroid Build Coastguard Worker 	ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
533*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context = (struct lws_context *)m->opaque_data;
534*1c60b9acSAndroid Build Coastguard Worker 
535*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: %p: %s, ord 0x%x\n", __func__, m->ss,
536*1c60b9acSAndroid Build Coastguard Worker 		    lws_ss_state_name(state), (unsigned int)ack);
537*1c60b9acSAndroid Build Coastguard Worker 
538*1c60b9acSAndroid Build Coastguard Worker 	switch (state) {
539*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CREATING:
540*1c60b9acSAndroid Build Coastguard Worker 		return lws_ss_client_connect(m->ss);
541*1c60b9acSAndroid Build Coastguard Worker 
542*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTING:
543*1c60b9acSAndroid Build Coastguard Worker 		m->pos = 0;
544*1c60b9acSAndroid Build Coastguard Worker 		break;
545*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTED:
546*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: CONNECTED\n", __func__);
547*1c60b9acSAndroid Build Coastguard Worker 		return lws_ss_request_tx(m->ss);
548*1c60b9acSAndroid Build Coastguard Worker 
549*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DISCONNECTED:
550*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_cancel(&m->sul);
551*1c60b9acSAndroid Build Coastguard Worker 		//if (m->mh) {
552*1c60b9acSAndroid Build Coastguard Worker 			play_mp3(NULL, NULL, NULL);
553*1c60b9acSAndroid Build Coastguard Worker 			m->mh = NULL;
554*1c60b9acSAndroid Build Coastguard Worker 		//}
555*1c60b9acSAndroid Build Coastguard Worker 		/*
556*1c60b9acSAndroid Build Coastguard Worker 		 * For this stream encapsulating an alexa exchange, dropping
557*1c60b9acSAndroid Build Coastguard Worker 		 * is the end of its life
558*1c60b9acSAndroid Build Coastguard Worker 		 */
559*1c60b9acSAndroid Build Coastguard Worker 		return 1;
560*1c60b9acSAndroid Build Coastguard Worker 
561*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DESTROYING:
562*1c60b9acSAndroid Build Coastguard Worker 		lws_buflist_destroy_all_segments(&m->dribble);
563*1c60b9acSAndroid Build Coastguard Worker 		break;
564*1c60b9acSAndroid Build Coastguard Worker 	default:
565*1c60b9acSAndroid Build Coastguard Worker 		break;
566*1c60b9acSAndroid Build Coastguard Worker 	}
567*1c60b9acSAndroid Build Coastguard Worker 
568*1c60b9acSAndroid Build Coastguard Worker 	return 0;
569*1c60b9acSAndroid Build Coastguard Worker }
570*1c60b9acSAndroid Build Coastguard Worker 
571*1c60b9acSAndroid Build Coastguard Worker /*
572*1c60b9acSAndroid Build Coastguard Worker  * avs event
573*1c60b9acSAndroid Build Coastguard Worker  */
574*1c60b9acSAndroid Build Coastguard Worker 
575*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_event_rx(void * userobj,const uint8_t * buf,size_t len,int flags)576*1c60b9acSAndroid Build Coastguard Worker ss_avs_event_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
577*1c60b9acSAndroid Build Coastguard Worker {
578*1c60b9acSAndroid Build Coastguard Worker 	return 0;
579*1c60b9acSAndroid Build Coastguard Worker }
580*1c60b9acSAndroid Build Coastguard Worker 
581*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_event_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)582*1c60b9acSAndroid Build Coastguard Worker ss_avs_event_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
583*1c60b9acSAndroid Build Coastguard Worker 		      size_t *len, int *flags)
584*1c60b9acSAndroid Build Coastguard Worker {
585*1c60b9acSAndroid Build Coastguard Worker 	return 1; /* don't transmit anything */
586*1c60b9acSAndroid Build Coastguard Worker }
587*1c60b9acSAndroid Build Coastguard Worker 
588*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_avs_event_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)589*1c60b9acSAndroid Build Coastguard Worker ss_avs_event_state(void *userobj, void *sh,
590*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
591*1c60b9acSAndroid Build Coastguard Worker {
592*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
593*1c60b9acSAndroid Build Coastguard Worker 		  (unsigned int)ack);
594*1c60b9acSAndroid Build Coastguard Worker 
595*1c60b9acSAndroid Build Coastguard Worker 	switch (state) {
596*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CREATING:
597*1c60b9acSAndroid Build Coastguard Worker 		mpg123_init();
598*1c60b9acSAndroid Build Coastguard Worker 		break;
599*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTING:
600*1c60b9acSAndroid Build Coastguard Worker 		break;
601*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTED:
602*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("Connected to Alexa... speak \"Alexa, ...\"\n");
603*1c60b9acSAndroid Build Coastguard Worker 		break;
604*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DISCONNECTED:
605*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("Disconnected from Alexa\n");
606*1c60b9acSAndroid Build Coastguard Worker 		break;
607*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DESTROYING:
608*1c60b9acSAndroid Build Coastguard Worker 		mpg123_exit();
609*1c60b9acSAndroid Build Coastguard Worker 		break;
610*1c60b9acSAndroid Build Coastguard Worker 	default:
611*1c60b9acSAndroid Build Coastguard Worker 		break;
612*1c60b9acSAndroid Build Coastguard Worker 	}
613*1c60b9acSAndroid Build Coastguard Worker 
614*1c60b9acSAndroid Build Coastguard Worker 	return 0;
615*1c60b9acSAndroid Build Coastguard Worker }
616*1c60b9acSAndroid Build Coastguard Worker 
617*1c60b9acSAndroid Build Coastguard Worker int
avs_query_start(struct lws_context * context)618*1c60b9acSAndroid Build Coastguard Worker avs_query_start(struct lws_context *context)
619*1c60b9acSAndroid Build Coastguard Worker {
620*1c60b9acSAndroid Build Coastguard Worker 	lws_ss_info_t ssi;
621*1c60b9acSAndroid Build Coastguard Worker 
622*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s:\n", __func__);
623*1c60b9acSAndroid Build Coastguard Worker 
624*1c60b9acSAndroid Build Coastguard Worker 	memset(&ssi, 0, sizeof(ssi));
625*1c60b9acSAndroid Build Coastguard Worker 	ssi.handle_offset	    = offsetof(ss_avs_metadata_t, ss);
626*1c60b9acSAndroid Build Coastguard Worker 	ssi.opaque_user_data_offset = offsetof(ss_avs_metadata_t, opaque_data);
627*1c60b9acSAndroid Build Coastguard Worker 	ssi.rx			    = ss_avs_metadata_rx;
628*1c60b9acSAndroid Build Coastguard Worker 	ssi.tx			    = ss_avs_metadata_tx;
629*1c60b9acSAndroid Build Coastguard Worker 	ssi.state		    = ss_avs_metadata_state;
630*1c60b9acSAndroid Build Coastguard Worker 	ssi.user_alloc		    = sizeof(ss_avs_metadata_t);
631*1c60b9acSAndroid Build Coastguard Worker 	ssi.streamtype		    = "avs_metadata";
632*1c60b9acSAndroid Build Coastguard Worker 
633*1c60b9acSAndroid Build Coastguard Worker 	ssi.manual_initial_tx_credit = 8192;
634*1c60b9acSAndroid Build Coastguard Worker 
635*1c60b9acSAndroid Build Coastguard Worker 	if (lws_ss_create(context, 0, &ssi, context, &hss_avs_sync, NULL, NULL)) {
636*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to create avs metadata secstream\n",
637*1c60b9acSAndroid Build Coastguard Worker 			 __func__);
638*1c60b9acSAndroid Build Coastguard Worker 
639*1c60b9acSAndroid Build Coastguard Worker 		return 1;
640*1c60b9acSAndroid Build Coastguard Worker 	}
641*1c60b9acSAndroid Build Coastguard Worker 
642*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("%s: created query stream %p\n", __func__, hss_avs_sync);
643*1c60b9acSAndroid Build Coastguard Worker 
644*1c60b9acSAndroid Build Coastguard Worker 	return 0;
645*1c60b9acSAndroid Build Coastguard Worker }
646*1c60b9acSAndroid Build Coastguard Worker 
647*1c60b9acSAndroid Build Coastguard Worker int
avs_example_start(struct lws_context * context)648*1c60b9acSAndroid Build Coastguard Worker avs_example_start(struct lws_context *context)
649*1c60b9acSAndroid Build Coastguard Worker {
650*1c60b9acSAndroid Build Coastguard Worker 	lws_ss_info_t ssi;
651*1c60b9acSAndroid Build Coastguard Worker 
652*1c60b9acSAndroid Build Coastguard Worker 	if (hss_avs_event)
653*1c60b9acSAndroid Build Coastguard Worker 		return 0;
654*1c60b9acSAndroid Build Coastguard Worker 
655*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: Starting AVS stream\n", __func__);
656*1c60b9acSAndroid Build Coastguard Worker 
657*1c60b9acSAndroid Build Coastguard Worker 	/* AVS wants us to establish the long poll event stream first */
658*1c60b9acSAndroid Build Coastguard Worker 
659*1c60b9acSAndroid Build Coastguard Worker 	memset(&ssi, 0, sizeof(ssi));
660*1c60b9acSAndroid Build Coastguard Worker 	ssi.handle_offset	    = offsetof(ss_avs_event_t, ss);
661*1c60b9acSAndroid Build Coastguard Worker 	ssi.opaque_user_data_offset = offsetof(ss_avs_event_t, opaque_data);
662*1c60b9acSAndroid Build Coastguard Worker 	ssi.rx			    = ss_avs_event_rx;
663*1c60b9acSAndroid Build Coastguard Worker 	ssi.tx			    = ss_avs_event_tx;
664*1c60b9acSAndroid Build Coastguard Worker 	ssi.state		    = ss_avs_event_state;
665*1c60b9acSAndroid Build Coastguard Worker 	ssi.user_alloc		    = sizeof(ss_avs_event_t);
666*1c60b9acSAndroid Build Coastguard Worker 	ssi.streamtype		    = "avs_event";
667*1c60b9acSAndroid Build Coastguard Worker 
668*1c60b9acSAndroid Build Coastguard Worker 	if (lws_ss_create(context, 0, &ssi, context, &hss_avs_event, NULL, NULL)) {
669*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to create avs event secure stream\n",
670*1c60b9acSAndroid Build Coastguard Worker 			 __func__);
671*1c60b9acSAndroid Build Coastguard Worker 		return 1;
672*1c60b9acSAndroid Build Coastguard Worker 	}
673*1c60b9acSAndroid Build Coastguard Worker 
674*1c60b9acSAndroid Build Coastguard Worker 	return 0;
675*1c60b9acSAndroid Build Coastguard Worker }
676