Remove non-jackdbus man pages
[jackdbus.git] / tools / zalsa / alsathread.cc
blobbb5cf75b29bb4cfdf427283e205f8f1b2ca68c6e
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.
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/>.
18 // ----------------------------------------------------------------------------
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include "alsathread.h"
26 #include "timers.h"
29 Alsathread::Alsathread (Alsa_pcmi *alsadev, int mode) :
30 _alsadev (alsadev ),
31 _mode (mode),
32 _state (INIT),
33 _fsize (alsadev->fsize ()),
34 _audioq (0),
35 _commq (0),
36 _alsaq (0)
38 // Compute DLL filter coefficients.
39 _dt = (double) _fsize / _alsadev->fsamp ();
40 _w1 = 2 * M_PI * 0.1 * _dt;
41 _w2 = _w1 * _w1;
42 _w1 *= 1.6;
46 Alsathread::~Alsathread (void)
48 if (_state != INIT)
50 _state = TERM;
51 thr_wait ();
53 else
55 _alsadev->pcm_stop ();
60 int Alsathread::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio)
62 // Start the ALSA thread.
63 _audioq = audioq;
64 _commq = commq;
65 _alsaq = alsaq;
66 _state = WAIT;
67 if (thr_start (SCHED_FIFO, rtprio, 0x10000)) return 1;
68 return 0;
72 void Alsathread::send (int k, double t)
74 Adata *D;
76 // Send (state, frame count, timestamp) to Jack thread.
77 if (_alsaq->wr_avail ())
79 D = _alsaq->wr_datap ();
80 D->_state = _state;
81 D->_nsamp = k;
82 D->_timer = t;
83 _alsaq->wr_commit ();
88 // The following two functions transfer data between the audio queue
89 // and the ALSA device. Note that we do *not* check the queue's fill
90 // state, and it may overrun or underrun. It actually will in the first
91 // few iterations and in error conditions. This is entirely intentional.
92 // The queue keeps correct read and write counters even in that case,
93 // and the main control loop and error recovery depend on it working
94 // and being used in this way.
96 int Alsathread::capture (void)
98 int c, n, k;
99 float *p;
101 // Start reading from ALSA device.
102 _alsadev->capt_init (_fsize);
103 if (_state == PROC)
105 // Input frames from the ALSA device to the audio queue.
106 // The outer loop takes care of wraparound.
107 for (n = _fsize; n; n -= k)
109 p = _audioq->wr_datap (); // Audio queue write pointer.
110 k = _audioq->wr_linav (); // Number of frames that can be
111 if (k > n) k = n; // written without wraparound.
112 for (c = 0; c < _audioq->nchan (); c++)
114 // Copy and interleave one channel.
115 _alsadev->capt_chan (c, p + c, k, _audioq->nchan ());
117 _audioq->wr_commit (k); // Update audio queue state.
120 // Finish reading from ALSA device.
121 _alsadev->capt_done (_fsize);
122 return _fsize;
126 int Alsathread::playback (void)
128 int c, n, k;
129 float *p;
131 // Start writing to ALSA device.
132 _alsadev->play_init (_fsize);
133 c = 0;
134 if (_state == PROC)
136 // Output frames from the audio queue to the ALSA device.
137 // The outer loop takes care of wraparound.
138 for (n = _fsize; n; n -= k)
140 p = _audioq->rd_datap (); // Audio queue read pointer.
141 k = _audioq->rd_linav (); // Number of frames that can
142 if (k > n) k = n; // be read without wraparound.
143 for (c = 0; c < _audioq->nchan (); c++)
145 // De-interleave and copy one channel.
146 _alsadev->play_chan (c, p + c, k, _audioq->nchan ());
148 _audioq->rd_commit (k); // Update audio queue state.
151 // Clear all or remaining channels.
152 while (c < _alsadev->nplay ()) _alsadev->clear_chan (c++, _fsize);
153 // Finish writing to ALSA device.
154 _alsadev->play_done (_fsize);
155 return _fsize;
159 void Alsathread::thr_main (void)
161 int na, nu;
162 double tw, er;
164 _alsadev->pcm_start ();
165 while (_state != TERM)
167 // Wait for next cycle, then take timestamp.
168 na = _alsadev->pcm_wait ();
170 tw = tjack (jack_get_time ());
171 // Check for errors - requires restart.
172 if (_alsadev->state () && (na == 0))
174 _state = WAIT;
175 send (0, 0);
176 usleep (10000);
177 continue;
180 // Check for commands from the Jack thread.
181 if (_commq->rd_avail ())
183 _state = _commq->rd_int32 ();
184 if (_state == PROC) _first = true;
185 if (_state == TERM) send (0, 0);
188 // We could have more than one period.
189 nu = 0;
190 while (na >= _fsize)
192 // Transfer frames.
193 if (_mode == PLAY) nu += playback ();
194 else nu += capture ();
195 // Update loop condition.
196 na -= _fsize;
197 // Run the DLL if in PROC state.
198 if (_state == PROC)
200 if (_first)
202 // Init DLL in first iteration.
203 _first = false;
204 _dt = (double) _fsize / _alsadev->fsamp ();
205 _t0 = tw;
206 _t1 = tw + _dt;
208 else
210 // Update the DLL.
211 // If we have more than one period, use
212 // the time error only for the last one.
213 if (na >= _fsize) er = 0;
214 else er = tjack_diff (tw, _t1);
215 _t0 = _t1;
216 _t1 = tjack_diff (_t1 + _dt + _w1 * er, 0.0);
217 _dt += _w2 * er;
222 // Send number of frames used and timestamp to Jack thread.
223 if (_state == PROC) send (nu, _t1);
225 _alsadev->pcm_stop ();