audio-io.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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 3 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. uint64_t base_timestamp;
  24. uint64_t last_timestamp;
  25. /* states whether this line is still being used. if not, then when the
  26. * buffer is depleted, it's destroyed */
  27. bool alive;
  28. };
  29. static inline void audio_line_destroy_data(struct audio_line *line)
  30. {
  31. circlebuf_free(&line->buffer);
  32. bfree(line);
  33. }
  34. struct audio_output {
  35. struct audio_info info;
  36. size_t block_size;
  37. media_t media;
  38. media_output_t output;
  39. pthread_t thread;
  40. event_t stop_event;
  41. DARRAY(uint8_t) pending_bytes;
  42. bool initialized;
  43. pthread_mutex_t line_mutex;
  44. DARRAY(struct audio_line*) lines;
  45. };
  46. static inline void audio_output_removeline(struct audio_output *audio,
  47. struct audio_line *line)
  48. {
  49. pthread_mutex_lock(&audio->line_mutex);
  50. da_erase_item(audio->lines, &line);
  51. pthread_mutex_unlock(&audio->line_mutex);
  52. audio_line_destroy_data(line);
  53. }
  54. /* ------------------------------------------------------------------------- */
  55. static void *audio_thread(void *param)
  56. {
  57. struct audio_output *audio = param;
  58. while (event_try(&audio->stop_event) == EAGAIN) {
  59. /* TODO */
  60. }
  61. return NULL;
  62. }
  63. /* ------------------------------------------------------------------------- */
  64. static inline bool valid_audio_params(struct audio_info *info)
  65. {
  66. return info->format && info->name && info->samples_per_sec > 0 &&
  67. info->speakers > 0;
  68. }
  69. static inline bool ao_add_to_media(audio_t audio)
  70. {
  71. struct media_output_info oi;
  72. oi.obj = audio;
  73. oi.connect = NULL;
  74. oi.format = NULL; /* TODO */
  75. audio->output = media_output_create(&oi);
  76. if (!audio->output)
  77. return false;
  78. media_add_output(audio->media, audio->output);
  79. return true;
  80. }
  81. int audio_output_open(audio_t *audio, media_t media, struct audio_info *info)
  82. {
  83. struct audio_output *out;
  84. if (!valid_audio_params(info))
  85. return AUDIO_OUTPUT_INVALIDPARAM;
  86. out = bmalloc(sizeof(struct audio_output));
  87. memset(out, 0, sizeof(struct audio_output));
  88. memcpy(&out->info, info, sizeof(struct audio_info));
  89. pthread_mutex_init_value(&out->line_mutex);
  90. out->media = media;
  91. out->block_size = get_audio_channels(info->speakers) *
  92. get_audio_bytes_per_channel(info->format);
  93. if (pthread_mutex_init(&out->line_mutex, NULL) != 0)
  94. goto fail;
  95. if (event_init(&out->stop_event, true) != 0)
  96. goto fail;
  97. if (!ao_add_to_media(out))
  98. goto fail;
  99. if (pthread_create(&out->thread, NULL, audio_thread, out) != 0)
  100. goto fail;
  101. out->initialized = true;
  102. *audio = out;
  103. return AUDIO_OUTPUT_SUCCESS;
  104. fail:
  105. audio_output_close(out);
  106. return AUDIO_OUTPUT_FAIL;
  107. }
  108. audio_line_t audio_output_createline(audio_t audio)
  109. {
  110. struct audio_line *line = bmalloc(sizeof(struct audio_line));
  111. memset(line, 0, sizeof(struct audio_line));
  112. line->alive = true;
  113. pthread_mutex_lock(&audio->line_mutex);
  114. da_push_back(audio->lines, &line);
  115. pthread_mutex_unlock(&audio->line_mutex);
  116. return line;
  117. }
  118. const struct audio_info *audio_output_getinfo(audio_t audio)
  119. {
  120. return &audio->info;
  121. }
  122. void audio_output_close(audio_t audio)
  123. {
  124. void *thread_ret;
  125. size_t i;
  126. if (!audio)
  127. return;
  128. if (audio->initialized) {
  129. event_signal(&audio->stop_event);
  130. pthread_join(audio->thread, &thread_ret);
  131. }
  132. for (i = 0; i < audio->lines.num; i++)
  133. audio_line_destroy_data(audio->lines.array[i]);
  134. da_free(audio->lines);
  135. media_remove_output(audio->media, audio->output);
  136. event_destroy(&audio->stop_event);
  137. pthread_mutex_destroy(&audio->line_mutex);
  138. bfree(audio);
  139. }
  140. void audio_line_destroy(struct audio_line *line)
  141. {
  142. if (line) {
  143. if (!line->buffer.size)
  144. audio_output_removeline(line->audio, line);
  145. else
  146. line->alive = false;
  147. }
  148. }
  149. size_t audio_output_blocksize(audio_t audio)
  150. {
  151. return audio->block_size;
  152. }
  153. static inline uint64_t convert_to_sample_offset(audio_t audio, uint64_t offset)
  154. {
  155. return (uint64_t)((double)offset *
  156. (1000000000.0 / (double)audio->info.samples_per_sec));
  157. }
  158. void audio_line_output(audio_line_t line, const struct audio_data *data)
  159. {
  160. if (!line->buffer.size) {
  161. line->base_timestamp = data->timestamp;
  162. circlebuf_push_back(&line->buffer, data->data,
  163. data->frames * line->audio->block_size);
  164. } else {
  165. uint64_t position = data->timestamp - line->base_timestamp;
  166. position = convert_to_sample_offset(line->audio, position);
  167. position *= line->audio->block_size;
  168. circlebuf_place(&line->buffer, (size_t)position, data->data,
  169. data->frames * line->audio->block_size);
  170. }
  171. }