JACK tools
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.

227 lines
6.0KB

  1. // ----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. //
  18. // ----------------------------------------------------------------------------
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include <jack/jack.h>
  24. #include "alsathread.h"
  25. Alsathread::Alsathread (Alsa_pcmi *alsadev, int mode) :
  26. _alsadev (alsadev ),
  27. _mode (mode),
  28. _state (INIT),
  29. _fsize (alsadev->fsize ()),
  30. _audioq (0),
  31. _commq (0),
  32. _alsaq (0)
  33. {
  34. // Compute DLL filter coefficients.
  35. _dt = (double) _fsize / _alsadev->fsamp ();
  36. _w1 = 2 * M_PI * 0.1 * _dt;
  37. _w2 = _w1 * _w1;
  38. _w1 *= 1.6;
  39. // Time wraps around after 2^28 usecs.
  40. _tq = ldexp (1e-6, 28);
  41. }
  42. Alsathread::~Alsathread (void)
  43. {
  44. _alsadev->pcm_stop ();
  45. }
  46. int Alsathread::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio)
  47. {
  48. // Start the ALSA thread.
  49. _audioq = audioq;
  50. _commq = commq;
  51. _alsaq = alsaq;
  52. _state = WAIT;
  53. if (thr_start (SCHED_FIFO, rtprio, 0x10000)) return 1;
  54. return 0;
  55. }
  56. void Alsathread::send (int k, double t)
  57. {
  58. Adata *D;
  59. // Send (state, frame count, timestamp) to Jack thread.
  60. if (_alsaq->wr_avail ())
  61. {
  62. D = _alsaq->wr_datap ();
  63. D->_state = _state;
  64. D->_nsamp = k;
  65. D->_timer = t;
  66. _alsaq->wr_commit ();
  67. }
  68. }
  69. // The following two functions transfer data between the audio queue
  70. // and the ALSA device. Note that we do *not* check the queue's fill
  71. // state, and it may overrun or underrun. It actually will in the first
  72. // few iterations and in error conditions. This is entirely intentional.
  73. // The queue keeps correct read and write counters even in that case,
  74. // and the main control loop and error recovery depend on it working
  75. // and being used in this way.
  76. int Alsathread::capture (void)
  77. {
  78. int c, n, k;
  79. float *p;
  80. // Start reading from ALSA device.
  81. _alsadev->capt_init (_fsize);
  82. if (_state == PROC)
  83. {
  84. // Input frames from the ALSA device to the audio queue.
  85. // The outer loop takes care of wraparound.
  86. for (n = _fsize; n; n -= k)
  87. {
  88. p = _audioq->wr_datap (); // Audio queue write pointer.
  89. k = _audioq->wr_linav (); // Number of frames that can be
  90. if (k > n) k = n; // written without wraparound.
  91. for (c = 0; c < _audioq->nchan (); c++)
  92. {
  93. // Copy and interleave one channel.
  94. _alsadev->capt_chan (c, p + c, k, _audioq->nchan ());
  95. }
  96. _audioq->wr_commit (k); // Update audio queue state.
  97. }
  98. }
  99. // Finish reading from ALSA device.
  100. _alsadev->capt_done (_fsize);
  101. return _fsize;
  102. }
  103. int Alsathread::playback (void)
  104. {
  105. int c, n, k;
  106. float *p;
  107. // Start writing to ALSA device.
  108. _alsadev->play_init (_fsize);
  109. c = 0;
  110. if (_state == PROC)
  111. {
  112. // Output frames from the audio queue to the ALSA device.
  113. // The outer loop takes care of wraparound.
  114. for (n = _fsize; n; n -= k)
  115. {
  116. p = _audioq->rd_datap (); // Audio queue read pointer.
  117. k = _audioq->rd_linav (); // Number of frames that can
  118. if (k > n) k = n; // be read without wraparound.
  119. for (c = 0; c < _audioq->nchan (); c++)
  120. {
  121. // De-interleave and copy one channel.
  122. _alsadev->play_chan (c, p + c, k, _audioq->nchan ());
  123. }
  124. _audioq->rd_commit (k); // Update audio queue state.
  125. }
  126. }
  127. // Clear all or remaining channels.
  128. while (c < _alsadev->nplay ()) _alsadev->clear_chan (c++, _fsize);
  129. // Finish writing to ALSA device.
  130. _alsadev->play_done (_fsize);
  131. return _fsize;
  132. }
  133. void Alsathread::thr_main (void)
  134. {
  135. int na, nu;
  136. double tw, er;
  137. _alsadev->pcm_start ();
  138. while (_state != TERM)
  139. {
  140. // Wait for next cycle, then take timestamp.
  141. na = _alsadev->pcm_wait ();
  142. tw = 1e-6 * (int)(jack_get_time () & 0x0FFFFFFF);
  143. // Check for errors - requires restart.
  144. if (_alsadev->state () && (na == 0))
  145. {
  146. _state = WAIT;
  147. send (0, 0);
  148. continue;
  149. }
  150. // Check for commands from the Jack thread.
  151. if (_commq->rd_avail ())
  152. {
  153. _state = _commq->rd_int32 ();
  154. if (_state == PROC) _first = true;
  155. if (_state == TERM) send (0, 0);
  156. }
  157. // We could have more than one period.
  158. nu = 0;
  159. while (na >= _fsize)
  160. {
  161. // Transfer frames.
  162. if (_mode == PLAY) nu += playback ();
  163. else nu += capture ();
  164. // Update loop condition.
  165. na -= _fsize;
  166. // Run the DLL if in PROC state.
  167. if (_state == PROC)
  168. {
  169. if (_first)
  170. {
  171. // Init DLL in first iteration.
  172. _first = false;
  173. _t0 = tw;
  174. _t1 = tw + _dt;
  175. // Required for initial delay calculation.
  176. if (_mode == PLAY) nu -= _fsize;
  177. else nu += _fsize;
  178. }
  179. else
  180. {
  181. // Update the DLL.
  182. er = tw - _t1;
  183. // Check for time wraparound.
  184. if (er < -200)
  185. {
  186. _t1 -= _tq;
  187. er = tw - _t1;
  188. }
  189. // If we have more than one period, use
  190. // the time error only for the last one.
  191. if (na >= _fsize) er = 0;
  192. _t0 = _t1;
  193. _t1 += _w1 * er + _dt;
  194. _dt += _w2 * er;
  195. }
  196. }
  197. }
  198. // Send number of frames used and timestamp to Jack thread.
  199. if (_state == PROC) send (nu, _t1);
  200. }
  201. _alsadev->pcm_stop ();
  202. }