** Warning: Cannot open xref database.
1 /*
2 Copyright (C) 2001-2003 Paul Davis
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 $Id: port.c,v 1.13 2003/10/31 20:52:24 joq Exp $
19 */
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <math.h>
24
25 #include <config.h>
26
27 #include <jack/jack.h>
28 #include <jack/types.h>
29 #include <jack/internal.h>
30 #include <jack/engine.h>
31 #include <jack/pool.h>
32 #include <jack/port.h>
33 #include <jack/jslist.h>
34
35 #include "local.h"
36
37 static void jack_audio_port_mixdown (jack_port_t *port,
38 jack_nframes_t nframes);
39
40 /* These function pointers are local to each address space. For
41 * internal clients they reside within jackd; for external clients in
42 * the application process. */
43 jack_port_functions_t jack_builtin_audio_functions = {
44 .mixdown = jack_audio_port_mixdown,
45 };
46
47 jack_port_functions_t jack_builtin_NULL_functions = {
48 .mixdown = NULL,
49 };
50
51 /* Only the Audio port type is currently built in. */
52 jack_port_type_info_t jack_builtin_port_types[] = {
53 { .type_name = JACK_DEFAULT_AUDIO_TYPE,
54 .buffer_scale_factor = 1,
55 },
56 { .type_name = "", }
57 };
58
59 jack_port_t *
60 jack_port_new (const jack_client_t *client, jack_port_id_t port_id,
61 jack_control_t *control)
62 {
63 jack_port_shared_t *shared = &control->ports[port_id];
64 jack_port_type_id_t ptid = shared->ptype_id;
65 jack_port_t *port = (jack_port_t *) malloc (sizeof (jack_port_t));
66
67 port->mix_buffer = NULL;
68 port->client_segment_base = NULL;
69 port->shared = shared;
70 port->type_info = &client->engine->port_types[ptid];
71 pthread_mutex_init (&port->connection_lock, NULL);
72 port->connections = 0;
73 port->tied = NULL;
74
75 if (client->control->id == port->shared->client_id) {
76
77 /* It's our port, so initialize the pointers to port
78 * functions within this address space. These builtin
79 * definitions can be overridden by the client.
80 */
81
82 if (ptid == JACK_AUDIO_PORT_TYPE) {
83
84 port->fptr = jack_builtin_audio_functions;
85 port->shared->has_mixdown = TRUE;
86
87 } else { /* no other builtin functions */
88
89 port->fptr = jack_builtin_NULL_functions;
90 port->shared->has_mixdown = FALSE;
91 }
92 }
93
94 /* set up a base address so that port->offset can be used to
95 compute the correct location. we don't store the location
96 directly, because port->client_segment_base and/or
97 port->offset can change if the buffer size or port counts
98 are changed.
99 */
100
101 port->client_segment_base = (void **) &client->port_segment[ptid].attached_at;
102
103 return port;
104 }
105
106 jack_port_t *
107 jack_port_register (jack_client_t *client,
108 const char *port_name,
109 const char *port_type,
110 unsigned long flags,
111 unsigned long buffer_size)
112 {
113 jack_request_t req;
114 jack_port_t *port = 0;
115 int length ;
116
117 req.type = RegisterPort;
118
119 length = strlen ( (const char *) client->control->name )
120 + 1 + strlen ( port_name ) ;
121 if ( length >= sizeof (req.x.port_info.name) ) {
122 jack_error ("\"%s:%s\" is too long to be used as a JACK port name.\n"
123 "Please use %lu characters or less.",
124 client->control->name ,
125 port_name ,
126 sizeof (req.x.port_info.name) - 1);
127 return NULL ;
128 }
129
130 strcpy ((char *) req.x.port_info.name,
131 (const char *) client->control->name);
132 strcat ((char *) req.x.port_info.name, ":");
133 strcat ((char *) req.x.port_info.name, port_name);
134
135 snprintf (req.x.port_info.type, sizeof (req.x.port_info.type),
136 "%s", port_type);
137 req.x.port_info.flags = flags;
138 req.x.port_info.buffer_size = buffer_size;
139 req.x.port_info.client_id = client->control->id;
140
141 if (jack_client_deliver_request (client, &req)) {
142 return NULL;
143 }
144
145 if ((port = jack_port_new (client, req.x.port_info.port_id,
146 client->engine)) == NULL) {
147 return NULL;
148 }
149
150 client->ports = jack_slist_prepend (client->ports, port);
151
152 return port;
153 }
154
155 int
156 jack_port_unregister (jack_client_t *client, jack_port_t *port)
157 {
158 jack_request_t req;
159
160 req.type = UnRegisterPort;
161 req.x.port_info.port_id = port->shared->id;
162 req.x.port_info.client_id = client->control->id;
163
164 return jack_client_deliver_request (client, &req);
165 }
166
167 int
168 jack_port_lock (jack_client_t *client, jack_port_t *port)
169 {
170 if (port) {
171 port->shared->locked = 1;
172 return 0;
173 }
174 return -1;
175 }
176
177 int
178 jack_port_unlock (jack_client_t *client, jack_port_t *port)
179 {
180 if (port) {
181 port->shared->locked = 0;
182 return 0;
183 }
184 return -1;
185 }
186
187 /* LOCAL (in-client) connection querying only */
188
189 int
190 jack_port_connected (const jack_port_t *port)
191 {
192 return jack_slist_length (port->connections);
193 }
194
195 int
196 jack_port_connected_to (const jack_port_t *port, const char *portname)
197 {
198 JSList *node;
199 int ret = FALSE;
200
201 /* XXX this really requires a cross-process lock
202 so that ports/connections cannot go away
203 while we are checking for them. that's hard,
204 and has a non-trivial performance impact
205 for jackd.
206 */
207
208 pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);
209
210 for (node = port->connections; node; node = jack_slist_next (node)) {
211 jack_port_t *other_port = (jack_port_t *) node->data;
212
213 if (strcmp (other_port->shared->name, portname) == 0) {
214 ret = TRUE;
215 break;
216 }
217 }
218
219 pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
220 return ret;
221 }
222
223 const char **
224 jack_port_get_connections (const jack_port_t *port)
225 {
226 const char **ret = NULL;
227 JSList *node;
228 unsigned int n;
229
230 /* XXX this really requires a cross-process lock
231 so that ports/connections cannot go away
232 while we are checking for them. that's hard,
233 and has a non-trivial performance impact
234 for jackd.
235 */
236
237 pthread_mutex_lock (&((jack_port_t *) port)->connection_lock);
238
239 if (port->connections != NULL) {
240
241 ret = (const char **)
242 malloc (sizeof (char *)
243 * (jack_slist_length (port->connections) + 1));
244 for (n = 0, node = port->connections; node;
245 node = jack_slist_next (node), ++n) {
246 ret[n] = ((jack_port_t *) node->data)->shared->name;
247 }
248 ret[n] = NULL;
249 }
250
251 pthread_mutex_unlock (&((jack_port_t *) port)->connection_lock);
252 return ret;
253 }
254
255 /* SERVER-SIDE (all) connection querying */
256
257 const char **
258 jack_port_get_all_connections (const jack_client_t *client,
259 const jack_port_t *port)
260 {
261 const char **ret;
262 jack_request_t req;
263 unsigned int i;
264
265 if (port == NULL) {
266 return NULL;
267 }
268
269 req.type = GetPortConnections;
270
271 req.x.port_info.name[0] = '\0';
272 req.x.port_info.type[0] = '\0';
273 req.x.port_info.flags = 0;
274 req.x.port_info.buffer_size = 0;
275 req.x.port_info.client_id = 0;
276 req.x.port_info.port_id = port->shared->id;
277
278 jack_client_deliver_request (client, &req);
279
280 if (req.status != 0 || req.x.port_connections.nports == 0) {
281 return NULL;
282 }
283
284 if (client->request_fd < 0) {
285 /* internal client */
286 return req.x.port_connections.ports;
287 }
288
289 ret = (const char **)
290 malloc (sizeof (char *) * (req.x.port_connections.nports + 1));
291
292 for (i = 0; i < req.x.port_connections.nports; ++i ) {
293 jack_port_id_t port_id;
294
295 if (read (client->request_fd, &port_id, sizeof (port_id))
296 != sizeof (port_id)) {
297 jack_error ("cannot read port id from server");
298 return 0;
299 }
300
301 ret[i] = jack_port_by_id (client, port_id)->shared->name;
302 }
303
304 ret[i] = NULL;
305
306 return ret;
307 }
308
309 jack_port_t *
310 jack_port_by_id (const jack_client_t *client, jack_port_id_t id)
311 {
312 JSList *node;
313
314 for (node = client->ports; node; node = jack_slist_next (node)) {
315 if (((jack_port_t *) node->data)->shared->id == id) {
316 return (jack_port_t *) node->data;
317 }
318 }
319
320 if (id >= client->engine->port_max)
321 return NULL;
322
323 if (client->engine->ports[id].in_use)
324 return jack_port_new (client, id, client->engine);
325
326 return NULL;
327 }
328
329 jack_port_t *
330 jack_port_by_name (jack_client_t *client, const char *port_name)
331 {
332 unsigned long i, limit;
333 jack_port_shared_t *port;
334
335 limit = client->engine->port_max;
336 port = &client->engine->ports[0];
337
338 for (i = 0; i < limit; i++) {
339 if (port[i].in_use && strcmp (port[i].name, port_name) == 0) {
340 return jack_port_new (client, port[i].id,
341 client->engine);
342 }
343 }
344
345 return NULL;
346 }
347
348 jack_nframes_t
349 jack_port_get_latency (jack_port_t *port)
350 {
351 return port->shared->latency;
352 }
353
354 jack_nframes_t
355 jack_port_get_total_latency (jack_client_t *client, jack_port_t *port)
356 {
357 return port->shared->total_latency;
358 }
359
360 void
361 jack_port_set_latency (jack_port_t *port, jack_nframes_t nframes)
362 {
363 port->shared->latency = nframes;
364 }
365
366 void *
367 jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
368 {
369 JSList *node, *next;
370
371 /* Output port. The buffer was assigned by the engine
372 when the port was registered.
373 */
374 if (port->shared->flags & JackPortIsOutput) {
375 if (port->tied) {
376 return jack_port_get_buffer (port->tied, nframes);
377 }
378
379 return jack_output_port_buffer (port);
380 }
381
382 /* Input port. Since this can only be called from the
383 process() callback, and since no connections can be
384 made/broken during this phase (enforced by the jack
385 server), there is no need to take the connection lock here
386 */
387 if ((node = port->connections) == NULL) {
388
389 /* no connections; return a zero-filled buffer */
390 return jack_zero_filled_buffer;
391 }
392
393 if ((next = jack_slist_next (node)) == NULL) {
394
395 /* one connection: use zero-copy mode - just pass
396 the buffer of the connected (output) port.
397 */
398 return jack_port_get_buffer (((jack_port_t *) node->data),
399 nframes);
400 }
401
402 /* Multiple connections. Use a local buffer and mix the
403 incoming data into that buffer. We have already
404 established the existence of a mixdown function during the
405 connection process.
406 */
407 if (port->mix_buffer == NULL) {
408 port->mix_buffer =
409 jack_pool_alloc (
410 port->type_info->buffer_scale_factor
411 * sizeof (jack_default_audio_sample_t)
412 * nframes);
413 }
414 port->fptr.mixdown (port, nframes);
415 return (jack_default_audio_sample_t *) port->mix_buffer;
416 }
417
418 int
419 jack_port_tie (jack_port_t *src, jack_port_t *dst)
420
421 {
422 if (dst->shared->client_id != src->shared->client_id) {
423 jack_error ("cannot tie ports not owned by the same client");
424 return -1;
425 }
426
427 if (dst->shared->flags & JackPortIsOutput) {
428 jack_error ("cannot tie an input port");
429 return -1;
430 }
431
432 dst->tied = src;
433 return 0;
434 }
435
436 int
437 jack_port_untie (jack_port_t *port)
438
439 {
440 if (port->tied == NULL) {
441 jack_error ("port \"%s\" is not tied", port->shared->name);
442 return -1;
443 }
444 port->tied = NULL;
445 return 0;
446 }
447
448 int
449 jack_port_request_monitor (jack_port_t *port, int onoff)
450
451 {
452 if (onoff) {
453 port->shared->monitor_requests++;
454 } else if (port->shared->monitor_requests) {
455 port->shared->monitor_requests--;
456 }
457
458 if ((port->shared->flags & JackPortIsOutput) == 0) {
459
460 JSList *node;
461
462 /* this port is for input, so recurse over each of the
463 connected ports.
464 */
465
466 pthread_mutex_lock (&port->connection_lock);
467 for (node = port->connections; node;
468 node = jack_slist_next (node)) {
469
470 /* drop the lock because if there is a feedback loop,
471 we will deadlock. XXX much worse things will
472 happen if there is a feedback loop !!!
473 */
474
475 pthread_mutex_unlock (&port->connection_lock);
476 jack_port_request_monitor ((jack_port_t *) node->data,
477 onoff);
478 pthread_mutex_lock (&port->connection_lock);
479 }
480 pthread_mutex_unlock (&port->connection_lock);
481 }
482
483 return 0;
484 }
485
486 int
487 jack_port_request_monitor_by_name (jack_client_t *client,
488 const char *port_name, int onoff)
489
490 {
491 jack_port_t *port;
492 unsigned long i, limit;
493 jack_port_shared_t *ports;
494
495 limit = client->engine->port_max;
496 ports = &client->engine->ports[0];
497
498 for (i = 0; i < limit; i++) {
499 if (ports[i].in_use &&
500 strcmp (ports[i].name, port_name) == 0) {
501 port = jack_port_new (client, ports[i].id,
502 client->engine);
503 return jack_port_request_monitor (port, onoff);
504 free (port);
505 return 0;
506 }
507 }
508
509 return -1;
510 }
511
512 int
513 jack_ensure_port_monitor_input (jack_port_t *port, int yn)
514 {
515 if (yn) {
516 if (port->shared->monitor_requests == 0) {
517 port->shared->monitor_requests++;
518 }
519 } else {
520 if (port->shared->monitor_requests > 0) {
521 port->shared->monitor_requests = 0;
522 }
523 }
524
525 return 0;
526 }
527
528 int
529 jack_port_monitoring_input (jack_port_t *port)
530 {
531 return port->shared->monitor_requests > 0;
532 }
533
534 const char *
535 jack_port_name (const jack_port_t *port)
536 {
537 return port->shared->name;
538 }
539
540 const char *
541 jack_port_short_name (const jack_port_t *port)
542 {
543 /* we know there is always a colon, because we put
544 it there ...
545 */
546
547 return strchr (port->shared->name, ':') + 1;
548 }
549
550 int
551 jack_port_is_mine (const jack_client_t *client, const jack_port_t *port)
552 {
553 return port->shared->client_id == client->control->id;
554 }
555
556 int
557 jack_port_flags (const jack_port_t *port)
558 {
559 return port->shared->flags;
560 }
561
562 const char *
563 jack_port_type (const jack_port_t *port)
564 {
565 return port->type_info->type_name;
566 }
567
568 int
569 jack_port_set_name (jack_port_t *port, const char *new_name)
570 {
571 char *colon;
572 int len;
573
574 colon = strchr (port->shared->name, ':');
575 len = sizeof (port->shared->name) -
576 ((int) (colon - port->shared->name)) - 2;
577 snprintf (colon+1, len, "%s", new_name);
578
579 return 0;
580 }
581
582 /* AUDIO PORT SUPPORT */
583
584 static inline float f_max(float x, float a)
585 {
586 x -= a;
587 x += fabs (x);
588 x *= 0.5;
589 x += a;
590
591 return (x);
592 }
593
594 static void
595 jack_audio_port_mixdown (jack_port_t *port, jack_nframes_t nframes)
596 {
597 JSList *node;
598 jack_port_t *input;
599 jack_nframes_t n;
600 jack_default_audio_sample_t *buffer;
601 jack_default_audio_sample_t *dst, *src;
602
603 /* by the time we've called this, we've already established
604 the existence of more than one connection to this input
605 port and allocated a mix_buffer.
606 */
607
608 /* no need to take connection lock, since this is called
609 from the process() callback, and the jack server
610 ensures that no changes to connections happen
611 during this time.
612 */
613
614 node = port->connections;
615 input = (jack_port_t *) node->data;
616 buffer = port->mix_buffer;
617
618 memcpy (buffer, jack_output_port_buffer (input),
619 sizeof (jack_default_audio_sample_t) * nframes);
620
621 for (node = jack_slist_next (node); node;
622 node = jack_slist_next (node)) {
623
624 input = (jack_port_t *) node->data;
625
626 n = nframes;
627 dst = buffer;
628 src = jack_output_port_buffer (input);
629
630 while (n--) {
631 *dst++ += *src++;
632 }
633 }
634 }
635
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.