1 /**
2  * @file alsa_src.c  ALSA sound driver - recorder
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #define _DEFAULT_SOURCE 1
7 #define _POSIX_SOURCE 1
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <alsa/asoundlib.h>
13 #include <pthread.h>
14 #include <re.h>
15 #include <rem.h>
16 #include <baresip.h>
17 #include "alsa.h"
18 
19 
20 struct ausrc_st {
21 	const struct ausrc *as;  /* pointer to base-class (inheritance) */
22 	pthread_t thread;
23 	bool run;
24 	snd_pcm_t *read;
25 	void *sampv;
26 	size_t sampc;
27 	ausrc_read_h *rh;
28 	void *arg;
29 	struct ausrc_prm prm;
30 	char *device;
31 };
32 
33 
ausrc_destructor(void * arg)34 static void ausrc_destructor(void *arg)
35 {
36 	struct ausrc_st *st = arg;
37 
38 	/* Wait for termination of other thread */
39 	if (st->run) {
40 		debug("alsa: stopping recording thread (%s)\n", st->device);
41 		st->run = false;
42 		(void)pthread_join(st->thread, NULL);
43 	}
44 
45 	if (st->read)
46 		snd_pcm_close(st->read);
47 
48 	mem_deref(st->sampv);
49 	mem_deref(st->device);
50 }
51 
52 
read_thread(void * arg)53 static void *read_thread(void *arg)
54 {
55 	struct ausrc_st *st = arg;
56 	int num_frames;
57 	int err;
58 
59 	num_frames = st->prm.srate * st->prm.ptime / 1000;
60 
61 	/* Start */
62 	err = snd_pcm_start(st->read);
63 	if (err) {
64 		warning("alsa: could not start ausrc device '%s' (%s)\n",
65 			st->device, snd_strerror(err));
66 		goto out;
67 	}
68 
69 	while (st->run) {
70 		size_t sampc;
71 		void *sampv;
72 
73 		sampv = st->sampv;
74 
75 		err = snd_pcm_readi(st->read, sampv, num_frames);
76 		if (err == -EPIPE) {
77 			snd_pcm_prepare(st->read);
78 			continue;
79 		}
80 		else if (err <= 0) {
81 			continue;
82 		}
83 
84 		sampc = err * st->prm.ch;
85 
86 		st->rh(st->sampv, sampc, st->arg);
87 	}
88 
89  out:
90 	return NULL;
91 }
92 
93 
alsa_src_alloc(struct ausrc_st ** stp,const struct ausrc * as,struct media_ctx ** ctx,struct ausrc_prm * prm,const char * device,ausrc_read_h * rh,ausrc_error_h * errh,void * arg)94 int alsa_src_alloc(struct ausrc_st **stp, const struct ausrc *as,
95 		   struct media_ctx **ctx,
96 		   struct ausrc_prm *prm, const char *device,
97 		   ausrc_read_h *rh, ausrc_error_h *errh, void *arg)
98 {
99 	struct ausrc_st *st;
100 	snd_pcm_format_t pcmfmt;
101 	int num_frames;
102 	int err;
103 	(void)ctx;
104 	(void)errh;
105 
106 	if (!stp || !as || !prm || !rh)
107 		return EINVAL;
108 
109 	if (!str_isset(device))
110 		device = alsa_dev;
111 
112 	st = mem_zalloc(sizeof(*st), ausrc_destructor);
113 	if (!st)
114 		return ENOMEM;
115 
116 	err = str_dup(&st->device, device);
117 	if (err)
118 		goto out;
119 
120 	st->prm = *prm;
121 	st->as  = as;
122 	st->rh  = rh;
123 	st->arg = arg;
124 
125 	st->sampc = prm->srate * prm->ch * prm->ptime / 1000;
126 	num_frames = st->prm.srate * st->prm.ptime / 1000;
127 
128 	st->sampv = mem_alloc(aufmt_sample_size(prm->fmt) * st->sampc, NULL);
129 	if (!st->sampv) {
130 		err = ENOMEM;
131 		goto out;
132 	}
133 
134 	err = snd_pcm_open(&st->read, st->device, SND_PCM_STREAM_CAPTURE, 0);
135 	if (err < 0) {
136 		warning("alsa: could not open ausrc device '%s' (%s)\n",
137 			st->device, snd_strerror(err));
138 		goto out;
139 	}
140 
141 	pcmfmt = aufmt_to_alsaformat(prm->fmt);
142 	if (pcmfmt == SND_PCM_FORMAT_UNKNOWN) {
143 		warning("alsa: unknown sample format '%s'\n",
144 			aufmt_name(prm->fmt));
145 		err = EINVAL;
146 		goto out;
147 	}
148 
149 	err = alsa_reset(st->read, st->prm.srate, st->prm.ch, num_frames,
150 			 pcmfmt);
151 	if (err) {
152 		warning("alsa: could not reset source '%s' (%s)\n",
153 			st->device, snd_strerror(err));
154 		goto out;
155 	}
156 
157 	st->run = true;
158 	err = pthread_create(&st->thread, NULL, read_thread, st);
159 	if (err) {
160 		st->run = false;
161 		goto out;
162 	}
163 
164 	debug("alsa: recording started (%s) format=%s\n",
165 	      st->device, aufmt_name(prm->fmt));
166 
167  out:
168 	if (err)
169 		mem_deref(st);
170 	else
171 		*stp = st;
172 
173 	return err;
174 }
175