1 /** 2 * @file aumix.c Audio Mixer 3 * 4 * Copyright (C) 2010 Creytiv.com 5 */ 6 7 #define _BSD_SOURCE 1 8 #define _DEFAULT_SOURCE 1 9 #include <unistd.h> 10 #include <pthread.h> 11 #include <string.h> 12 #include <re.h> 13 #include <rem_au.h> 14 #include <rem_aubuf.h> 15 #include <rem_aufile.h> 16 #include <rem_aumix.h> 17 18 19 /** Defines an Audio mixer */ 20 struct aumix { 21 pthread_mutex_t mutex; 22 pthread_cond_t cond; 23 struct list srcl; 24 pthread_t thread; 25 struct aufile *af; 26 uint32_t ptime; 27 uint32_t frame_size; 28 uint32_t srate; 29 uint8_t ch; 30 bool run; 31 }; 32 33 /** Defines an Audio mixer source */ 34 struct aumix_source { 35 struct le le; 36 int16_t *frame; 37 struct aubuf *aubuf; 38 struct aumix *mix; 39 aumix_frame_h *fh; 40 void *arg; 41 }; 42 43 44 static void dummy_frame_handler(const int16_t *sampv, size_t sampc, void *arg) 45 { 46 (void)sampv; 47 (void)sampc; 48 (void)arg; 49 } 50 51 52 static void destructor(void *arg) 53 { 54 struct aumix *mix = arg; 55 56 if (mix->run) { 57 58 pthread_mutex_lock(&mix->mutex); 59 mix->run = false; 60 pthread_cond_signal(&mix->cond); 61 pthread_mutex_unlock(&mix->mutex); 62 63 pthread_join(mix->thread, NULL); 64 } 65 66 mem_deref(mix->af); 67 } 68 69 70 static void source_destructor(void *arg) 71 { 72 struct aumix_source *src = arg; 73 74 if (src->le.list) { 75 pthread_mutex_lock(&src->mix->mutex); 76 list_unlink(&src->le); 77 pthread_mutex_unlock(&src->mix->mutex); 78 } 79 80 mem_deref(src->aubuf); 81 mem_deref(src->frame); 82 mem_deref(src->mix); 83 } 84 85 86 static void *aumix_thread(void *arg) 87 { 88 uint8_t *silence, *frame, *base_frame; 89 struct aumix *mix = arg; 90 int16_t *mix_frame; 91 uint64_t ts = 0; 92 93 silence = mem_zalloc(mix->frame_size*2, NULL); 94 frame = mem_alloc(mix->frame_size*2, NULL); 95 mix_frame = mem_alloc(mix->frame_size*2, NULL); 96 97 if (!silence || !frame || !mix_frame) 98 goto out; 99 100 pthread_mutex_lock(&mix->mutex); 101 102 while (mix->run) { 103 104 struct le *le; 105 uint64_t now; 106 107 if (!mix->srcl.head) { 108 mix->af = mem_deref(mix->af); 109 pthread_cond_wait(&mix->cond, &mix->mutex); 110 ts = 0; 111 } 112 else { 113 pthread_mutex_unlock(&mix->mutex); 114 (void)usleep(4000); 115 pthread_mutex_lock(&mix->mutex); 116 } 117 118 now = tmr_jiffies(); 119 if (!ts) 120 ts = now; 121 122 if (ts > now) 123 continue; 124 125 if (mix->af) { 126 127 size_t n = mix->frame_size*2; 128 129 if (aufile_read(mix->af, frame, &n) || n == 0) { 130 mix->af = mem_deref(mix->af); 131 base_frame = silence; 132 } 133 else if (n < mix->frame_size*2) { 134 memset(frame + n, 0, mix->frame_size*2 - n); 135 mix->af = mem_deref(mix->af); 136 base_frame = frame; 137 } 138 else { 139 base_frame = frame; 140 } 141 } 142 else { 143 base_frame = silence; 144 } 145 146 for (le=mix->srcl.head; le; le=le->next) { 147 148 struct aumix_source *src = le->data; 149 150 aubuf_read_samp(src->aubuf, src->frame, 151 mix->frame_size); 152 } 153 154 for (le=mix->srcl.head; le; le=le->next) { 155 156 struct aumix_source *src = le->data; 157 struct le *cle; 158 159 memcpy(mix_frame, base_frame, mix->frame_size*2); 160 161 for (cle=mix->srcl.head; cle; cle=cle->next) { 162 163 struct aumix_source *csrc = cle->data; 164 size_t i; 165 #if 1 166 /* skip self */ 167 if (csrc == src) 168 continue; 169 #endif 170 for (i=0; i<mix->frame_size; i++) 171 mix_frame[i] += csrc->frame[i]; 172 } 173 174 src->fh(mix_frame, mix->frame_size, src->arg); 175 } 176 177 ts += mix->ptime; 178 } 179 180 pthread_mutex_unlock(&mix->mutex); 181 182 out: 183 mem_deref(mix_frame); 184 mem_deref(silence); 185 mem_deref(frame); 186 187 return NULL; 188 } 189 190 191 /** 192 * Allocate a new Audio mixer 193 * 194 * @param mixp Pointer to allocated audio mixer 195 * @param srate Sample rate in [Hz] 196 * @param ch Number of channels 197 * @param ptime Packet time in [ms] 198 * 199 * @return 0 for success, otherwise error code 200 */ 201 int aumix_alloc(struct aumix **mixp, uint32_t srate, 202 uint8_t ch, uint32_t ptime) 203 { 204 struct aumix *mix; 205 int err; 206 207 if (!mixp || !srate || !ch || !ptime) 208 return EINVAL; 209 210 mix = mem_zalloc(sizeof(*mix), destructor); 211 if (!mix) 212 return ENOMEM; 213 214 mix->ptime = ptime; 215 mix->frame_size = srate * ch * ptime / 1000; 216 mix->srate = srate; 217 mix->ch = ch; 218 219 err = pthread_mutex_init(&mix->mutex, NULL); 220 if (err) 221 goto out; 222 223 err = pthread_cond_init(&mix->cond, NULL); 224 if (err) 225 goto out; 226 227 mix->run = true; 228 229 err = pthread_create(&mix->thread, NULL, aumix_thread, mix); 230 if (err) { 231 mix->run = false; 232 goto out; 233 } 234 235 out: 236 if (err) 237 mem_deref(mix); 238 else 239 *mixp = mix; 240 241 return err; 242 } 243 244 245 /** 246 * Load audio file for mixer announcements 247 * 248 * @param mix Audio mixer 249 * @param filepath Filename of audio file with complete path 250 * 251 * @return 0 for success, otherwise error code 252 */ 253 int aumix_playfile(struct aumix *mix, const char *filepath) 254 { 255 struct aufile_prm prm; 256 struct aufile *af; 257 int err; 258 259 if (!mix || !filepath) 260 return EINVAL; 261 262 err = aufile_open(&af, &prm, filepath, AUFILE_READ); 263 if (err) 264 return err; 265 266 if (prm.fmt != AUFMT_S16LE || prm.srate != mix->srate || 267 prm.channels != mix->ch) { 268 mem_deref(af); 269 return EINVAL; 270 } 271 272 pthread_mutex_lock(&mix->mutex); 273 mem_deref(mix->af); 274 mix->af = af; 275 pthread_mutex_unlock(&mix->mutex); 276 277 return 0; 278 } 279 280 281 /** 282 * Count number of audio sources in the audio mixer 283 * 284 * @param mix Audio mixer 285 * 286 * @return Number of audio sources 287 */ 288 uint32_t aumix_source_count(const struct aumix *mix) 289 { 290 if (!mix) 291 return 0; 292 293 return list_count(&mix->srcl); 294 } 295 296 297 /** 298 * Allocate an audio mixer source 299 * 300 * @param srcp Pointer to allocated audio source 301 * @param mix Audio mixer 302 * @param fh Mixer frame handler 303 * @param arg Handler argument 304 * 305 * @return 0 for success, otherwise error code 306 */ 307 int aumix_source_alloc(struct aumix_source **srcp, struct aumix *mix, 308 aumix_frame_h *fh, void *arg) 309 { 310 struct aumix_source *src; 311 size_t sz; 312 int err; 313 314 if (!srcp || !mix) 315 return EINVAL; 316 317 src = mem_zalloc(sizeof(*src), source_destructor); 318 if (!src) 319 return ENOMEM; 320 321 src->mix = mem_ref(mix); 322 src->fh = fh ? fh : dummy_frame_handler; 323 src->arg = arg; 324 325 sz = mix->frame_size*2; 326 327 src->frame = mem_alloc(sz, NULL); 328 if (!src->frame) { 329 err = ENOMEM; 330 goto out; 331 } 332 333 err = aubuf_alloc(&src->aubuf, sz * 6, sz * 12); 334 if (err) 335 goto out; 336 337 out: 338 if (err) 339 mem_deref(src); 340 else 341 *srcp = src; 342 343 return err; 344 } 345 346 347 /** 348 * Enable/disable aumix source 349 * 350 * @param src Audio mixer source 351 * @param enable True to enable, false to disable 352 */ 353 void aumix_source_enable(struct aumix_source *src, bool enable) 354 { 355 struct aumix *mix; 356 357 if (!src) 358 return; 359 360 if (src->le.list && enable) 361 return; 362 363 if (!src->le.list && !enable) 364 return; 365 366 mix = src->mix; 367 368 pthread_mutex_lock(&mix->mutex); 369 370 if (enable) { 371 list_append(&mix->srcl, &src->le, src); 372 pthread_cond_signal(&mix->cond); 373 } 374 else { 375 list_unlink(&src->le); 376 } 377 378 pthread_mutex_unlock(&mix->mutex); 379 } 380 381 382 /** 383 * Write PCM samples for a given source to the audio mixer 384 * 385 * @param src Audio mixer source 386 * @param sampv PCM samples 387 * @param sampc Number of samples 388 * 389 * @return 0 for success, otherwise error code 390 */ 391 int aumix_source_put(struct aumix_source *src, const int16_t *sampv, 392 size_t sampc) 393 { 394 if (!src || !sampv) 395 return EINVAL; 396 397 return aubuf_write_samp(src->aubuf, sampv, sampc); 398 } 399 400 401 /** 402 * Flush the audio buffer of a given audio mixer source 403 * 404 * @param src Audio mixer source 405 */ 406 void aumix_source_flush(struct aumix_source *src) 407 { 408 if (!src) 409 return; 410 411 aubuf_flush(src->aubuf); 412 } 413