xref: /aosp_15_r20/external/libwebsockets/minimal-examples/raw/minimal-raw-audio/audio.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-raw-audio
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2019 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker  *
9*1c60b9acSAndroid Build Coastguard Worker  * This demonstrates adopting and managing audio device file descriptors in the
10*1c60b9acSAndroid Build Coastguard Worker  * event loop.
11*1c60b9acSAndroid Build Coastguard Worker  */
12*1c60b9acSAndroid Build Coastguard Worker 
13*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
14*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
15*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
16*1c60b9acSAndroid Build Coastguard Worker #include <sys/types.h>
17*1c60b9acSAndroid Build Coastguard Worker #include <sys/stat.h>
18*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
19*1c60b9acSAndroid Build Coastguard Worker 
20*1c60b9acSAndroid Build Coastguard Worker #include <alsa/asoundlib.h>
21*1c60b9acSAndroid Build Coastguard Worker 
22*1c60b9acSAndroid Build Coastguard Worker static unsigned int sample_rate = 16000;
23*1c60b9acSAndroid Build Coastguard Worker 
24*1c60b9acSAndroid Build Coastguard Worker struct raw_vhd {
25*1c60b9acSAndroid Build Coastguard Worker 	uint8_t simplebuf[32768 * 2];
26*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_t *pcm_capture;
27*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_t *pcm_playback;
28*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_t *params;
29*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_uframes_t frames;
30*1c60b9acSAndroid Build Coastguard Worker 	int filefd;
31*1c60b9acSAndroid Build Coastguard Worker 	int rpos;
32*1c60b9acSAndroid Build Coastguard Worker 	int wpos;
33*1c60b9acSAndroid Build Coastguard Worker 	int times;
34*1c60b9acSAndroid Build Coastguard Worker };
35*1c60b9acSAndroid Build Coastguard Worker 
36*1c60b9acSAndroid Build Coastguard Worker static int
set_hw_params(struct lws_vhost * vh,snd_pcm_t ** pcm,int type)37*1c60b9acSAndroid Build Coastguard Worker set_hw_params(struct lws_vhost *vh, snd_pcm_t **pcm, int type)
38*1c60b9acSAndroid Build Coastguard Worker {
39*1c60b9acSAndroid Build Coastguard Worker 	unsigned int rate = sample_rate;
40*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_t *params;
41*1c60b9acSAndroid Build Coastguard Worker 	lws_sock_file_fd_type u;
42*1c60b9acSAndroid Build Coastguard Worker 	struct pollfd pfd;
43*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi1;
44*1c60b9acSAndroid Build Coastguard Worker 	int n;
45*1c60b9acSAndroid Build Coastguard Worker 
46*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_open(pcm, "default", type, SND_PCM_NONBLOCK);
47*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
48*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Can't open default for playback: %s\n",
49*1c60b9acSAndroid Build Coastguard Worker 			 __func__, snd_strerror(n));
50*1c60b9acSAndroid Build Coastguard Worker 
51*1c60b9acSAndroid Build Coastguard Worker 		return -1;
52*1c60b9acSAndroid Build Coastguard Worker 	}
53*1c60b9acSAndroid Build Coastguard Worker 
54*1c60b9acSAndroid Build Coastguard Worker 	if (snd_pcm_poll_descriptors(*pcm, &pfd, 1) != 1) {
55*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to get playback desc\n", __func__);
56*1c60b9acSAndroid Build Coastguard Worker 		return -1;
57*1c60b9acSAndroid Build Coastguard Worker 	}
58*1c60b9acSAndroid Build Coastguard Worker 
59*1c60b9acSAndroid Build Coastguard Worker 	u.filefd = (lws_filefd_type)(long long)pfd.fd;
60*1c60b9acSAndroid Build Coastguard Worker 	wsi1 = lws_adopt_descriptor_vhost(vh, LWS_ADOPT_RAW_FILE_DESC, u,
61*1c60b9acSAndroid Build Coastguard Worker 					  "lws-audio-test", NULL);
62*1c60b9acSAndroid Build Coastguard Worker 	if (!wsi1) {
63*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: Failed to adopt playback desc\n", __func__);
64*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
65*1c60b9acSAndroid Build Coastguard Worker 	}
66*1c60b9acSAndroid Build Coastguard Worker 	if (type == SND_PCM_STREAM_PLAYBACK)
67*1c60b9acSAndroid Build Coastguard Worker 		lws_rx_flow_control(wsi1, 0); /* no POLLIN */
68*1c60b9acSAndroid Build Coastguard Worker 
69*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_malloc(&params);
70*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_any(*pcm, params);
71*1c60b9acSAndroid Build Coastguard Worker 
72*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_hw_params_set_access(*pcm, params,
73*1c60b9acSAndroid Build Coastguard Worker 					 SND_PCM_ACCESS_RW_INTERLEAVED);
74*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0)
75*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_hw_params_set_format(*pcm, params, SND_PCM_FORMAT_S16_LE);
78*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0)
79*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
80*1c60b9acSAndroid Build Coastguard Worker 
81*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_hw_params_set_channels(*pcm, params, 1);
82*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0)
83*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_hw_params_set_rate_near(*pcm, params, &rate, 0);
86*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0)
87*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
88*1c60b9acSAndroid Build Coastguard Worker 
89*1c60b9acSAndroid Build Coastguard Worker 	n = snd_pcm_hw_params(*pcm, params);
90*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_free(params);
91*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0)
92*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
93*1c60b9acSAndroid Build Coastguard Worker 
94*1c60b9acSAndroid Build Coastguard Worker 	return 0;
95*1c60b9acSAndroid Build Coastguard Worker 
96*1c60b9acSAndroid Build Coastguard Worker bail1:
97*1c60b9acSAndroid Build Coastguard Worker 	snd_pcm_hw_params_free(params);
98*1c60b9acSAndroid Build Coastguard Worker bail:
99*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("%s: Set hw params failed: %s\n", __func__, snd_strerror(n));
100*1c60b9acSAndroid Build Coastguard Worker 
101*1c60b9acSAndroid Build Coastguard Worker 	return -1;
102*1c60b9acSAndroid Build Coastguard Worker }
103*1c60b9acSAndroid Build Coastguard Worker 
104*1c60b9acSAndroid Build Coastguard Worker static int
callback_raw_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)105*1c60b9acSAndroid Build Coastguard Worker callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
106*1c60b9acSAndroid Build Coastguard Worker 			void *user, void *in, size_t len)
107*1c60b9acSAndroid Build Coastguard Worker {
108*1c60b9acSAndroid Build Coastguard Worker 	struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
109*1c60b9acSAndroid Build Coastguard Worker 				     lws_get_vhost(wsi), lws_get_protocol(wsi));
110*1c60b9acSAndroid Build Coastguard Worker 	int n;
111*1c60b9acSAndroid Build Coastguard Worker 
112*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
113*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_INIT:
114*1c60b9acSAndroid Build Coastguard Worker 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
115*1c60b9acSAndroid Build Coastguard Worker 				lws_get_protocol(wsi), sizeof(struct raw_vhd));
116*1c60b9acSAndroid Build Coastguard Worker 
117*1c60b9acSAndroid Build Coastguard Worker 		if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_playback,
118*1c60b9acSAndroid Build Coastguard Worker 				  SND_PCM_STREAM_PLAYBACK))  {
119*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: Can't open default for playback\n",
120*1c60b9acSAndroid Build Coastguard Worker 				 __func__);
121*1c60b9acSAndroid Build Coastguard Worker 
122*1c60b9acSAndroid Build Coastguard Worker 			return -1;
123*1c60b9acSAndroid Build Coastguard Worker 		}
124*1c60b9acSAndroid Build Coastguard Worker 
125*1c60b9acSAndroid Build Coastguard Worker 		if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_capture,
126*1c60b9acSAndroid Build Coastguard Worker 				  SND_PCM_STREAM_CAPTURE))  {
127*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: Can't open default for capture\n",
128*1c60b9acSAndroid Build Coastguard Worker 				 __func__);
129*1c60b9acSAndroid Build Coastguard Worker 
130*1c60b9acSAndroid Build Coastguard Worker 			return -1;
131*1c60b9acSAndroid Build Coastguard Worker 		}
132*1c60b9acSAndroid Build Coastguard Worker 		break;
133*1c60b9acSAndroid Build Coastguard Worker 
134*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_DESTROY:
135*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("LWS_CALLBACK_PROTOCOL_DESTROY\n");
136*1c60b9acSAndroid Build Coastguard Worker 		if (vhd && vhd->pcm_playback) {
137*1c60b9acSAndroid Build Coastguard Worker 			snd_pcm_drain(vhd->pcm_playback);
138*1c60b9acSAndroid Build Coastguard Worker 			snd_pcm_close(vhd->pcm_playback);
139*1c60b9acSAndroid Build Coastguard Worker 			vhd->pcm_playback = NULL;
140*1c60b9acSAndroid Build Coastguard Worker 		}
141*1c60b9acSAndroid Build Coastguard Worker 		if (vhd && vhd->pcm_capture) {
142*1c60b9acSAndroid Build Coastguard Worker 			snd_pcm_close(vhd->pcm_capture);
143*1c60b9acSAndroid Build Coastguard Worker 			vhd->pcm_capture = NULL;
144*1c60b9acSAndroid Build Coastguard Worker 		}
145*1c60b9acSAndroid Build Coastguard Worker 		break;
146*1c60b9acSAndroid Build Coastguard Worker 
147*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RAW_RX_FILE:
148*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->times >= 6) {  /* delay amount decided by this */
149*1c60b9acSAndroid Build Coastguard Worker 			n = snd_pcm_writei(vhd->pcm_playback,
150*1c60b9acSAndroid Build Coastguard Worker 					   &vhd->simplebuf[vhd->rpos],
151*1c60b9acSAndroid Build Coastguard Worker 					   ((vhd->wpos - vhd->rpos) &
152*1c60b9acSAndroid Build Coastguard Worker 					    (sizeof(vhd->simplebuf) - 1)) / 2);
153*1c60b9acSAndroid Build Coastguard Worker 			vhd->rpos =  (vhd->rpos + (n * 2)) &
154*1c60b9acSAndroid Build Coastguard Worker 					(sizeof(vhd->simplebuf) - 1);
155*1c60b9acSAndroid Build Coastguard Worker 		}
156*1c60b9acSAndroid Build Coastguard Worker 
157*1c60b9acSAndroid Build Coastguard Worker 		n = snd_pcm_readi(vhd->pcm_capture, &vhd->simplebuf[vhd->wpos],
158*1c60b9acSAndroid Build Coastguard Worker 				  (sizeof(vhd->simplebuf) - vhd->wpos) / 2);
159*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("LWS_CALLBACK_RAW_RX_FILE: %d samples\n", n);
160*1c60b9acSAndroid Build Coastguard Worker 		vhd->times++;
161*1c60b9acSAndroid Build Coastguard Worker 
162*1c60b9acSAndroid Build Coastguard Worker 		vhd->wpos = (vhd->wpos + (n * 2)) & (sizeof(vhd->simplebuf) - 1);
163*1c60b9acSAndroid Build Coastguard Worker 		break;
164*1c60b9acSAndroid Build Coastguard Worker 
165*1c60b9acSAndroid Build Coastguard Worker 	default:
166*1c60b9acSAndroid Build Coastguard Worker 		break;
167*1c60b9acSAndroid Build Coastguard Worker 	}
168*1c60b9acSAndroid Build Coastguard Worker 
169*1c60b9acSAndroid Build Coastguard Worker 	return 0;
170*1c60b9acSAndroid Build Coastguard Worker }
171*1c60b9acSAndroid Build Coastguard Worker 
172*1c60b9acSAndroid Build Coastguard Worker static struct lws_protocols protocols[] = {
173*1c60b9acSAndroid Build Coastguard Worker 	{ "lws-audio-test", callback_raw_test, 0, 0 },
174*1c60b9acSAndroid Build Coastguard Worker 	LWS_PROTOCOL_LIST_TERM
175*1c60b9acSAndroid Build Coastguard Worker };
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker static int interrupted;
178*1c60b9acSAndroid Build Coastguard Worker 
sigint_handler(int sig)179*1c60b9acSAndroid Build Coastguard Worker void sigint_handler(int sig)
180*1c60b9acSAndroid Build Coastguard Worker {
181*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
182*1c60b9acSAndroid Build Coastguard Worker }
183*1c60b9acSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)184*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
185*1c60b9acSAndroid Build Coastguard Worker {
186*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context_creation_info info;
187*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context;
188*1c60b9acSAndroid Build Coastguard Worker 	int n = 0;
189*1c60b9acSAndroid Build Coastguard Worker 
190*1c60b9acSAndroid Build Coastguard Worker 	signal(SIGINT, sigint_handler);
191*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof info);
192*1c60b9acSAndroid Build Coastguard Worker 	lws_cmdline_option_handle_builtin(argc, argv, &info);
193*1c60b9acSAndroid Build Coastguard Worker 
194*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("LWS minimal raw audio\n");
195*1c60b9acSAndroid Build Coastguard Worker 
196*1c60b9acSAndroid Build Coastguard Worker 	info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
197*1c60b9acSAndroid Build Coastguard Worker 	info.protocols = protocols;
198*1c60b9acSAndroid Build Coastguard Worker 
199*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
200*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
201*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("lws init failed\n");
202*1c60b9acSAndroid Build Coastguard Worker 		return 1;
203*1c60b9acSAndroid Build Coastguard Worker 	}
204*1c60b9acSAndroid Build Coastguard Worker 
205*1c60b9acSAndroid Build Coastguard Worker 	while (n >= 0 && !interrupted)
206*1c60b9acSAndroid Build Coastguard Worker 		n = lws_service(context, 0);
207*1c60b9acSAndroid Build Coastguard Worker 
208*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
209*1c60b9acSAndroid Build Coastguard Worker 
210*1c60b9acSAndroid Build Coastguard Worker 	return 0;
211*1c60b9acSAndroid Build Coastguard Worker }
212