1 package net.sf.jack4j;
2
3 /*
4 Copyright (C) 2008 Ondrej Par
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 import java.lang.ref.WeakReference;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.EnumSet;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30
31 /**
32 * Client of Jack daemon.
33 *
34 * <p>
35 * The Java callback methods defined in this class (such as
36 * {@link #process(int)}, {@link #xRunCallback()} etc.) <b>will only work if
37 * both default native JackThreadInit callback and the default native callback
38 * for the event are set</b>. For example, the <code>process(int)</code>
39 * method is called only if you call {@link #setDefaultThreadInitCallback()} and
40 * {@link #setDefaultProcessCallback()} before activating the client.
41 *
42 * <p>
43 * See {@link #setAllDefaultCallbacks()} if you want to set all native callbacks
44 * at once.
45 *
46 * <p>
47 * Most methods correspond to functions defined in Jack library, except for
48 * {@link #localPort(String)} and friends, that work with the internal Java
49 * structure.
50 *
51 * @author repa
52 *
53 */
54 public abstract class JackClient {
55
56 static {
57 JackBridge.initializeJackBridge();
58 }
59
60 private volatile boolean isOpen;
61 private volatile long clientHandle = 0;
62 private volatile long callbackStruct = 0;
63 private volatile boolean isActive;
64 private ConcurrentMap<String, JackLocalPort> localPorts;
65 private ConcurrentMap<Long, WeakReference<JackPort>> ports;
66 private ConcurrentMap<Long, WeakReference<JackInternalClient>> internalClients;
67 private JackClientThread clientThread;
68 private final Statistics statistics;
69
70 /**
71 * Creates new, inactive Jack client.
72 *
73 * @param clientName
74 * desired client name
75 * @param useExactName
76 * if true, server won't modify the client name and exception is
77 * thrown if client with that name already exists
78 * @param canStartServer
79 * if true, the server will be started unless it's already
80 * running
81 * @param serverName
82 * if not null, connects to specified server; otherwise, connects
83 * to default server
84 * @throws JackException
85 * if communication with the server fails
86 */
87 public JackClient(String clientName, boolean useExactName, boolean canStartServer, String serverName)
88 throws JackException {
89 open(clientName, useExactName, canStartServer, serverName);
90
91 isOpen = true;
92
93 isActive = false;
94
95 localPorts = new ConcurrentHashMap<String, JackLocalPort>();
96 ports = new ConcurrentHashMap<Long, WeakReference<JackPort>>();
97
98 internalClients = new ConcurrentHashMap<Long, WeakReference<JackInternalClient>>();
99
100 clientThread = null;
101
102 statistics = new Statistics(this);
103 }
104
105 /**
106 * @see java.lang.Object#finalize()
107 */
108 @Override
109 protected void finalize() throws Throwable {
110 if (isOpen) {
111 close();
112 }
113 super.finalize();
114 }
115
116 private native void open(String clientName, boolean useExactName, boolean canStartServer, String serverName)
117 throws JackException;
118
119 /**
120 * Returns a value indicating whether the native process callback will
121 * obtain a lock on JackClient structure before calling
122 * {@link #process(int)} method.
123 */
124 public native boolean isProcessMethodSynchronized();
125
126 /**
127 * Sets a flag indicating whether the native process callback will obtain a
128 * lock on JackClient structure before calling {@link #process(int)} method.
129 *
130 * <p>
131 * If the flag is set, the <code>process</code> method behaves as a
132 * synchronized method.
133 */
134 public native boolean setProcessMethodSynchronized(boolean synchronize);
135
136 /**
137 * Returns the pointer to C <code>jack_client_t</code> structure,
138 * represented as <code>long</code>.
139 */
140 public long getClientHandle() {
141 return clientHandle;
142 }
143
144 /**
145 * Returns the pointer to C structure that can be used by native Jack
146 * callbacks.
147 *
148 * <p>
149 * The pointer is represented as <code>long</code> value.
150 */
151 public long getCallbackStruct() {
152 return callbackStruct;
153 }
154
155 /**
156 * Sets the default "on shutdown" callback for this client.
157 */
158 public native void setDefaultShutdownCallback() throws JackException;
159
160 /**
161 * Sets custom "on shutdown" callback for this client.
162 *
163 * <p>
164 * The <code>pointer</code> must be a native
165 * <code>void(*)(void *arg)</code> pointer, represented as
166 * <code>long</code>.
167 *
168 * @param pointer
169 * the pointer to native function
170 * @param arg
171 * the value passed as <code>void* arg</code> parameter to the
172 * callback
173 * @see #setDefaultShutdownCallback()
174 */
175 public native void setShutdownCallback(long pointer, long arg) throws JackException;
176
177 /**
178 * Sets the default native JackProcessCallback for this client.
179 */
180 public native void setDefaultProcessCallback() throws JackException;
181
182 /**
183 * Sets custom JackProcessCallback for this client.
184 *
185 * <p>
186 * The <code>pointer</code> must be a native
187 * <code>JackProcessCallback</code> pointer, represented as
188 * <code>long</code>.
189 *
190 * @param pointer
191 * the pointer to native function
192 * @param arg
193 * the value passed as <code>void* arg</code> parameter to the
194 * callback
195 * @see #setDefaultProcessCallback()
196 */
197 public native void setProcessCallback(long pointer, long arg) throws JackException;
198
199 /**
200 * Sets the default native JackThreadInitCallback for this client.
201 *
202 * <p>
203 * This callback must be set, otherwise the other callbacks will not work
204 * correctly!
205 */
206 public native void setDefaultThreadInitCallback() throws JackException;
207
208 /**
209 * Sets custom JackThreadInitCallback for this client.
210 *
211 * <p>
212 * The <code>pointer</code> must be a native
213 * <code>JackThreadInitCallback</code> pointer, represented as
214 * <code>long</code>.
215 *
216 * @param pointer
217 * the pointer to native function
218 * @param arg
219 * the value passed as <code>void* arg</code> parameter to the
220 * callback
221 * @see #setDefaultThreadInitCallback()
222 */
223 public native void setThreadInitCallback(long pointer, long arg) throws JackException;
224
225 /**
226 * Sets the default native JackFreewheelCallback for this client.
227 */
228 public native void setDefaultFreewheelCallback() throws JackException;
229
230 /**
231 * Sets custom JackFreewheelCallback for this client.
232 *
233 * <p>
234 * The <code>pointer</code> must be a native
235 * <code>JackFreewheelCallback</code> pointer, represented as
236 * <code>long</code>.
237 *
238 * @param pointer
239 * the pointer to native function
240 * @param arg
241 * the value passed as <code>void* arg</code> parameter to the
242 * callback
243 * @see #setDefaultFreewheelCallback()
244 */
245 public native void setFreewheelCallback(long pointer, long arg) throws JackException;
246
247 /**
248 * Sets the default native JackBufferSizeCallback for this client.
249 */
250 public native void setDefaultBufferSizeCallback() throws JackException;
251
252 /**
253 * Sets custom JackBufferSizeCallback for this client.
254 *
255 * <p>
256 * The <code>pointer</code> must be a native
257 * <code>JackBufferSizeCallback</code> pointer, represented as
258 * <code>long</code>.
259 *
260 * @param pointer
261 * the pointer to native function
262 * @param arg
263 * the value passed as <code>void* arg</code> parameter to the
264 * callback
265 * @see #setDefaultBufferSizeCallback()
266 */
267 public native void setBufferSizeCallback(long pointer, long arg) throws JackException;
268
269 /**
270 * Sets the default native JackSampleRateCallback for this client.
271 */
272 public native void setDefaultSampleRateCallback() throws JackException;
273
274 /**
275 * Sets custom JackSampleRateCallback for this client.
276 *
277 * <p>
278 * The <code>pointer</code> must be a native
279 * <code>JackSampleRateCallback</code> pointer, represented as
280 * <code>long</code>.
281 *
282 * @param pointer
283 * the pointer to native function
284 * @param arg
285 * the value passed as <code>void* arg</code> parameter to the
286 * callback
287 * @see #setDefaultSampleRateCallback()
288 */
289 public native void setSampleRateCallback(long pointer, long arg) throws JackException;
290
291 /**
292 * Sets the default native JackClientRegistrationCallback for this client.
293 */
294 public native void setDefaultClientRegistrationCallback() throws JackException;
295
296 /**
297 * Sets custom JackClientRegistrationCallback for this client.
298 *
299 * <p>
300 * The <code>pointer</code> must be a native
301 * <code>JackClientRegistrationCallback</code> pointer, represented as
302 * <code>long</code>.
303 *
304 * @param pointer
305 * the pointer to native function
306 * @param arg
307 * the value passed as <code>void* arg</code> parameter to the
308 * callback
309 * @see #setDefaultClientRegistrationCallback()
310 */
311 public native void setClientRegistrationCallback(long pointer, long arg) throws JackException;
312
313 /**
314 * Sets the default native JackPortRegistrationCallback for this client.
315 */
316 public native void setDefaultPortRegistrationCallback() throws JackException;
317
318 /**
319 * Sets custom JackPortRegistrationCallback for this client.
320 *
321 * <p>
322 * The <code>pointer</code> must be a native
323 * <code>JackPortRegistrationCallback</code> pointer, represented as
324 * <code>long</code>.
325 *
326 * @param pointer
327 * the pointer to native function
328 * @param arg
329 * the value passed as <code>void* arg</code> parameter to the
330 * callback
331 * @see #setDefaultPortRegistrationCallback()
332 */
333 public native void setPortRegistrationCallback(long pointer, long arg) throws JackException;
334
335 /**
336 * Sets the default native JackPortConnectCallback for this client.
337 */
338 public native void setDefaultPortConnectCallback() throws JackException;
339
340 /**
341 * Sets custom JackPortConnectCallback for this client.
342 *
343 * <p>
344 * The <code>pointer</code> must be a native
345 * <code>JackPortConnectCallback</code> pointer, represented as
346 * <code>long</code>.
347 *
348 * @param pointer
349 * the pointer to native function
350 * @param arg
351 * the value passed as <code>void* arg</code> parameter to the
352 * callback
353 * @see #setDefaultPortConnectCallback()
354 */
355 public native void setPortConnectCallback(long pointer, long arg) throws JackException;
356
357 /**
358 * Sets the default native JackGraphOrderCallback for this client.
359 */
360 public native void setDefaultGraphOrderCallback() throws JackException;
361
362 /**
363 * Sets custom JackGraphOrderCallback for this client.
364 *
365 * <p>
366 * The <code>pointer</code> must be a native
367 * <code>JackGraphOrderCallback</code> pointer, represented as
368 * <code>long</code>.
369 *
370 * @param pointer
371 * the pointer to native function
372 * @param arg
373 * the value passed as <code>void* arg</code> parameter to the
374 * callback
375 * @see #setDefaultGraphOrderCallback()
376 */
377 public native void setGraphOrderCallback(long pointer, long arg) throws JackException;
378
379 /**
380 * Sets the default native JackXRunCallback for this client.
381 */
382 public native void setDefaultXRunCallback() throws JackException;
383
384 /**
385 * Sets custom JackXRunCallback for this client.
386 *
387 * <p>
388 * The <code>pointer</code> must be a native <code>JackXRunCallback</code>
389 * pointer, represented as <code>long</code>.
390 *
391 * @param pointer
392 * the pointer to native function
393 * @param arg
394 * the value passed as <code>void* arg</code> parameter to the
395 * callback
396 * @see #setDefaultXRunCallback()
397 */
398 public native void setXRunCallback(long pointer, long arg) throws JackException;
399
400 /**
401 * Sets all available default native callbacks.
402 *
403 * <p>
404 * The Java callback methods (such as {@link #process(int)}) will only work
405 * if the default native callback is set for thread initialization and for
406 * the corresponding event. It's recommended to call this method to set all
407 * those native callbacks at once.
408 *
409 * <p>
410 * This method currently doesn't set the JackPortConnectCallback, because
411 * using that callback causes buggy behavior of Jackd 0.109.2.
412 */
413 public void setAllDefaultCallbacks() throws JackException {
414 setDefaultThreadInitCallback();
415
416 setDefaultBufferSizeCallback();
417 setDefaultClientRegistrationCallback();
418 setDefaultFreewheelCallback();
419 setDefaultGraphOrderCallback();
420 // setDefaultPortConnectCallback(); // FIXME: commented out due to bug in Jackd 0.109.2
421 setDefaultPortRegistrationCallback();
422 setDefaultProcessCallback();
423 setDefaultSampleRateCallback();
424 setDefaultShutdownCallback();
425 setDefaultXRunCallback();
426 }
427
428 /**
429 * Returns true if the client is still open.
430 */
431 public boolean isOpen() {
432 return isOpen;
433 }
434
435 /**
436 * Returns real client name (which may be different than the one specified
437 * in constructor).
438 */
439 public native String getClientName() throws JackException;
440
441 /**
442 * Closes the client.
443 *
444 * <p>
445 * The client is completely unusable after this call.
446 */
447 public native void close() throws JackException;
448
449 /**
450 * Returns true if the server runs in real-time mode.
451 */
452 public native boolean isRealtime() throws JackException;
453
454 /**
455 * Returns true if the client was activated
456 */
457 public boolean isActive() {
458 return isActive;
459 }
460
461 /**
462 * Activates the client.
463 */
464 public native void activate() throws JackException;
465
466 /**
467 * Deactivates the client.
468 */
469 public native void deactivate() throws JackException;
470
471 /**
472 * Returns true if the Jack client thread was shut down.
473 *
474 * <p>
475 * This method only works if the correct "on shutdown" callback was set,
476 * preferably using {@link #setDefaultShutdownCallback()}.
477 */
478 public native boolean isShutdown();
479
480 /**
481 * Calls <code>jack_thread_wait</code>.
482 */
483 public native int threadWait(int status) throws JackException;
484
485 /**
486 * Starts or stops Jack "freewheel" mode.
487 */
488 public native void setFreewheel(boolean onoff) throws JackException;
489
490 /**
491 * Sets buffer size used by Jack server.
492 *
493 * <p>
494 * This can cause audio gap.
495 *
496 * @throws IllegalArgumentException
497 * if the bufferSize is not a power of two
498 * @throws JackException
499 * if jack_set_buffer_size fails
500 */
501 public native void setBufferSize(int bufferSize) throws JackException;
502
503 /**
504 * Returns buffer size.
505 *
506 * <p>
507 * Should only be used <b>before</b> {@link #activate()}. If you want to
508 * monitor buffer size changes, see {@link #bufferSizeCallback(int)}.
509 */
510 public native int getBufferSize() throws JackException;
511
512 /**
513 * Returns current sample rate.
514 */
515 public native int getSampleRate() throws JackException;
516
517 private native long registerPort(String portName, int flags, String portType, int bufferSize) throws JackException;
518
519 /**
520 * Registers new port.
521 *
522 * <p>
523 * Tip: you can to use {@link EnumSet} as <code>flags</code> parameter.
524 *
525 * @param portName
526 * short name of the new port
527 * @param flags
528 * set of port flags
529 * @param portType
530 * port type, currently only built-ins
531 * {@link JackConstants#JACK_DEFAULT_AUDIO_TYPE()} and
532 * {@link JackConstants#JACK_DEFAULT_MIDI_TYPE()} are allowed
533 * @param bufferSize
534 * must be non-zero for non-standard portType, otherwise is
535 * ignored
536 * @throws JackException
537 * if port registration fails
538 */
539 public JackLocalPort addPort(String portName, Collection<JackPortFlag> flags, String portType, int bufferSize)
540 throws JackException {
541 EnumSet<JackPortFlag> flagSet = EnumSet.copyOf(flags);
542
543 long portHandle = registerPort(portName, JackPortFlag.encode(flagSet), portType, bufferSize);
544
545 JackLocalPort port;
546 if (JackConstants.JACK_DEFAULT_MIDI_TYPE().equals(portType)) {
547 port = new JackLocalMidiPort(portHandle, this);
548 } else {
549 port = new JackLocalPort(portHandle, this);
550 }
551
552 localPorts.put(portName, port);
553
554 return port;
555 }
556
557 /**
558 * Registers new port of standard audio type.
559 *
560 * <p>
561 * Calls {@link #addPort(String, Collection, String, int)} with portType set
562 * to {@link JackConstants#JACK_DEFAULT_AUDIO_TYPE()} and bufferSize set to
563 * 0.
564 */
565 public JackLocalPort addAudioPort(String portName, Collection<JackPortFlag> flags) throws JackException {
566 return addPort(portName, flags, JackConstants.JACK_DEFAULT_AUDIO_TYPE(), 0);
567 }
568
569 /**
570 * Registers new port of standard MIDI type.
571 *
572 * <p>
573 * Calls {@link #addPort(String, Collection, String, int)} with portType set
574 * to {@link JackConstants#JACK_DEFAULT_MIDI_TYPE()} and bufferSize set to
575 * 0.
576 */
577 public JackLocalMidiPort addMidiPort(String portName, Collection<JackPortFlag> flags) throws JackException {
578 return (JackLocalMidiPort) addPort(portName, flags, JackConstants.JACK_DEFAULT_MIDI_TYPE(), 0);
579 }
580
581 /**
582 * Returns unmodifiable set of (short) names of ports registered by this
583 * client.
584 *
585 * <p>
586 * The returned set will reflect changes (adding/removing ports), but cannot
587 * be modified with Set methods.
588 */
589 public Set<String> localPortNames() {
590 return Collections.unmodifiableSet(localPorts.keySet());
591 }
592
593 /**
594 * Returns port registered under given (short) name, or null if such port
595 * doesn't exist.
596 *
597 * <p>
598 * Note that this method ignores aliases given to the ports.
599 */
600 public JackLocalPort localPort(String name) {
601 return localPorts.get(name);
602 }
603
604 private native void unregisterPort(JackLocalPort port) throws JackException;
605
606 /**
607 * Unregisters given port.
608 *
609 * <p>
610 * The corresponding {@link JackPort} instance will be unusable after this
611 * call.
612 *
613 * @throws IllegalArgumentException
614 * if port with given name doesn't exist
615 * @throws JackException
616 * if the port couldn't be unregistered
617 */
618 public void removePort(String portName) throws JackException {
619 JackLocalPort port = localPorts.get(portName);
620 if (port == null) {
621 throw new IllegalArgumentException("JackPort doesn't exist: " + portName); //$NON-NLS-1$
622 }
623
624 unregisterPort(port);
625
626 localPorts.remove(portName);
627 }
628
629 private JackPort portForHandle(long portHandle) {
630 if (portHandle == 0) {
631 return null;
632 }
633
634 WeakReference<JackPort> portReference = ports.get(portHandle);
635 JackPort port = (portReference == null) ? null : portReference.get();
636
637 if (port == null) {
638 JackPort newPort = new JackPort(portHandle);
639 WeakReference<JackPort> newPortReference = new WeakReference<JackPort>(newPort);
640
641 do {
642 WeakReference<JackPort> oldPortReference = ports.putIfAbsent(portHandle, newPortReference);
643
644 if (oldPortReference == null) {
645 port = newPort;
646 } else {
647 port = oldPortReference.get();
648 }
649 } while (port == null);
650 }
651
652 return port;
653 }
654
655 /**
656 * Returns (local or foreign) port with given name, or null if it doesn't
657 * exist.
658 *
659 * <p>
660 * Note that the returned instance <b>is not</b> of type
661 * {@link JackLocalPort}, even if the port belongs to this client. See
662 * {@link #localPort(String)} method if you want to get JackLocalPort
663 * instance.
664 *
665 * @param name
666 * in the form 'client_name:form_name'
667 */
668 public JackPort portByName(String name) throws JackException {
669 return portForHandle(portByNameInternal(name));
670 }
671
672 private native long portByNameInternal(String name) throws JackException;
673
674 /**
675 * Returns (local or foreign) port with given ID, or null if it doesn't
676 * exist.
677 *
678 * <p>
679 * It seems that the only place where this method is currently usable are
680 * some of the callbacks, namely
681 * {@link #portRegistrationCallback(long, boolean)} and
682 * {@link #portConnectCallback(long, long, boolean)}.
683 *
684 * <p>
685 * Note that the returned instance <b>is not</b> of type
686 * {@link JackLocalPort}, even if the port belongs to this client. See
687 * {@link #localPort(String)} method if you want to get JackLocalPort
688 * instance.
689 *
690 * @param id
691 * unique ID of the port
692 */
693 public JackPort portById(long id) throws JackException {
694 return portForHandle(portByIdInternal(id));
695 }
696
697 private native long portByIdInternal(long id) throws JackException;
698
699 /**
700 * Returns names of ports that fulfill given criteria.
701 *
702 * @param portNamePattern
703 * regex used to select ports by name; this parameter is ignored
704 * if it's null or empty string
705 * @param typeNamePattern
706 * regex used to select ports by type; this parameter is ignored
707 * if it's null or empty string
708 * @param flagSet
709 * required port flags; this parameter is ignored if it's null
710 * @return array of port names
711 */
712 public String[] getPorts(String portNamePattern, String typeNamePattern, EnumSet<JackPortFlag> flagSet) {
713 long flags;
714 if (flagSet == null) {
715 flags = 0;
716 } else {
717 flags = JackPortFlag.encode(flagSet);
718 }
719
720 return getPorts(portNamePattern, typeNamePattern, flags);
721 }
722
723 /**
724 * Returns names of ports that fulfill given criteria.
725 *
726 * @param portNamePattern
727 * regex used to select ports by name; this parameter is ignored
728 * if it's null or empty string
729 * @param typeNamePattern
730 * regex used to select ports by type; this parameter is ignored
731 * if it's null or empty string
732 * @param flags
733 * required port flags; this parameter is ignored if it's zero
734 * @return array of port names
735 */
736 public native String[] getPorts(String portNamePattern, String typeNamePattern, long flags);
737
738 /**
739 * Establish a connection between two ports.
740 *
741 * <p>
742 * The port types must be identical, the source port must be an output port,
743 * and the destination port must be an input port.
744 *
745 * <p>
746 * The ports need not to belong to this client.
747 *
748 * @param sourcePortName
749 * long name of source port
750 * @param destinationPortName
751 * long name of destination port
752 * @return true if the connection was added, false if it already existed
753 * @throws JackException
754 * if the connection can't be established
755 */
756 public native boolean connect(String sourcePortName, String destinationPortName) throws JackException;
757
758 /**
759 * Remove a connection between two ports.
760 *
761 * <p>
762 * The port types must be identical, the source port must be an output port,
763 * and the destination port must be an input port.
764 *
765 * <p>
766 * The ports need not to belong to this client.
767 *
768 * @param sourcePortName
769 * long name of source port
770 * @param destinationPortName
771 * long name of destination port
772 * @throws JackException
773 * if the connection can't be established
774 */
775 public native void disconnect(String sourcePortName, String destinationPortName) throws JackException;
776
777 /**
778 * Returns full port names of to which the specified port is connected.
779 *
780 * This differs from {@link JackLocalPort#getConnections()} in two important
781 * respects:
782 * <ul>
783 * <li>You may not call this function from code that is executed in
784 * response to a JACK event. For example, you cannot use it in a
785 * GraphReordered handler.</li>
786 * <li>You need not be the owner of the port to get information about its
787 * connections.</li>
788 * </ul>
789 */
790 public native String[] getAllPortConnections(JackPort port) throws JackException;
791
792 /**
793 * Returns true if the specified port is owned by this client.
794 */
795 public native boolean isMine(JackPort port) throws JackException;
796
797 /**
798 * Recomputes port latencies.
799 */
800 public native void recomputeTotalLatencies() throws JackException;
801
802 /**
803 * Recomputes port latency.
804 */
805 public native void recomputeTotalPortLatency(JackPort port) throws JackException;
806
807 /**
808 * Returns port total latency.
809 */
810 public native int getTotalPortLatency(JackPort port) throws JackException;
811
812 /**
813 * If the port can be monitored, sets monitoring on or off.
814 */
815 public native void requestPortMonitorByName(String portName, boolean on) throws JackException;
816
817 /**
818 * Returns time in frames since Jack server began the current process cycle.
819 */
820 public native int framesSinceCycleStart();
821
822 /**
823 * Returns current frame time (running counter).
824 */
825 public native int frameTime();
826
827 /**
828 * Returns frame time after the last processing of the graph.
829 *
830 * <p>
831 * This method should only be called from {@link #process(int)} callback.
832 */
833 public native int lastFrameTime();
834
835 /**
836 * Converts time in microseconds to frame time.
837 */
838 public native int timeToFrames(long microseconds);
839
840 /**
841 * Converts time in microseconds to frame time.
842 */
843 public native long framesToTime(int frameTime);
844
845 /**
846 * Returns current time in microseconds.
847 */
848 public native long time();
849
850 /**
851 * Returns current CPU load.
852 */
853 public native float cpuLoad();
854
855 /**
856 * Returns the {@link Statistics} object associated with this client.
857 */
858 public Statistics getStatistics() {
859 return statistics;
860 }
861
862 /**
863 * Returns the object that allows operations on client thread.
864 *
865 * <p>
866 * Returns null if the thread wasn't created yet.
867 *
868 * <p>
869 * The {@link #setDefaultThreadInitCallback()} must be used, otherwise this
870 * method always returns null.
871 */
872 public JackClientThread getClientThread() {
873 return clientThread;
874 }
875
876 /**
877 * Loads internal client.
878 *
879 * @param clientName
880 * name of internal client
881 * @param useExactName
882 * if set to true, request that the client have exact clientName;
883 * otherwise, Jack server may generate unique name
884 * @param sharedObjectName
885 * if not null, specifies name of shared library; otherwise,
886 * clientName is used
887 * @param initValue
888 * if not null, this string will be passed to internal client's
889 * <code>jack_initialize</code> function
890 */
891 public JackInternalClient loadInternalClient(String clientName, boolean useExactName, String sharedObjectName,
892 String initValue) throws JackException {
893 return internalClientForHandle(loadInternalClientNative(clientName, useExactName, sharedObjectName, initValue));
894 }
895
896 private native long loadInternalClientNative(String clientName, boolean useExactName, String sharedObjectName,
897 String initValue) throws JackException;
898
899 /**
900 * Returns an object that represents internal client with specified name.
901 *
902 * @throws JackException
903 * if the client doesn't exist or if other error occurred
904 */
905 public JackInternalClient internalClientByName(String clientName) throws JackException {
906 return internalClientForHandle(internalClientByNameNative(clientName));
907 }
908
909 private native long internalClientByNameNative(String clientName) throws JackException;
910
911 private JackInternalClient internalClientForHandle(long handle) {
912 if (handle == 0) {
913 return null;
914 }
915
916 WeakReference<JackInternalClient> internalClientReference = internalClients.get(handle);
917
918 JackInternalClient internalClient = (internalClientReference == null) ? null : internalClientReference.get();
919
920 if (internalClient == null) {
921 internalClient = new JackInternalClient(clientHandle, handle);
922 internalClients.put(handle, new WeakReference<JackInternalClient>(internalClient));
923 }
924
925 return internalClient;
926 }
927
928 /**
929 * Called during each process cycle.
930 *
931 * <p>
932 * Must return zero on success, non-zero on error. If this method throws an
933 * exception, status -1 is returned to the server.
934 *
935 * <p>
936 * Normally, this method is not called as synchronized; see
937 * {@link #setProcessMethodSynchronized(boolean)}.
938 */
939 public abstract int process(int bufferSize) throws Exception;
940
941 /**
942 * Called once, when Jack server initializes client thread.
943 *
944 * <p>
945 * Exceptions thrown by this callback are ignored.
946 */
947 public abstract void threadInitCallback() throws Exception;
948
949 /**
950 * Called when Jack enters or leaves "freewheel" mode.
951 *
952 * <p>
953 * Exceptions thrown by this callback are ignored.
954 */
955 public abstract void freewheelCallback(boolean onoff) throws Exception;
956
957 /**
958 * Called when Jack buffer size changes.
959 *
960 * <p>
961 * Must return zero on success, non-zero on error. If this method throws an
962 * exception, status -1 is returned to the server.
963 */
964 public abstract int bufferSizeCallback(int newBufferSize) throws Exception;
965
966 /**
967 * Called when Jack sample rate changes.
968 *
969 * <p>
970 * Must return zero on success, non-zero on error. If this method throws an
971 * exception, status -1 is returned to the server.
972 */
973 public abstract int sampleRateCallback(int newSampleRate) throws Exception;
974
975 /**
976 * Called when another Jack client is registered/unregistered.
977 *
978 * <p>
979 * Exceptions thrown by this callback are ignored.
980 *
981 * @param clientName
982 * name of the other client
983 * @param registered
984 * true if the client is registered, false if it's unregistered
985 */
986 public abstract void clientRegistrationCallback(String clientName, boolean registered) throws Exception;
987
988 /**
989 * Called when Jack port is registered/unregistered.
990 *
991 * <p>
992 * Exceptions thrown by this callback are ignored.
993 *
994 * @param portId
995 * unique port ID (see {@link #portById(long)})
996 * @param registered
997 * true if the port is registered, false if it's unregistered
998 */
999 public abstract void portRegistrationCallback(long portId, boolean registered) throws Exception;
1000
1001 /**
1002 * CURRENTLY NOT WORKING.
1003 *
1004 * Called when two ports are connected or disconnected.
1005 *
1006 * <p>
1007 * Exceptions thrown by this callback are ignored.
1008 *
1009 * <p>
1010 * The Jack API documentation doesn't specify which port is source and which
1011 * is destination.
1012 *
1013 * @param portAId
1014 * unique ID of one of two ports connected or disconnected
1015 * @param portBId
1016 * unique ID of one of two ports connected or disconnected
1017 * @param connected
1018 * true if the connection is established, false if it's removed
1019 *
1020 * @see #portById(long)
1021 */
1022 public abstract void portConnectCallback(long portAId, long portBId, boolean connected) throws Exception;
1023
1024 /**
1025 * Called whenever the processing graph is reordered.
1026 *
1027 * <p>
1028 * Must return zero on success, non-zero on error. If this method throws an
1029 * exception, status -1 is returned to the server.
1030 */
1031 public abstract int graphOrderCallback() throws Exception;
1032
1033 /**
1034 * Called when Jack XRUN occurs.
1035 *
1036 * <p>
1037 * Must return zero on success, non-zero on error. If this method throws an
1038 * exception, status -1 is returned to the server.
1039 */
1040 public abstract int xRunCallback() throws Exception;
1041
1042 void localPortNameChanged(JackLocalPort jackLocalPort, String portName) {
1043 String oldName = null;
1044 for (Map.Entry<String, JackLocalPort> entry : localPorts.entrySet()) {
1045 if (entry.getValue() == jackLocalPort) {
1046 oldName = entry.getKey();
1047 break;
1048 }
1049 }
1050
1051 localPorts.remove(oldName);
1052 localPorts.put(portName, jackLocalPort);
1053 }
1054 }