audio-io.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /******************************************************************************
  2. Copyright (C) 2013 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "../util/threading.h"
  15. #include "../util/darray.h"
  16. #include "../util/circlebuf.h"
  17. #include "../util/platform.h"
  18. #include "audio-io.h"
  19. /* TODO: Incomplete */
  20. struct audio_line {
  21. struct audio_output *audio;
  22. struct circlebuf buffer;
  23. DARRAY(uint8_t) volume_buffer;
  24. uint64_t base_timestamp;
  25. uint64_t last_timestamp;
  26. /* states whether this line is still being used. if not, then when the
  27. * buffer is depleted, it's destroyed */
  28. bool alive;
  29. };
  30. static inline void audio_line_destroy_data(struct audio_line *line)
  31. {
  32. circlebuf_free(&line->buffer);
  33. da_free(line->volume_buffer);
  34. bfree(line);
  35. }
  36. struct audio_output {
  37. struct audio_info info;
  38. size_t block_size;
  39. size_t channels;
  40. media_t media;
  41. media_output_t output;
  42. pthread_t thread;
  43. event_t stop_event;
  44. DARRAY(uint8_t) pending_bytes;
  45. bool initialized;
  46. pthread_mutex_t line_mutex;
  47. DARRAY(struct audio_line*) lines;
  48. };
  49. static inline void audio_output_removeline(struct audio_output *audio,
  50. struct audio_line *line)
  51. {
  52. pthread_mutex_lock(&audio->line_mutex);
  53. da_erase_item(audio->lines, &line);
  54. pthread_mutex_unlock(&audio->line_mutex);
  55. audio_line_destroy_data(line);
  56. }
  57. /* ------------------------------------------------------------------------- */
  58. static void *audio_thread(void *param)
  59. {
  60. struct audio_output *audio = param;
  61. while (event_try(&audio->stop_event) == EAGAIN) {
  62. /* TODO */
  63. }
  64. return NULL;
  65. }
  66. /* ------------------------------------------------------------------------- */
  67. static inline bool valid_audio_params(struct audio_info *info)
  68. {
  69. return info->format && info->name && info->samples_per_sec > 0 &&
  70. info->speakers > 0;
  71. }
  72. static inline bool ao_add_to_media(audio_t audio)
  73. {
  74. struct media_output_info oi;
  75. oi.obj = audio;
  76. oi.connect = NULL;
  77. oi.format = NULL; /* TODO */
  78. audio->output = media_output_create(&oi);
  79. if (!audio->output)
  80. return false;
  81. media_add_output(audio->media, audio->output);
  82. return true;
  83. }
  84. int audio_output_open(audio_t *audio, media_t media, struct audio_info *info)
  85. {
  86. struct audio_output *out;
  87. if (!valid_audio_params(info))
  88. return AUDIO_OUTPUT_INVALIDPARAM;
  89. out = bmalloc(sizeof(struct audio_output));
  90. memset(out, 0, sizeof(struct audio_output));
  91. memcpy(&out->info, info, sizeof(struct audio_info));
  92. pthread_mutex_init_value(&out->line_mutex);
  93. out->media = media;
  94. out->channels = get_audio_channels(info->speakers);
  95. out->block_size = out->channels *
  96. get_audio_bytes_per_channel(info->format);
  97. if (pthread_mutex_init(&out->line_mutex, NULL) != 0)
  98. goto fail;
  99. if (event_init(&out->stop_event, true) != 0)
  100. goto fail;
  101. if (!ao_add_to_media(out))
  102. goto fail;
  103. if (pthread_create(&out->thread, NULL, audio_thread, out) != 0)
  104. goto fail;
  105. out->initialized = true;
  106. *audio = out;
  107. return AUDIO_OUTPUT_SUCCESS;
  108. fail:
  109. audio_output_close(out);
  110. return AUDIO_OUTPUT_FAIL;
  111. }
  112. audio_line_t audio_output_createline(audio_t audio)
  113. {
  114. struct audio_line *line = bmalloc(sizeof(struct audio_line));
  115. memset(line, 0, sizeof(struct audio_line));
  116. line->alive = true;
  117. pthread_mutex_lock(&audio->line_mutex);
  118. da_push_back(audio->lines, &line);
  119. pthread_mutex_unlock(&audio->line_mutex);
  120. return line;
  121. }
  122. const struct audio_info *audio_output_getinfo(audio_t audio)
  123. {
  124. return &audio->info;
  125. }
  126. void audio_output_close(audio_t audio)
  127. {
  128. void *thread_ret;
  129. size_t i;
  130. if (!audio)
  131. return;
  132. if (audio->initialized) {
  133. event_signal(&audio->stop_event);
  134. pthread_join(audio->thread, &thread_ret);
  135. }
  136. for (i = 0; i < audio->lines.num; i++)
  137. audio_line_destroy_data(audio->lines.array[i]);
  138. da_free(audio->lines);
  139. media_remove_output(audio->media, audio->output);
  140. event_destroy(&audio->stop_event);
  141. pthread_mutex_destroy(&audio->line_mutex);
  142. bfree(audio);
  143. }
  144. void audio_line_destroy(struct audio_line *line)
  145. {
  146. if (line) {
  147. if (!line->buffer.size)
  148. audio_output_removeline(line->audio, line);
  149. else
  150. line->alive = false;
  151. }
  152. }
  153. size_t audio_output_blocksize(audio_t audio)
  154. {
  155. return audio->block_size;
  156. }
  157. static inline uint64_t convert_to_sample_offset(audio_t audio, uint64_t offset)
  158. {
  159. return (uint64_t)((double)offset *
  160. (1000000000.0 / (double)audio->info.samples_per_sec));
  161. }
  162. static inline void mul_vol_u8bit(struct audio_line *line, float volume,
  163. size_t total_num)
  164. {
  165. uint8_t *vals = line->volume_buffer.array;
  166. int16_t vol = (int16_t)(volume * 127.0f);
  167. for (size_t i = 0; i < total_num; i++) {
  168. int16_t val = (int16_t)(vals[i] ^ 0x80) << 8;
  169. vals[i] = (uint8_t)((val * vol / 127) + 128);
  170. }
  171. }
  172. static inline void mul_vol_16bit(struct audio_line *line, float volume,
  173. size_t total_num)
  174. {
  175. uint16_t *vals = (uint16_t*)line->volume_buffer.array;
  176. int32_t vol = (int32_t)(volume * 32767.0f);
  177. for (size_t i = 0; i < total_num; i++)
  178. vals[i] = (int32_t)((int32_t)vals[i] * vol / 32767);
  179. }
  180. static inline float conv_24bit_to_float(uint8_t *vals)
  181. {
  182. int32_t val = ((int32_t)vals[0]) |
  183. ((int32_t)vals[1] << 8) |
  184. ((int32_t)vals[2] << 16);
  185. if ((val & 0x800000) != 0)
  186. val |= 0xFF000000;
  187. return (float)val / 8388607.0f;
  188. }
  189. static inline void conv_float_to_24bit(float fval, uint8_t *vals)
  190. {
  191. int32_t val = (int32_t)(fval * 8388607.0f);
  192. vals[0] = (val) & 0xFF;
  193. vals[1] = (val >> 8) & 0xFF;
  194. vals[2] = (val >> 16) & 0xFF;
  195. }
  196. static inline void mul_vol_24bit(struct audio_line *line, float volume,
  197. size_t total_num)
  198. {
  199. uint8_t *vals = line->volume_buffer.array;
  200. for (size_t i = 0; i < total_num; i++) {
  201. float val = conv_24bit_to_float(vals) * volume;
  202. conv_float_to_24bit(val, vals);
  203. vals += 3;
  204. }
  205. }
  206. static inline void mul_vol_32bit(struct audio_line *line, float volume,
  207. size_t total_num)
  208. {
  209. int32_t *vals = (int32_t*)line->volume_buffer.array;
  210. for (size_t i = 0; i < total_num; i++) {
  211. float val = (float)vals[i] / 2147483647.0f;
  212. vals[i] = (int32_t)(val * volume / 2147483647.0f);
  213. }
  214. }
  215. static inline void mul_vol_float(struct audio_line *line, float volume,
  216. size_t total_num)
  217. {
  218. float *vals = (float*)line->volume_buffer.array;
  219. for (size_t i = 0; i < total_num; i++)
  220. vals[i] *= volume;
  221. }
  222. static void audio_line_place_data(struct audio_line *line,
  223. const struct audio_data *data, size_t position)
  224. {
  225. size_t total_size = data->frames * line->audio->block_size;
  226. size_t total_num = data->frames * line->audio->channels;
  227. da_copy_array(line->volume_buffer, data->data, total_size);
  228. switch (line->audio->info.format) {
  229. case AUDIO_FORMAT_U8BIT:
  230. mul_vol_u8bit(line, data->volume, total_num);
  231. break;
  232. case AUDIO_FORMAT_16BIT:
  233. mul_vol_16bit(line, data->volume, total_num);
  234. break;
  235. case AUDIO_FORMAT_32BIT:
  236. mul_vol_32bit(line, data->volume, total_num);
  237. break;
  238. case AUDIO_FORMAT_FLOAT:
  239. mul_vol_float(line, data->volume, total_num);
  240. break;
  241. case AUDIO_FORMAT_UNKNOWN:
  242. break;
  243. }
  244. circlebuf_place(&line->buffer, position, line->volume_buffer.array,
  245. total_size);
  246. }
  247. void audio_line_output(audio_line_t line, const struct audio_data *data)
  248. {
  249. if (!line->buffer.size) {
  250. line->base_timestamp = data->timestamp;
  251. audio_line_place_data(line, data, 0);
  252. } else {
  253. uint64_t position = data->timestamp - line->base_timestamp;
  254. position = convert_to_sample_offset(line->audio, position);
  255. position *= line->audio->block_size;
  256. audio_line_place_data(line, data, (size_t)position);
  257. }
  258. }