You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
преди 8 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2016 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "usb_dev.h"
  31. #include "usb_audio.h"
  32. #include "HardwareSerial.h"
  33. #include <string.h> // for memcpy()
  34. #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h
  35. #if F_CPU >= 20000000
  36. bool AudioInputUSB::update_responsibility;
  37. audio_block_t * AudioInputUSB::incoming_left;
  38. audio_block_t * AudioInputUSB::incoming_right;
  39. audio_block_t * AudioInputUSB::ready_left;
  40. audio_block_t * AudioInputUSB::ready_right;
  41. uint16_t AudioInputUSB::incoming_count;
  42. uint8_t AudioInputUSB::receive_flag;
  43. #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4)))
  44. uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR;
  45. uint32_t usb_audio_sync_feedback DMABUFATTR;
  46. uint8_t usb_audio_receive_setting=0;
  47. static uint32_t feedback_accumulator = 185042824;
  48. void AudioInputUSB::begin(void)
  49. {
  50. incoming_count = 0;
  51. incoming_left = NULL;
  52. incoming_right = NULL;
  53. ready_left = NULL;
  54. ready_right = NULL;
  55. receive_flag = 0;
  56. // update_responsibility = update_setup();
  57. // TODO: update responsibility is tough, partly because the USB
  58. // interrupts aren't sychronous to the audio library block size,
  59. // but also because the PC may stop transmitting data, which
  60. // means we no longer get receive callbacks from usb_dev.
  61. update_responsibility = false;
  62. //usb_audio_sync_feedback = 722824;
  63. //usb_audio_sync_feedback = 723700; // too fast?
  64. usb_audio_sync_feedback = 722534; // too slow
  65. }
  66. static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
  67. {
  68. // TODO: optimize...
  69. while (len > 0) {
  70. uint32_t n = *src++;
  71. *left++ = n & 0xFFFF;
  72. *right++ = n >> 16;
  73. len--;
  74. }
  75. }
  76. // Called from the USB interrupt when an isochronous packet arrives
  77. // we must completely remove it from the receive buffer before returning
  78. //
  79. void usb_audio_receive_callback(unsigned int len)
  80. {
  81. unsigned int count, avail;
  82. audio_block_t *left, *right;
  83. const uint32_t *data;
  84. AudioInputUSB::receive_flag = 1;
  85. len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
  86. data = (const uint32_t *)usb_audio_receive_buffer;
  87. count = AudioInputUSB::incoming_count;
  88. left = AudioInputUSB::incoming_left;
  89. right = AudioInputUSB::incoming_right;
  90. if (left == NULL) {
  91. left = AudioStream::allocate();
  92. if (left == NULL) return;
  93. AudioInputUSB::incoming_left = left;
  94. }
  95. if (right == NULL) {
  96. right = AudioStream::allocate();
  97. if (right == NULL) return;
  98. AudioInputUSB::incoming_right = right;
  99. }
  100. while (len > 0) {
  101. avail = AUDIO_BLOCK_SAMPLES - count;
  102. if (len < avail) {
  103. copy_to_buffers(data, left->data + count, right->data + count, len);
  104. AudioInputUSB::incoming_count = count + len;
  105. return;
  106. } else if (avail > 0) {
  107. copy_to_buffers(data, left->data + count, right->data + count, avail);
  108. data += avail;
  109. len -= avail;
  110. if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) {
  111. // buffer overrun, PC sending too fast
  112. AudioInputUSB::incoming_count = count + avail;
  113. //if (len > 0) {
  114. //serial_print("!");
  115. //serial_phex(len);
  116. //}
  117. return;
  118. }
  119. send:
  120. AudioInputUSB::ready_left = left;
  121. AudioInputUSB::ready_right = right;
  122. //if (AudioInputUSB::update_responsibility) AudioStream::update_all();
  123. left = AudioStream::allocate();
  124. if (left == NULL) {
  125. AudioInputUSB::incoming_left = NULL;
  126. AudioInputUSB::incoming_right = NULL;
  127. AudioInputUSB::incoming_count = 0;
  128. return;
  129. }
  130. right = AudioStream::allocate();
  131. if (right == NULL) {
  132. AudioStream::release(left);
  133. AudioInputUSB::incoming_left = NULL;
  134. AudioInputUSB::incoming_right = NULL;
  135. AudioInputUSB::incoming_count = 0;
  136. return;
  137. }
  138. AudioInputUSB::incoming_left = left;
  139. AudioInputUSB::incoming_right = right;
  140. count = 0;
  141. } else {
  142. if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return;
  143. goto send; // recover from buffer overrun
  144. }
  145. }
  146. AudioInputUSB::incoming_count = count;
  147. }
  148. void AudioInputUSB::update(void)
  149. {
  150. audio_block_t *left, *right;
  151. __disable_irq();
  152. left = ready_left;
  153. ready_left = NULL;
  154. right = ready_right;
  155. ready_right = NULL;
  156. uint16_t c = incoming_count;
  157. uint8_t f = receive_flag;
  158. receive_flag = 0;
  159. __enable_irq();
  160. if (f) {
  161. int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c;
  162. feedback_accumulator += diff;
  163. // TODO: min/max sanity check for feedback_accumulator??
  164. usb_audio_sync_feedback = (feedback_accumulator >> 8) + diff * 3;
  165. //if (diff > 0) {
  166. //serial_print(".");
  167. //} else if (diff < 0) {
  168. //serial_print("^");
  169. //}
  170. }
  171. //serial_phex(c);
  172. //serial_print(".");
  173. if (!left || !right) {
  174. //serial_print("#"); // buffer underrun - PC sending too slow
  175. if (f) feedback_accumulator += 10 << 8;
  176. }
  177. if (left) {
  178. transmit(left, 0);
  179. release(left);
  180. }
  181. if (right) {
  182. transmit(right, 1);
  183. release(right);
  184. }
  185. }
  186. bool AudioOutputUSB::update_responsibility;
  187. audio_block_t * AudioOutputUSB::left_1st;
  188. audio_block_t * AudioOutputUSB::left_2nd;
  189. audio_block_t * AudioOutputUSB::right_1st;
  190. audio_block_t * AudioOutputUSB::right_2nd;
  191. uint16_t AudioOutputUSB::offset_1st;
  192. uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR;
  193. uint8_t usb_audio_transmit_setting=0;
  194. void AudioOutputUSB::begin(void)
  195. {
  196. update_responsibility = false;
  197. left_1st = NULL;
  198. right_1st = NULL;
  199. }
  200. static void copy_from_buffers(uint32_t *dst, int16_t *left, int16_t *right, unsigned int len)
  201. {
  202. // TODO: optimize...
  203. while (len > 0) {
  204. *dst++ = (*right++ << 16) | (*left++ & 0xFFFF);
  205. len--;
  206. }
  207. }
  208. void AudioOutputUSB::update(void)
  209. {
  210. audio_block_t *left, *right;
  211. left = receiveReadOnly(0); // input 0 = left channel
  212. right = receiveReadOnly(1); // input 1 = right channel
  213. if (usb_audio_transmit_setting == 0) {
  214. if (left) release(left);
  215. if (right) release(right);
  216. if (left_1st) { release(left_1st); left_1st = NULL; }
  217. if (left_2nd) { release(left_2nd); left_2nd = NULL; }
  218. if (right_1st) { release(right_1st); right_1st = NULL; }
  219. if (right_2nd) { release(right_2nd); right_2nd = NULL; }
  220. offset_1st = 0;
  221. return;
  222. }
  223. if (left == NULL) {
  224. if (right == NULL) return;
  225. right->ref_count++;
  226. left = right;
  227. } else if (right == NULL) {
  228. left->ref_count++;
  229. right = left;
  230. }
  231. __disable_irq();
  232. if (left_1st == NULL) {
  233. left_1st = left;
  234. right_1st = right;
  235. offset_1st = 0;
  236. } else if (left_2nd == NULL) {
  237. left_2nd = left;
  238. right_2nd = right;
  239. } else {
  240. // buffer overrun - PC is consuming too slowly
  241. audio_block_t *discard1 = left_1st;
  242. left_1st = left_2nd;
  243. left_2nd = left;
  244. audio_block_t *discard2 = right_1st;
  245. right_1st = right_2nd;
  246. right_2nd = right;
  247. offset_1st = 0; // TODO: discard part of this data?
  248. //serial_print("*");
  249. release(discard1);
  250. release(discard2);
  251. }
  252. __enable_irq();
  253. }
  254. // Called from the USB interrupt when ready to transmit another
  255. // isochronous packet. If we place data into the transmit buffer,
  256. // the return is the number of bytes. Otherwise, return 0 means
  257. // no data to transmit
  258. unsigned int usb_audio_transmit_callback(void)
  259. {
  260. static uint32_t count=5;
  261. uint32_t avail, num, target, offset, len=0;
  262. audio_block_t *left, *right;
  263. if (++count < 9) { // TODO: dynamic adjust to match USB rate
  264. target = 44;
  265. } else {
  266. count = 0;
  267. target = 45;
  268. }
  269. while (len < target) {
  270. num = target - len;
  271. left = AudioOutputUSB::left_1st;
  272. if (left == NULL) {
  273. // buffer underrun - PC is consuming too quickly
  274. memset(usb_audio_transmit_buffer + len, 0, num * 4);
  275. //serial_print("%");
  276. break;
  277. }
  278. right = AudioOutputUSB::right_1st;
  279. offset = AudioOutputUSB::offset_1st;
  280. avail = AUDIO_BLOCK_SAMPLES - offset;
  281. if (num > avail) num = avail;
  282. copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len,
  283. left->data + offset, right->data + offset, num);
  284. len += num;
  285. offset += num;
  286. if (offset >= AUDIO_BLOCK_SAMPLES) {
  287. AudioStream::release(left);
  288. AudioStream::release(right);
  289. AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd;
  290. AudioOutputUSB::left_2nd = NULL;
  291. AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd;
  292. AudioOutputUSB::right_2nd = NULL;
  293. AudioOutputUSB::offset_1st = 0;
  294. } else {
  295. AudioOutputUSB::offset_1st = offset;
  296. }
  297. }
  298. return target * 4;
  299. }
  300. #endif // F_CPU
  301. #endif // AUDIO_INTERFACE