1 #include <limits.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <audio.h>
5 #include <cmdline.h>
6 #include <list.h>
7 #include <log.h>
8
9 #define DEFAULT_SAMPLING_RATE 48000
10
11 struct resample_data {
12 enum audio_format format;
13 int num_channels;
14 float mul;
15 float step;
16 int count;
17 int left;
18 int right;
19 };
20
21 static int16_t audio_get_sample(void **buffer);
22
23 /* Command-line parameter */
24 static char *audio_fe_name;
25 PARAM(audio_fe_name, string, "audio", NULL, "Selects audio frontend")
26 static int sampling_rate = DEFAULT_SAMPLING_RATE;
27 PARAM(sampling_rate, int, "sampling-rate", NULL, "Sets audio sampling rate")
28
29 struct list_link *audio_frontends;
30 static struct audio_frontend *frontend;
31 static struct resample_data resample_data;
32
audio_get_sample(void ** buffer)33 int16_t audio_get_sample(void **buffer)
34 {
35 int16_t v = 0;
36
37 /* Get value based on format */
38 switch (resample_data.format) {
39 case AUDIO_FORMAT_U8:
40 v = *((uint8_t *)*buffer);
41 v -= UCHAR_MAX / 2;
42 v <<= 8;
43 (*(uint8_t **)buffer)++;
44 break;
45 case AUDIO_FORMAT_S8:
46 v = *((int8_t *)*buffer);
47 v <<= 8;
48 (*(int8_t **)buffer)++;
49 break;
50 case AUDIO_FORMAT_U16:
51 v = *((uint16_t *)*buffer);
52 v -= USHRT_MAX / 2;
53 (*(uint16_t **)buffer)++;
54 break;
55 case AUDIO_FORMAT_S16:
56 v = *((int16_t *)*buffer);
57 (*(int16_t **)buffer)++;
58 break;
59 }
60
61 /* Return value */
62 return v;
63 }
64
audio_init(struct audio_specs * specs)65 bool audio_init(struct audio_specs *specs)
66 {
67 struct list_link *link = audio_frontends;
68 struct audio_frontend *fe;
69
70 if (frontend) {
71 LOG_E("Audio frontend already initialized!\n");
72 return false;
73 }
74
75 /* Validate audio option */
76 if (!audio_fe_name) {
77 LOG_W("No audio frontend selected!\n");
78 return true;
79 }
80
81 /* Validate audio sampling rate */
82 switch (sampling_rate) {
83 case 11025:
84 case 22050:
85 case 44100:
86 case 48000:
87 break;
88 default:
89 LOG_W("%u Hz sampling rate not supported.\n", sampling_rate);
90 LOG_W("Please select 11025, 22050, 44100, or 48000 Hz.\n");
91 sampling_rate = DEFAULT_SAMPLING_RATE;
92 break;
93 }
94
95 /* Find audio frontend */
96 while ((fe = list_get_next(&link))) {
97 /* Skip if name does not match */
98 if (strcmp(audio_fe_name, fe->name))
99 continue;
100
101 /* Initialize frontend */
102 if (fe->init && !fe->init(fe, sampling_rate))
103 return false;
104
105 /* Save frontend */
106 frontend = fe;
107
108 /* Initialize resampling data */
109 resample_data.format = specs->format;
110 resample_data.num_channels = specs->channels;
111 resample_data.mul = sampling_rate / specs->freq;
112 resample_data.step = 0.0f;
113 resample_data.count = 0;
114 resample_data.left = 0;
115 resample_data.right = 0;
116
117 /* Return success */
118 return true;
119 }
120
121 /* Warn as audio frontend was not found */
122 LOG_E("Audio frontend \"%s\" not recognized!\n", audio_fe_name);
123 return false;
124 }
125
audio_enqueue(void * buffer,int length)126 void audio_enqueue(void *buffer, int length)
127 {
128 bool stereo = (resample_data.num_channels == 2);
129 bool reset;
130 float prev_step;
131 int16_t left;
132 int16_t right;
133 int i;
134
135 /* Return if needed */
136 if (!frontend || !frontend->enqueue)
137 return;
138
139 /* Parse all input buffer samples */
140 for (i = 0; i < length; i++) {
141 /* Get left (or mono) value */
142 resample_data.left += audio_get_sample(&buffer);
143
144 /* Get right value if needed */
145 if (stereo)
146 resample_data.right += audio_get_sample(&buffer);
147
148 /* Increment resample data count */
149 resample_data.count++;
150
151 /* Compute next step until output is no longer generated */
152 reset = false;
153 prev_step = resample_data.step;
154 resample_data.step = prev_step + resample_data.mul;
155 while ((int)prev_step != (int)resample_data.step) {
156 /* Compute final left/right (or mono) samples */
157 left = resample_data.left / resample_data.count;
158 right = !stereo ?
159 left :
160 resample_data.right / resample_data.count;
161
162 /* Push left/right pair to frontend */
163 frontend->enqueue(frontend, left, right);
164
165 /* Update step and request state reset */
166 resample_data.step -= 1.0f;
167 reset = true;
168 }
169
170 /* Reset state if required */
171 if (reset) {
172 resample_data.count = 0;
173 resample_data.left = 0;
174 resample_data.right = 0;
175 }
176 }
177 }
178
audio_start()179 void audio_start()
180 {
181 if (frontend && frontend->start)
182 frontend->start(frontend);
183 }
184
audio_stop()185 void audio_stop()
186 {
187 if (frontend && frontend->stop)
188 frontend->stop(frontend);
189 }
190
audio_deinit()191 void audio_deinit()
192 {
193 if (!frontend)
194 return;
195
196 if (frontend->deinit)
197 frontend->deinit(frontend);
198 frontend = NULL;
199 }
200
201