jack2 codebase
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
5.9KB

  1. // ----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2012-2018 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 "alsathread.h"
  24. #include "timers.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. }
  40. Alsathread::~Alsathread (void)
  41. {
  42. if (_state != INIT)
  43. {
  44. _state = TERM;
  45. thr_wait ();
  46. }
  47. else
  48. {
  49. _alsadev->pcm_stop ();
  50. }
  51. }
  52. int Alsathread::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio)
  53. {
  54. // Start the ALSA thread.
  55. _audioq = audioq;
  56. _commq = commq;
  57. _alsaq = alsaq;
  58. _state = WAIT;
  59. if (thr_start (SCHED_FIFO, rtprio, 0x10000)) return 1;
  60. return 0;
  61. }
  62. void Alsathread::send (int k, double t)
  63. {
  64. Adata *D;
  65. // Send (state, frame count, timestamp) to Jack thread.
  66. if (_alsaq->wr_avail ())
  67. {
  68. D = _alsaq->wr_datap ();
  69. D->_state = _state;
  70. D->_nsamp = k;
  71. D->_timer = t;
  72. _alsaq->wr_commit ();
  73. }
  74. }
  75. // The following two functions transfer data between the audio queue
  76. // and the ALSA device. Note that we do *not* check the queue's fill
  77. // state, and it may overrun or underrun. It actually will in the first
  78. // few iterations and in error conditions. This is entirely intentional.
  79. // The queue keeps correct read and write counters even in that case,
  80. // and the main control loop and error recovery depend on it working
  81. // and being used in this way.
  82. int Alsathread::capture (void)
  83. {
  84. int c, n, k;
  85. float *p;
  86. // Start reading from ALSA device.
  87. _alsadev->capt_init (_fsize);
  88. if (_state == PROC)
  89. {
  90. // Input frames from the ALSA device to the audio queue.
  91. // The outer loop takes care of wraparound.
  92. for (n = _fsize; n; n -= k)
  93. {
  94. p = _audioq->wr_datap (); // Audio queue write pointer.
  95. k = _audioq->wr_linav (); // Number of frames that can be
  96. if (k > n) k = n; // written without wraparound.
  97. for (c = 0; c < _audioq->nchan (); c++)
  98. {
  99. // Copy and interleave one channel.
  100. _alsadev->capt_chan (c, p + c, k, _audioq->nchan ());
  101. }
  102. _audioq->wr_commit (k); // Update audio queue state.
  103. }
  104. }
  105. // Finish reading from ALSA device.
  106. _alsadev->capt_done (_fsize);
  107. return _fsize;
  108. }
  109. int Alsathread::playback (void)
  110. {
  111. int c, n, k;
  112. float *p;
  113. // Start writing to ALSA device.
  114. _alsadev->play_init (_fsize);
  115. c = 0;
  116. if (_state == PROC)
  117. {
  118. // Output frames from the audio queue to the ALSA device.
  119. // The outer loop takes care of wraparound.
  120. for (n = _fsize; n; n -= k)
  121. {
  122. p = _audioq->rd_datap (); // Audio queue read pointer.
  123. k = _audioq->rd_linav (); // Number of frames that can
  124. if (k > n) k = n; // be read without wraparound.
  125. for (c = 0; c < _audioq->nchan (); c++)
  126. {
  127. // De-interleave and copy one channel.
  128. _alsadev->play_chan (c, p + c, k, _audioq->nchan ());
  129. }
  130. _audioq->rd_commit (k); // Update audio queue state.
  131. }
  132. }
  133. // Clear all or remaining channels.
  134. while (c < _alsadev->nplay ()) _alsadev->clear_chan (c++, _fsize);
  135. // Finish writing to ALSA device.
  136. _alsadev->play_done (_fsize);
  137. return _fsize;
  138. }
  139. void Alsathread::thr_main (void)
  140. {
  141. int na, nu;
  142. double tw, er;
  143. _alsadev->pcm_start ();
  144. while (_state != TERM)
  145. {
  146. // Wait for next cycle, then take timestamp.
  147. na = _alsadev->pcm_wait ();
  148. tw = tjack (jack_get_time ());
  149. // Check for errors - requires restart.
  150. if (_alsadev->state () && (na == 0))
  151. {
  152. _state = WAIT;
  153. send (0, 0);
  154. usleep (10000);
  155. continue;
  156. }
  157. // Check for commands from the Jack thread.
  158. if (_commq->rd_avail ())
  159. {
  160. _state = _commq->rd_int32 ();
  161. if (_state == PROC) _first = true;
  162. if (_state == TERM) send (0, 0);
  163. }
  164. // We could have more than one period.
  165. nu = 0;
  166. while (na >= _fsize)
  167. {
  168. // Transfer frames.
  169. if (_mode == PLAY) nu += playback ();
  170. else nu += capture ();
  171. // Update loop condition.
  172. na -= _fsize;
  173. // Run the DLL if in PROC state.
  174. if (_state == PROC)
  175. {
  176. if (_first)
  177. {
  178. // Init DLL in first iteration.
  179. _first = false;
  180. _dt = (double) _fsize / _alsadev->fsamp ();
  181. _t0 = tw;
  182. _t1 = tw + _dt;
  183. }
  184. else
  185. {
  186. // Update the DLL.
  187. // If we have more than one period, use
  188. // the time error only for the last one.
  189. if (na >= _fsize) er = 0;
  190. else er = tjack_diff (tw, _t1);
  191. _t0 = _t1;
  192. _t1 = tjack_diff (_t1 + _dt + _w1 * er, 0.0);
  193. _dt += _w2 * er;
  194. }
  195. }
  196. }
  197. // Send number of frames used and timestamp to Jack thread.
  198. if (_state == PROC) send (nu, _t1);
  199. }
  200. _alsadev->pcm_stop ();
  201. }