View Javadoc

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 }