fix debug message when acquiring the "problem" lock
[jack.git] / libjack / transclient.c
blob267e98b2fdd8975f5891698be67cf7420b841195
1 /*
2 JACK transport client interface -- runs in the client process.
4 Copyright (C) 2001-2003 Paul Davis
5 Copyright (C) 2003 Jack O'Quin
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
23 #include <config.h>
24 #include <errno.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <jack/atomicity.h>
28 #include <jack/internal.h>
29 #include "local.h"
32 /********************* Internal functions *********************/
34 /* generate a unique non-zero ID, different for each call */
35 jack_unique_t
36 jack_generate_unique_id (jack_control_t *ectl)
38 /* The jack_unique_t is an opaque type. */
39 return exchange_and_add(&ectl->seq_number, 1);
42 static inline void
43 jack_read_frame_time (const jack_client_t *client, jack_frame_timer_t *copy)
45 int tries = 0;
46 long timeout = 1000;
48 do {
49 /* throttle the busy wait if we don't get
50 the answer very quickly.
52 XXX This is disgusting. on a UP
53 system, it needs to sleep
54 if the first try didn't work. on an SMP
55 system, it should wait for half of
56 the context switch time before
57 sleeping.
60 if (tries > 10) {
61 usleep (20);
62 tries = 0;
64 /* debug code to avoid system hangs... */
65 if (--timeout == 0) {
66 jack_error ("hung in loop copying position A");
67 abort();
71 *copy = client->engine->frame_timer;
73 tries++;
75 } while (copy->guard1 != copy->guard2);
78 /* copy a JACK transport position structure (thread-safe) */
79 void
80 jack_transport_copy_position (jack_position_t *from, jack_position_t *to)
82 int tries = 0;
83 long timeout = 1000;
85 do {
86 /* throttle the busy wait if we don't get the answer
87 * very quickly. See comment above about this
88 * design.
90 if (tries > 10) {
91 usleep (20);
92 tries = 0;
94 /* debug code to avoid system hangs... */
95 if (--timeout == 0) {
96 jack_error ("hung in loop copying position B");
97 abort();
100 *to = *from;
101 tries++;
103 } while (to->unique_1 != to->unique_2);
106 static inline int
107 jack_transport_request_new_pos (jack_client_t *client, jack_position_t *pos)
109 jack_control_t *ectl = client->engine;
111 /* distinguish this request from all others */
112 pos->unique_1 = pos->unique_2 = jack_generate_unique_id(ectl);
114 /* clients may not set these fields */
115 pos->usecs = ectl->current_time.usecs;
116 pos->frame_rate = ectl->current_time.frame_rate;
118 /* carefully copy requested postion into shared memory */
119 jack_transport_copy_position (pos, &ectl->request_time);
121 return 0;
125 /******************** Callback invocations ********************/
127 void
128 jack_call_sync_client (jack_client_t *client)
130 jack_client_control_t *control = client->control;
131 jack_control_t *ectl = client->engine;
133 /* Make sure still active and slow-sync; active_slowsync is
134 * set in a critical section; sync_cb is not. */
135 if ((ectl->new_pos || control->sync_poll || control->sync_new) &&
136 control->active_slowsync) {
138 if (client->sync_cb (ectl->transport_state,
139 &ectl->current_time,
140 client->sync_arg)) {
142 if (control->sync_poll) {
143 control->sync_poll = 0;
144 ectl->sync_remain--;
147 control->sync_new = 0;
151 void
152 jack_call_timebase_master (jack_client_t *client)
154 jack_client_control_t *control = client->control;
155 jack_control_t *ectl = client->engine;
156 int new_pos = (int) ectl->pending_pos;
159 /* Make sure this is still the master; is_timebase is set in a
160 * critical section; timebase_cb is not. */
161 if (control->is_timebase) {
163 if (control->timebase_new) { /* first callback? */
164 control->timebase_new = 0;
165 new_pos = 1;
169 if ((ectl->transport_state == JackTransportRolling) ||
170 new_pos) {
172 client->timebase_cb (ectl->transport_state,
173 control->nframes,
174 &ectl->pending_time,
175 new_pos,
176 client->timebase_arg);
179 } else {
181 /* another master took over, so resign */
182 client->timebase_cb = NULL;
183 client->timebase_arg = NULL;
184 control->timebase_cb_cbset = FALSE;
189 /************************* API functions *************************/
191 jack_nframes_t
192 jack_get_current_transport_frame (const jack_client_t *client)
194 jack_position_t position;
195 float usecs;
196 jack_nframes_t elapsed;
197 jack_transport_state_t tstate;
199 /* get the current transport position information.
200 this is thread-safe and atomic with respect
201 to the structure contents.
204 tstate = jack_transport_query (client, &position);
206 if (tstate != JackTransportRolling) {
207 return position.frame;
210 /* compute the elapsed usecs then audio frames since
211 the transport info was last updated
214 usecs = jack_get_microseconds() - position.usecs;
215 elapsed = (jack_nframes_t) floor ((((float) position.frame_rate)
216 / 1000000.0f) * usecs);
218 /* return the estimated transport frame position
221 return position.frame + elapsed;
224 jack_nframes_t
225 jack_frames_since_cycle_start (const jack_client_t *client)
227 float usecs;
228 jack_control_t *ectl = client->engine;
230 usecs = jack_get_microseconds() - ectl->current_time.usecs;
231 return (jack_nframes_t) floor ((((float) ectl->current_time.frame_rate)
232 / 1000000.0f) * usecs);
235 jack_time_t
236 jack_get_time()
238 return jack_get_microseconds();
241 jack_nframes_t
242 jack_time_to_frames(const jack_client_t *client, jack_time_t now)
244 jack_frame_timer_t time;
245 jack_control_t *ectl = client->engine;
247 jack_read_frame_time (client, &time);
249 if (time.initialized) {
250 #if 0
251 jack_info ("now = %Lu current wakeup = %Lu next = %Lu frames = %lu + %f => %lu",
252 now, time.current_wakeup, time.next_wakeup, time.frames,
253 (double) (now - time.current_wakeup)/
254 (time.next_wakeup - time.current_wakeup),
255 time.frames +
256 (long) rint (((double) (now - time.current_wakeup)/
257 (time.next_wakeup - time.current_wakeup)) * ectl->buffer_size));
258 #endif
260 return time.frames +
261 (long) rint (((double) ((long long) (now - time.current_wakeup))/
262 ((long long) (time.next_wakeup - time.current_wakeup))) * ectl->buffer_size);
264 return 0;
267 jack_nframes_t
268 jack_frame_time (const jack_client_t *client)
270 jack_time_t now = jack_get_microseconds();
271 return jack_time_to_frames(client, now);
274 jack_nframes_t
275 jack_last_frame_time (const jack_client_t *client)
277 jack_frame_timer_t current;
278 jack_read_frame_time (client, &current);
279 return current.frames;
282 jack_time_t
283 jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames)
285 jack_frame_timer_t time;
286 jack_control_t *ectl = client->engine;
288 jack_read_frame_time (client, &time);
290 if (time.initialized) {
291 return time.current_wakeup +
292 (long) rint (((double) ((long long) (frames - time.frames)) *
293 ((long long) (time.next_wakeup - time.current_wakeup)) / ectl->buffer_size) );
296 return 0;
299 jack_nframes_t
300 jack_get_sample_rate (jack_client_t *client)
302 return client->engine->current_time.frame_rate;
306 jack_set_sample_rate_callback (jack_client_t *client,
307 JackSampleRateCallback callback, void *arg)
309 if (client->control->active) {
310 jack_error ("You cannot set callbacks on an active client.");
311 return -1;
313 client->srate_arg = arg;
314 client->srate = callback;
315 client->control->srate_cbset = (callback != NULL);
317 /* Now invoke it */
319 callback (client->engine->current_time.frame_rate, arg);
321 return 0;
324 int
325 jack_release_timebase (jack_client_t *client)
327 int rc;
328 jack_request_t req;
329 jack_client_control_t *ctl = client->control;
331 req.type = ResetTimeBaseClient;
332 req.x.client_id = ctl->id;
334 rc = jack_client_deliver_request (client, &req);
335 if (rc == 0) {
336 client->timebase_cb = NULL;
337 client->timebase_arg = NULL;
338 ctl->timebase_cb_cbset = 0;
341 return rc;
344 int
345 jack_set_sync_callback (jack_client_t *client,
346 JackSyncCallback sync_callback, void *arg)
348 jack_client_control_t *ctl = client->control;
349 jack_request_t req;
350 int rc;
352 if (sync_callback)
353 req.type = SetSyncClient;
354 else
355 req.type = ResetSyncClient;
356 req.x.client_id = ctl->id;
358 rc = jack_client_deliver_request (client, &req);
359 if (rc == 0) {
360 client->sync_cb = sync_callback;
361 client->sync_arg = arg;
362 ctl->sync_cb_cbset = TRUE;
364 return rc;
367 int
368 jack_set_sync_timeout (jack_client_t *client, jack_time_t usecs)
370 jack_request_t req;
372 req.type = SetSyncTimeout;
373 req.x.timeout = usecs;
375 return jack_client_deliver_request (client, &req);
378 int
379 jack_set_timebase_callback (jack_client_t *client, int conditional,
380 JackTimebaseCallback timebase_cb, void *arg)
382 int rc;
383 jack_request_t req;
384 jack_client_control_t *ctl = client->control;
386 req.type = SetTimeBaseClient;
387 req.x.timebase.client_id = ctl->id;
388 req.x.timebase.conditional = conditional;
390 rc = jack_client_deliver_request (client, &req);
391 if (rc == 0) {
392 client->timebase_arg = arg;
393 client->timebase_cb = timebase_cb;
394 ctl->timebase_cb_cbset = TRUE;
396 return rc;
400 jack_transport_locate (jack_client_t *client, jack_nframes_t frame)
402 jack_position_t pos;
404 pos.frame = frame;
405 pos.valid = 0;
406 return jack_transport_request_new_pos (client, &pos);
409 jack_transport_state_t
410 jack_transport_query (const jack_client_t *client, jack_position_t *pos)
412 jack_control_t *ectl = client->engine;
414 if (pos) {
415 /* the guarded copy makes this function work in any
416 * thread
418 jack_transport_copy_position (&ectl->current_time, pos);
421 return ectl->transport_state;
425 jack_transport_reposition (jack_client_t *client, jack_position_t *pos)
427 /* copy the input, to avoid modifying its contents */
428 jack_position_t tmp = *pos;
430 /* validate input */
431 if (tmp.valid & ~JACK_POSITION_MASK) /* unknown field present? */
432 return EINVAL;
434 return jack_transport_request_new_pos (client, &tmp);
437 void
438 jack_transport_start (jack_client_t *client)
440 client->engine->transport_cmd = TransportCommandStart;
443 void
444 jack_transport_stop (jack_client_t *client)
446 client->engine->transport_cmd = TransportCommandStop;
450 #ifdef OLD_TRANSPORT
452 /************* Compatibility with old transport API. *************/
455 jack_engine_takeover_timebase (jack_client_t *client)
457 jack_error ("jack_engine_takeover_timebase() is no longer supported.");
458 return ENOSYS;
461 void
462 jack_get_transport_info (jack_client_t *client,
463 jack_transport_info_t *info)
465 jack_control_t *ectl = client->engine;
466 static int first_time = 1;
468 if (first_time)
469 jack_error ("jack_get_transport_info() is deprecated.");
470 first_time = 0;
472 /* check that this is the process thread */
473 if (!pthread_equal(client->thread_id, pthread_self())) {
474 jack_error("Invalid thread for jack_get_transport_info().");
475 abort(); /* kill this client */
478 info->usecs = ectl->current_time.usecs;
479 info->frame_rate = ectl->current_time.frame_rate;
480 info->transport_state = ectl->transport_state;
481 info->frame = ectl->current_time.frame;
482 info->valid = (ectl->current_time.valid |
483 JackTransportState | JackTransportPosition);
485 if (info->valid & JackTransportBBT) {
486 info->bar = ectl->current_time.bar;
487 info->beat = ectl->current_time.beat;
488 info->tick = ectl->current_time.tick;
489 info->bar_start_tick = ectl->current_time.bar_start_tick;
490 info->beats_per_bar = ectl->current_time.beats_per_bar;
491 info->beat_type = ectl->current_time.beat_type;
492 info->ticks_per_beat = ectl->current_time.ticks_per_beat;
493 info->beats_per_minute = ectl->current_time.beats_per_minute;
497 void
498 jack_set_transport_info (jack_client_t *client,
499 jack_transport_info_t *info)
501 static int first_time = 1;
503 if (first_time)
504 jack_error ("jack_set_transport_info() no longer supported.");
505 first_time = 0;
508 #endif /* OLD_TRANSPORT */