diff --git a/ChangeLog b/ChangeLog index fbb75e3c..06afa7d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,9 +34,38 @@ Valerio Pilo Jackdmp changes log --------------------------- +2011-03-29 Stephane Letz + + * Synchronize JackWeakAPI.cpp with new APIs. + +2011-03-28 Stephane Letz + + * Correction of jack_connect/jack_disconnect: use of jack_activate and volatile keyword for thread shared variable. + * Correction of JackNetOneDriver for latest CELT API. + +2011-03-24 Stephane Letz + + * Implement renaming in JackDriver::Open to avoid name collision (thanks Devin Anderson). + * Correct alsa_driver_restart (thanks Devin Anderson). + +2011-03-23 Stephane Letz + + * Devin Anderson server-ctl-proposal branch merged on trunk: improved control API, slave backend reworked. + +2011-03-14 Stephane Letz + + * Correct JackEngine::NotifyGraphReorder, update JackDebugClient with latest API. + +2011-03-13 Stephane Letz + + * Rework internal slave driver management, JackServerGlobals now handle same parameters as jackdmp. + 2011-03-11 Stephane Letz * Correct JackNetMaster::SetBufferSize. + * Use jack_default_audio_sample_t instead of float consistently, fix ticket #201." + * -X now allows to add several slave backends, add -I to load several internal clients. + 2011-03-10 Stephane Letz diff --git a/README b/README index 92eb746d..b9a0a533 100644 --- a/README +++ b/README @@ -1,14 +1,14 @@ ------------------------------------------------ -jackdmp for Linux, MacOSX, Windows and Solaris ------------------------------------------------ +----------------------------------------------------------- +jackdmp (aka JACK2) for Linux, MacOSX, Windows and Solaris +----------------------------------------------------------- -jackdmp is a C++ version of the JACK low-latency audio server for multi-processor machines. It is a new implementation of the JACK server core features that aims in removing some limitations of the current design. The activation system has been changed for a data flow model and lock-free programming techniques for graph access have been used to have a more dynamic and robust system. +jackdmp is a C++ version of the JACK low-latency audio server for multi-processor machines. It is a new implementation of the JACK server core features that aims in removing some limitations of the JACK1 design. The activation system has been changed for a data flow model and lock-free programming techniques for graph access have been used to have a more dynamic and robust system. - jackdmp use a new client activation model that allows simultaneous client execution (on a smp machine) when parallel clients exist in the graph (client that have the same inputs). This activation model allows to better use available CPU on a smp machine, but also works on mono-processor machine. - jackdmp use a lock-free way to access (read/write) the client graph, thus allowing connections/disconnection to be done without interrupting the audio stream. The result is that connections/disconnections are glitch-free. -- jackdmp can work in 2 different mode at the server level : +- jackdmp can work in 2 different modes at the server level : - synchronous activation : in a given cycle, the server waits for all clients to be finished (similar to normal jackd) @@ -20,7 +20,7 @@ The audible result of this mode is that if a client is not activated during one Linux version -------------- -The published version still uses fifos for server/client synchronization. The use of POSIX named semaphore is implemented but still a bit unstable. Sockets are used for server/client communications. The ALSA backend derived from jackd implementation is used. To build jackdmp, a "waf" (http://code.google.com/p/waf/) based compilation system is available. The code has to be compiled on a machine where ALSA and possibly frebob (FFADO) headers and libraries are corrected installed. +The published version still uses fifos for server/client synchronization. The use of POSIX named semaphore is implemented but still a bit unstable. Sockets are used for server/client communications. The ALSA backend derived from jackd implementation is used. To build jackdmp, a "waf" (http://code.google.com/p/waf/) based compilation system is available. The code has to be compiled on a machine where ALSA and possibly freeboot (FFADO) headers and libraries are corrected installed. In the top folder do : @@ -54,7 +54,7 @@ In the top folder do : ./waf build sudo ./waf install -(Note : you may have to use "pfexec" instead of "sudo" on systems where sudo is not there.) +(Note : you may have to use "pfexec" instead of "sudo" on systems where sudo is not there). Various compilation options can be seen using ./waf --help. @@ -68,43 +68,37 @@ Starting the server : - for best performances, the server has to be started with privileges that allows to use "real-time" threads, for example using the "pfexec" command (or configurating the system with "priocntl" first), for instance : pfexec jackd -R -S -P59 -d oss -- audio cards info can be retrieved using "ossinfo" tool (for instance ossinfo -v3). Some card needs to be configurated first using "ossxmix" then the correct buffer size has to be used, for instance : pfexec jackd -R -S -P59 -d oss -p 512 +- audio cards info can be retrieved using "ossinfo" tool (for instance ossinfo -v3). Some card needs to be configured first using "ossxmix" then the correct buffer size has to be used, for instance : pfexec jackd -R -S -P59 -d oss -p 512 ------------ OSX version ------------ -The published version uses Mach semaphores for server/client synchronization. MIG generated Remote Procedure Calls (RPC) are used for server/client communications. The CoreAudio backend derived from jackd implementation is used. - -The package contains : - - - the compiled binaries with "install" and "remove" scripts located in bin/osx - - the source code with an XCode project - - the component needed to use CoreAudio applications with JACK (the JackRouter JACK/CoreAudio bridge) +The published version uses Mach semaphores for server/client synchronization. Sockets are used for server/client communications. The CoreAudio backend derived from JACK1 implementation is used. Starting with 0.70 version, the OSX project can compile 32/64 bits binaries for PPC and Intel machines. On a 64 bits machine, using the "jackdmp" in a terminal will start the 64 bits version. Using the "arch" command possibly allows to force starting in 32 bits (see man arch). The JackPilot and JackRouter binaries are now also released as 32/64 bits versions for PPC and Intel machines. By default the JackPilot application will start in 32 bits mode (even on a 64 bits machine) and launch the 32 bits jackdmp. Unchecking the "Launch in 32 bits mode" box in the JackPilot info (GetInfo = %I in the Finder...) allows to start JackPilot in 64 bits then launch the 64 bits jackdmp version. Very few audio applications are already 64 bits aware: Apple AU Lab (included in Developer tools) can be launched in 64 bit, here again by unchecking the "Launch in 32 bits mode" box in the AU Lab info. -WARNING !! WARNING !! - -Users of the "official" JackOSX package (found at www.jackosx.com) MUST uninstall JackOSX (using the script located in /Applications/Jack) before installing and testing jackdmp. The "official" JackOSX package can then be re-installed by using the JackOSX installer again. +JackOSX package (found at www.jackosx.com) is the preferred way to Jackdmp on OSX. --------------------------------- Mac Intel special considerations --------------------------------- -- New Mac Intel use 2 different coreaudio device for input/output. Jackdmp cannot directly handle 2 devices to do duplex processing. An "aggregate" device has to be built in this case. +- New Mac Intel use 2 different CoreAudio device for input/output. Jackdmp cannot directly handle 2 devices to do duplex processing. An "aggregate" device has to be built in this case. Use the "/Applications/Utilities/Audio MIDI Setup" tool to build and aggregate device that combine both input and output in a single duplex device, then select it when launching jackdmp, with something like : jackdmp -R -d coreaudio -n "~:Aggregate:0" -or directly with the JackPilot tool. +or directly with the JackPilot tool. + +Starting from 1.9.6 version, the CoreAudio diver can now dynamically aggregate devices. So using "Audio MIDI Setup" tool is not mandatory anymore. - CoreAudio applications running under Rosetta emulator cannot access an Intel version of Jackdmp. -Using Jackdmp with Qjackctl : +Using jackdmp with QjackCtl : -To start jackdmp server in Qjackctl, the complete server path has to be added, like /usr/local/bin/jackdmp in Setup/Server Path. +To start jackdmp server in QjackCtl, the complete server path has to be added, like /usr/local/bin/jackdmp in Setup/Server Path. ---------------- Windows version @@ -124,7 +118,9 @@ The binary elements are : - jack_dummy.dll : the "dummy" driver. -- jack_net.dll : the NetJack driver. +- jack_net.dll : the NetJack2 driver. + +- jack_netone.dll : the NetJack1 driver. - netmanager.dll : the "in server" client NetJack Manager. @@ -132,13 +128,13 @@ The binary elements are : - netadapter.dll : the network to audio card adapter (to be used on a slave machine started with an audio driver). -- jack_connect.exe, jack_disconnect.exe, jack_lsp.exe, jack_metro.exe, jack_load.exe, jack_unload.exe tools. +- jack_connect.exe, jack_disconnect.exe, jack_lsp.exe, jack_metro.exe, jack_load.exe, jack_unload.exe, jack_netsource.exe tools. -- JackRouter.dll : an ASIO/JACK driver that allows ASIO compatible applications to become JACK clients and access the JACK server. ASIO "jackified" applications appear with their names. Ableton Live, Samplitude, Reason, Arturia applications have been successfully tested. To install it, use "regsvr32 JackRouter.dll" in a terminal (use regsvr32 /u JackRouter.dll to uninstall). [VISTA special note: regsvr32 has to be used with "administrator" priviledges to properly register JackRouter.dll (Start Menu -> All Programs -> Accessories -> Right Click on Command Prompt -> Run As Administrator)]. A JackRouter.ini file is used by the driver to read parameters : an [IO] section allows to setup the number of input/output jack ports for the application and a [AUTO_CONNECT] section allows to setup jack ports autoconnection mode to machine input/output. +- JackRouter.dll : an ASIO/JACK driver that allows ASIO compatible applications to become JACK clients and access the JACK server. ASIO "jackified" applications appear with their names. Ableton Live, Samplitude, Reason, Arturia applications have been successfully tested. To install it, use "regsvr32 JackRouter.dll" in a terminal (use regsvr32 /u JackRouter.dll to uninstall). [VISTA special note: regsvr32 has to be used with "administrator" rights to properly register JackRouter.dll (Start Menu -> All Programs -> Accessories -> Right Click on Command Prompt -> Run As Administrator)]. A JackRouter.ini file is used by the driver to read parameters : an [IO] section allows to setup the number of input/output jack ports for the application and a [AUTO_CONNECT] section allows to setup jack ports auto connection mode to machine input/output. WARNING !! WARNING !! -Depending of the used interface and driver settings, the PortAudio layer may add additionnal buffering between the real card interrupt and the jack server callback. This usually result in *unregular* calls of the jack server callback (for example if jack server used a 256 frames buffer and the card used a 512 frames, the jack server callback will be called twice every card interrupt). For proper functionning of jack server and clients in this case, the jack server has to be started in "synchronous" mode, using the "-S" parameter. +Depending of the used interface and driver settings, the PortAudio layer may add additional buffering between the real card interrupt and the jack server callback. This usually result in *unregular* calls of the jack server callback (for example if jack server used a 256 frames buffer and the card used a 512 frames, the jack server callback will be called twice every card interrupt). For proper functioning of jack server and clients in this case, the jack server has to be started in "synchronous" mode, using the "-S" parameter. ---------------------------- Known problems, limitations @@ -150,7 +146,7 @@ Known problems, limitations Automatic server launch ---------------------------- -Starting from the 0.64 version, automatic server launch from client is implemented : when the server is not yet running, and if the client uses the "jack_client_open" API, the server will be started automatically. The server configuration is saved in a ".jackdrc" file located in the user home folder. The Qjackctl tool allows to save its configuration in this . jackdrc (setting can be done in Qjackctl Setup/Misc). If no configuration file is found, a default setup will be used. +Starting from the 0.64 version, automatic server launch from client is implemented : when the server is not yet running, QjackCtl if the client uses the "jack_client_open" API, the server will be started automatically. The server configuration is saved in a ".jackdrc" file located in the user home folder. The QjackCtl tool allows to save its configuration in this .jackdrc (setting can be done in QjackCtl Setup/Misc). If no configuration file is found, a default setup will be used. WARNING : automatic server launch is not implemented on Windows @@ -158,7 +154,7 @@ WARNING : automatic server launch is not implemented on Windows Validations tools ------------------ -jackdmp can possibly validate client applications by checking they are using the API in a correct manner (calling functions in the right order, correctly desallocating ressources....) and produce a log file. A JACK_CLIENT_DEBUG environment variable must be used to activate client validation : use "export JACK_CLIENT_DEBUG=on". +jackdmp can possibly validate client applications by checking they are using the API in a correct manner (calling functions in the right order, correctly deallocating resources....) and produce a log file. A JACK_CLIENT_DEBUG environment variable must be used to activate client validation : use "export JACK_CLIENT_DEBUG=on". -------------- Documentation @@ -182,7 +178,7 @@ Note : To experiment with the -S option, jackdmp must be launched in a console. 0.42 : Patch from Nick Mainsbridge. Correct default mode for ALSA driver. Correct XCode project. 0.43 : Correct freewheel mode. Optimize ALSA and coreaudio drivers. Correct OSX installation script. 0.44 : Patch from Dmitry Daikov : use clock_gettime by default for timing. Correct dirty buffer issue in CoreAudio driver. Updated doc. -0.45 : Script to remove the OSX binary stuff. Correct an export symbol issue that was preventing Qjacktcl to work on OSX. Fix the consequences of the asynchronous semantic of connections/disconnections. +0.45 : Script to remove the OSX binary stuff. Correct an export symbol issue that was preventing QjackCtl to work on OSX. Fix the consequences of the asynchronous semantic of connections/disconnections. 0.46 : Fix a bug in loop management. Fix a bug in driver loading/unloading code. Internal code cleanup for better 64 bits architecture support. Compilation on OSX/Intel. Add the -d option for coreaudio driver (display CoreAudio devices internal name). 0.47 : More fix for 64 bits compilation. Correct ALSA driver. Create a specific folder for jackdmp drivers. Use /dev/shm as default for fifo and sockets. "Install" and "Remove" script for smoother use with regular jack. 0.48 : Finish software monitoring implementation for ALSA and CoreAudio drivers. Simpler shared library management on OSX. @@ -199,25 +195,26 @@ Note : To experiment with the -S option, jackdmp must be launched in a console. 0.59 : Various fixes in Windows version. Signal handling in the Windows server. Improved JackRouter ASIO/Jack bridge on Windows. Rename global "verbose" in "jack_verbose" to avoid symbol clash with PureData. Add a new cpu testing/loading client. Correct server SetBufferSize in case of failure. Correct PortAudio driver help. Use -D to setup ADDON_DIR on OSX and Linux. Synchronize ALSA backend with jack one. 0.60 : Improve audio driver synchronous code to better handle possible time-out cases. Correct JackWinEnvent::Allocate (handle the ERROR_ALREADY_EXISTS case). Correct JackEngine::ClientExternalNew. 0.61 : Tom Szilagyi memory leak fix in ringbuffer.c. Move client refnum management in JackEngine. Shared_ports renamed to shared_graph. Add call to the init callback (set up using the jack_set_thread_init_callback API) in Real-Time and Notification threads. Define a new 'kActivateClient' notification. New server/client data transfer model to fix a 64 bits system bug. Fix a device name reversal bug in ALSA driver. Implement thread.h API. -0.62 : More client debug code : check if the client is still valid in every JackDebugClient method, check if the library context is still valid in every API call. Uses a time out value of 10 sec in freewheel mode (like jack). More robust activation/deactivation code, especially in case of client crash. New LockAllMemory and UnlockAllMemory functions. Use pthread_attr_setstacksize in JackPosixThread class. Add Pieter Palmers FreeBob driver. Thibault LeMeur ALSA driver patch. Thom Johansen fix for port buffer alignment issues. Better error checking in PortAudio driver. +0.62 : More client debug code : check if the client is still valid in every JackDebugClient method, check if the library context is still valid in every API call. Uses a time out value of 10 sec in freewheel mode (like jack). More robust activation/deactivation code, especially in case of client crash. New LockAllMemory and UnlockAllMemory functions. Use pthread_attr_setstacksize in JackPosixThread class. Add Pieter Palmers FreeBob driver. Thibault LeMeur ALSA driver patch. Thom Johansen fix for port buffer alignment issues. Better error checking in PortAudio driver. 0.63 : Correct back JackAlsaDriver::Read method. Dmitry Baikov patch for JackGraphManager.cpp. Merge JackGraphManager Remove and Release method in a unique Release method. Dmitry Baikov jackmp-time patch : add jack_get_time, jack_time_to_frames, jack_frames_to_time. Add missing -D__SMP__in OSX project. Add new jack_port_set_alias, jack_port_unset_alias and jack_port_get_aliases API. Steven Chamberlain patch to fix jack_port_by_id export. Steven Chamberlain patch to fix jack_port_type. Test for jack_port_type behaviour in jack_test.cpp tool. Add jack_set_client_registration_callback API. Add "callback exiting" and "jack_frame_time" tests in jack_test. 0.64 : Checking in the server to avoid calling the clients if no callback are registered. Correct deprecated jack_set_sample_rate_callback to return 0 instead of -1. Dmitry Baikov buffer size patch. Correct notification for kActivateClient event. Correct JackEngine::ClientCloseAux (when called from JackEngine::ClientExternalOpen). Correct JackWinEvent::Allocate. Automatic client renaming. Add "systemic" latencies management in CoreAudio driver. Automatic server launch. Removes unneeded 'volatile' for JackTransportEngine::fWriteCounter. 0.65 : Fix backend port alias management (renaming in system:xxx). Fix a bug in JackLibClient::Open introduced when adding automatic client renaming. Fix a bug in jack_test. Correct JackShmMem destructor. Correct end case in JackClient::Execute. Correct JackMachSemaphore::Disconnect. Implement server temporary (-T) mode. Make "Rename" a method of JackPort class, call it from driver Attach method. Server/library protocol checking implementation. 0.66 : Internal cleanup. Windows JackRouter.dll version 0.16 : use of "jack_client_open" API to allow automatic client renaming, better Windows VISTA support, new JackRouter.ini file. 0.67 : Correct jack_client_open "status" management. Rename server_name from "default" to "jackdmp_default" to avoid conflict with regular jackd server. Fix a resource leak issue in JackCoreAudioDriver::Close(). Better implement "jack_client_open" when linking a client with the server library. Correct "jack_register_server" in shm.c. Add missing timestamps.c and timestamps.h files. Correctly export public headers in OSX frameworks. Suppress JackEngine::ClientInternalCloseIm method. Use .jackdrc file (instead of .jackdmprc). Install script now creates a link "jackd ==> jackdmp" so that automatic launch can work correctly. Paul Davis patch for -r (--replace-registry) feature. Internal loadable client implementation. Fix JackEngine::Close() method. Windows JackRouter.dll version 0.17: 32 integer sample format. -0.68 : Internal loadable client implementation, winpipe version added. Reorganize jack headers. Improve Linux install/remove scripts. Use LIB_DIR variable for 64 bits related compilation (drivers location). More generic Linux script. Correct jack_acquire_real_time_scheduling on OSX. Merge of Dmitry Baikov MIDI branch. Correct JackGraphManager::GetPortsAux to use port type. Remove JackEngineTiming class: code moved in JackEngineControl. Add midiseq and midisine examples. Cleanup old zombification code. Linux Makefile now install jack headers. Use of JACK_CLIENT_DEBUG environment variable to activate debug client mode. Definition of JACK_LOCATION variable using -D in the Makefile. Restore jack 0.103.0 MIDI API version. Fix a bug in freewheel management in async mode: drivers now receive the kStartFreewheelCallback and kStopFreewheelCallback notifications. Server and user directory related code moved in a JackTools file. Client name rewritting to remove path characters (used in fifo naming). Correct ALSA driver Attach method: internal driver may have changed the buffer_size and sample_rate values. Add JackWinSemaphore class. Add an implementation for obsolete jack_internal_client_new and jack_internal_client_close. Add missing jack_port_type_size. Use of JackWinSemaphore instead of JackWinEvent for inter-process synchronization. Correct types.h for use with MINGW on Windows. Move OSX start/stop notification mechanism in Jackdmp.cpp. Correct CheckPort in JackAPI.cpp. +0.68 : Internal loadable client implementation, winpipe version added. Reorganize jack headers. Improve Linux install/remove scripts. Use LIB_DIR variable for 64 bits related compilation (drivers location). More generic Linux script. Correct jack_acquire_real_time_scheduling on OSX. Merge of Dmitry Baikov MIDI branch. Correct JackGraphManager::GetPortsAux to use port type. Remove JackEngineTiming class: code moved in JackEngineControl. Add midiseq and midisine examples. Cleanup old zombification code. Linux Makefile now install jack headers. Use of JACK_CLIENT_DEBUG environment variable to activate debug client mode. Definition of JACK_LOCATION variable using -D in the Makefile. Restore jack 0.103.0 MIDI API version. Fix a bug in freewheel management in async mode: drivers now receive the kStartFreewheelCallback and kStopFreewheelCallback notifications. Server and user directory related code moved in a JackTools file. Client name rewriting to remove path characters (used in fifo naming). Correct ALSA driver Attach method: internal driver may have changed the buffer_size and sample_rate values. Add JackWinSemaphore class. Add an implementation for obsolete jack_internal_client_new and jack_internal_client_close. Add missing jack_port_type_size. Use of JackWinSemaphore instead of JackWinEvent for inter-process synchronization. Correct types.h for use with MINGW on Windows. Move OSX start/stop notification mechanism in Jackdmp.cpp. Correct CheckPort in JackAPI.cpp. 0.69 : On OSX, use CFNotificationCenterPostNotificationWithOptions with kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions for server ==> JackRouter plugin notification. On OSX, use jack server name in notification system. Correct fPeriodUsecs computation in JackAudioDriver::SetBufferSize and JackAudioDriver::SetSampleRate. Correct JackMachNotifyChannel::ClientNotify. Correct bug in CoreAudio driver sample rate management. Add a sample_rate change listener in CoreAudio driver. Correct sample_rate management in JackCoreAudioDriver::Open. Better handling in sample_rate change listener. Pieter Palmers FFADO driver and scons based build. Pieter Palmers second new build system: scons and Makefile based build. Tim Blechmann scons patch. Change string management for proper compilation with gcc 4.2.2. JackLog cleanup. Cleanup in CoreAudio driver. Tim Blechmann patch for JackGraphManager::GetPortsAux memory leak, Tim Blechmann patch for scons install. Dmitry Baikov MIDI patch : alsa_seqmidi and alsa_rammidi drivers. CoreAudio driver improvement : detect and notify abnormal situations (stopped driver in case of SR change...). 0.70 : Updated API to match jack 0.109.0 version. Update in usx2y.c and JackPort.cpp to match jackd 0.109.2. Latest jack_lsp code from jack SVN. Add jack_mp_thread_wait client example. Add jack_thread_wait client example. Remove checking thread in CoreAudio driver, better device state change recovery strategy: the driver is stopped and restarted. Move transport related methods from JackEngine to JackServer. Tim Blechmann sse optimization patch for JackaudioPort::MixAudioBuffer, use of Apple Accelerate framework on OSX. Remove use of assert in JackFifo, JackMachSemaphore, and JackPosixSemaphore: print an error instead. Correct "server_connect": close the communication channel. More robust external API. Use SetAlias for port naming. Use jackd midi port naming scheme. Notify ports unregistration in JackEngine::ClientCloseAux. Fix in JackClient::Error(): when RT thread is failing and calling Shutdown, Shutdown was not desactivating the client correctly. 0.71 : Add port register/unregister notification in JackAlsaDriver. Correct JACK_port_unregister in MIDI backend. Add TimeCallback in JackDebugClient class. Correct jack_get_time propotype. Correct JackSocketClientChannel::ClientClose to use ServerSyncCall instead of ServerAsyncCall. Better documentation in jack.h. libjackdmp.so renamed to libjackservermp.so and same for OSX framework. Define an internal jack_client_open_aux needed for library wrapper feature. Remove unneeded jack_port_connect API. Correct jack_port_get_connections function (should return NULL when no connections). In thread model, execute a dummy cycle to be sure thread has the correct properties (ensure thread creation is finished). Fix engine real-time notification (was broken since ??). Implements wrapper layer. Correct jack_port_get_total_latency. Correct all backend playback port latency in case of "asynchronous" mode (1 buffer more). Add test for jack_cycle_wait, jack_cycle_wait and jack_set_process_thread API. RT scheduling for OSX thread (when used in dummy driver). Add -L (extra output latency in aynchronous mode) in CoreAudio driver. New JackLockedEngine decorator class to serialize access from ALSA Midi thread, command thread and in-server clients. Use engine in JackAlsaDriver::port_register and JackAlsaDriver::port_unregister. Fix connect notification to deliver *one* notification only. Correct JackClient::Activate so that first kGraphOrderCallback can be received by the client notification thread. New jack_server_control client to test notifications when linked to the server library. Synchronise transport.h with latest jackd version (Video handling). Transport timebase fix. Dmitry Baikov patch for alsa_rawmidi driver. Pieter Palmers patch for FFADO driver. Add an Init method for blocking drivers to be decorated using JackThreadedDriver class. Correct PortRegister, port name checking must be done on server side. Correct a missing parameter in the usage message of jack_midiseq. New SetNonBlocking method for JackSocket. Correct a dirty port array issue in JackGraphManager::GetPortsAux. 1.9.0 : Waf based build system : Nedko Arnaudov, Grame for preliminary OSX support. Control API, dbus based server control access : Nedko Arnaudov, Grame. NetJack2 components (in progress) : jack_net backend, netmanager, audioadapter, netadapter : Romain Moret, Grame. Code restructuring to help port on other architectures : Michael Voigt. Code cleanup/optimization : Tim Blechmann. Improve handling of server internal clients that can now be loaded/unloaded using the new server control API : Grame. A lot of bug fix and improvements. -1.9.1 : Fix jackctl_server_unload_internal. Filter SIGPIPE to avoid having client get a SIGPIPE when trying to access a died server. Libjack shutdown handler does not "deactivate" (fActive = false) the client anymore, so that jack_deactivate correctly does the job later on. Better isolation of server and clients system resources to allow starting the server in several user account at the same time. Report ringbuffer.c fixes from jack1. Client and library global context cleanup in case of incorrect shutdown handling (that is applications not correctly closing client after server has shutdown). Use JACK_DRIVER_DIR variable in internal clients loader. For ALSA driver, synchronize with latest jack1 memops functions. Synchronize jack2 public headers with jack1 ones. Implement jack_client_real_time_priority and jack_client_max_real_time_priority API. Use up to BUFFER_SIZE_MAX frames in midi ports, fix for ticket #117. Cleanup server starting code for clients directly linked with libjackserver.so. JackMessageBuffer was using thread "Stop" scheme in destructor, now use the safer thread "Kill" way. Synchronize ALSA backend code with JACK1 one. Set default mode to 'slow' in JackNetDriver and JackNetAdapter. Simplify audio packet order verification. Fix JackNetInterface::SetNetBufferSize for socket buffer size computation and JackNetMasterInterface::DataRecv if synch packet is received, various cleanup. Better recovery of network overload situations, now "resynchronize" by skipping cycles.". Support for BIG_ENDIAN machines in NetJack2. Support for BIG_ENDIAN machines in NetJack2 for MIDI ports. Support for "-h" option in internal clients to print the parameters. In NetJack2, fix a bug when capture or playback only channels are used. Add a JACK_INTERNAL_DIR environment variable to be used for internal clients. Add a resample quality parameter in audioadapter. Now correctly return an error if JackServer::SetBufferSize could not change the buffer size (and was just restoring the current one). Use PRIu32 kind of macro in JackAlsaDriver again. Add a resample quality parameter in netadapter. +1.9.1 : Fix jackctl_server_unload_internal. Filter SIGPIPE to avoid having client get a SIGPIPE when trying to access a died server. Libjack shutdown handler does not "deactivate" (fActive = false) the client anymore, so that jack_deactivate correctly does the job later on. Better isolation of server and clients system resources to allow starting the server in several user account at the same time. Report ringbuffer.c fixes from JACK1. Client and library global context cleanup in case of incorrect shutdown handling (that is applications not correctly closing client after server has shutdown). Use JACK_DRIVER_DIR variable in internal clients loader. For ALSA driver, synchronize with latest JACK1 memops functions. Synchronize JACK2 public headers with JACK1 ones. Implement jack_client_real_time_priority and jack_client_max_real_time_priority API. Use up to BUFFER_SIZE_MAX frames in midi ports, fix for ticket #117. Cleanup server starting code for clients directly linked with libjackserver.so. JackMessageBuffer was using thread "Stop" scheme in destructor, now use the safer thread "Kill" way. Synchronize ALSA backend code with JACK1 one. Set default mode to 'slow' in JackNetDriver and JackNetAdapter. Simplify audio packet order verification. Fix JackNetInterface::SetNetBufferSize for socket buffer size computation and JackNetMasterInterface::DataRecv if synch packet is received, various cleanup. Better recovery of network overload situations, now "resynchronize" by skipping cycles.". Support for BIG_ENDIAN machines in NetJack2. Support for BIG_ENDIAN machines in NetJack2 for MIDI ports. Support for "-h" option in internal clients to print the parameters. In NetJack2, fix a bug when capture or playback only channels are used. Add a JACK_INTERNAL_DIR environment variable to be used for internal clients. Add a resample quality parameter in audioadapter. Now correctly return an error if JackServer::SetBufferSize could not change the buffer size (and was just restoring the current one). Use PRIu32 kind of macro in JackAlsaDriver again. Add a resample quality parameter in netadapter. 1.9.2 : Solaris version. New "profiling" tools. Rework the mutex/signal classes. Support for BIG_ENDIAN machines in NetJack2. D-BUS based device reservation to better coexist with PulseAudio on Linux. Add auto_connect parameter in netmanager and netadapter. Use Torben Hohn PI controler code for adapters. Client incorrect re-naming fixed : now done at socket and fifo level. Virtualize and allow overriding of thread creation function, to allow Wine support (from JACK1). 1.9.3 : New JackBoomerDriver class for Boomer driver on Solaris. Add mixed 32/64 bits mode (off by default). Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver). In ALSA audio card reservation code, tries to open the card even if reservation fails. Clock source setting on Linux. Add jackctl_server_switch_master API. Fix transport callback (timebase master, sync) issue when used after jack_activate (RT thread was not running). D-Bus access for jackctl_server_add_slave/jackctl_server_remove_slave API. Cleanup "loopback" stuff in server. Torben Hohn fix for InitTime and GetMicroSeconds in JackWinTime.c. New jack_free function added in jack.h. Reworked Torben Hohn fix for server restart issue on Windows. Correct jack_set_error_function, jack_set_info_function and jack_set_thread_creator functions. Correct JackFifo::TimedWait for EINTR handling. Move DBus based audio device reservation code in ALSA backend compilation. Correct JackTransportEngine::MakeAllLocating, sync callback has to be called in this case also. NetJack2 code : better error checkout, method renaming. Tim Bechmann patch : hammerfall, only release monitor thread, if it has been created. Tim Bechmann memops.c optimization patches. In combined --dbus and --classic compilation code, use PulseAudio acquire/release code. Big rewrite of Solaris boomer driver, seems to work in duplex mode at least. Loopback backend reborn as a dynamically loadable separated backend. 1.9.4 : Solaris boomer backend now working in capture or playback only mode. Add a -G parameter in CoreAudio backend (the computation value in RT thread expressed as percent of period). Use SNDCTL_DSP_SYNCGROUP/SNDCTL_DSP_SYNCSTART API to synchronize input and output in Solaris boomer backend. Big endian bug fix in memops.c. Fix issues in JackNetDriver::DecodeTransportData and JackNetDriver::Initialize. Correct CPU timing in JackNetDriver, now take cycle begin time after Read. Simplify transport in NetJack2: master only can control transport. Change CoreAudio notification thread setup for OSX Snow Leopard. Correct server temporary mode : now set a global and quit after server/client message handling is finished. Add a string parameter to server ==> client notification, add a new JackInfoShutdownCallback type. CoreAudio backend now issue a JackInfoShutdownCallback when an unrecoverable error is detected (sampling rate change, stream configuration changeÉ). Correct jackdmp.cpp (failures case were not correct..). Improve JackCoreAudioDriver code. Raise default port number to 2048. Correct JackProcessSync::LockedTimedWait. Correct JACK_MESSAGE_SIZE value, particularly in OSX RPC code. Now start server channel thread only when backend has been started (so in JackServer::Start). Should solve race conditions at start time. jack_verbose moved to JackGlobals class. Improve aggregate device management in JackCoreAudioDriver : now a "private" device only and cleanup properly. Aggregate device code added to JackCoreAudioAdapter. Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. Fix jack_set_sample_rate_callback to have he same behavior as in JACK1. Dynamic system version detection in JackCoreAudioDriver to either create public or private aggregate device. In JackCoreAudioDriver, force the SR value to the wanted one *before* creating aggregate device (otherwise creation will fail). In JackCoreAudioDriver, better cleanup of AD when intermediate open failure. In JackCoreAudioDriver::Start, wait for the audio driver to effectively start (use the MeasureCallback). In JackCoreAudioDriver, improve management of input/output channels: -1 is now used internally to indicate a wanted max value. In JackCoreAudioDriver::OpenAUHAL, correct stream format setup and cleanup. Correct crash bug in JackAudioAdapterInterface when not input is used in adapter (temporary fixÉ). Sync JackCoreAudioAdapter code on JackCoreAudioDriver one. JACK_SCHED_POLICY switched to SCHED_FIFO. Now can aggregate device that are themselves AD. No reason to make jack_on_shutdown deprecated, so revert the incorrect change. Thread AcquireRealTime and DropRealTime were (incorrectly) using fThread field. Use pthread_self()) (or GetCurrentThread() on Windows) to get the calling thread. Correctly save and restore RT mode state in freewheel mode. Correct freewheel code on client side. Fix AcquireRealTime and DropRealTime: now distinguish when called from another thread (AcquireRealTime/DropRealTime) and from the thread itself (AcquireSelfRealTime/DropSelfRealTime). Correct JackPosixThread::StartImp : thread priority setting now done in the RT case only. Correct JackGraphManager::GetBuffer for the "client loop with one connection" case : buffer must be copied. Correct JackInfoShutdownCallback prototype, two new JackClientProcessFailure and JackClientZombie JackStatus code. Correct JackCoreAudio driver when empty strings are given as -C, -P or -d parameter. Better memory allocation error checking on client (library) side. Better memory allocation error checking in ringbuffer.c, weak import improvements. Memory allocation error checking for jack_client_new and jack_client_open (server and client side). Memory allocation error checking in server for RPC. Simplify server temporary mode : now use a JackTemporaryException. Lock/Unlock shared memory segments (to test...). Sync with JACK1 : -r parameter now used for no-realtime, realtime (-R) is now default, usable backend given vie platform. In JackCoreAudio driver, (possibly) clock drift compensation when needed in aggregated devices. In JackCoreAudio driver, clock drift compensation in aggregated devices working. In JackCoreAudio driver, clock drift compensation semantic changed a bit : when on, does not activate if not needed (same clock domain). Sync JackCoreAudioAdapter code with JackCoreAudioDriver. 1.9.5 : Dynamic choice of maximum port number. More robust sample rate change handling code in JackCoreAudioDriver. Devin Anderson patch for Jack FFADO driver issues with lost MIDI bytes between periods (and more). Fix port_rename callback : now both old name and new name are given as parameters. Special code in JackCoreAudio driver to handle completely buggy Digidesign CoreAudio user-land driver. Ensure that client-side message buffer thread calls thread_init callback if/when it is set by the client (backport of JACK1 rev 3838). Check dynamic port-max value. Fix JackCoreMidiDriver::ReadProcAux when ring buffer is full (thanks Devin Anderson). Josh Green ALSA driver capture only patch. When threads are cancelled, the exception has to be rethrown. Use a QUIT notification to properly quit the server channel, the server channel thread can then be 'stopped' instead of 'canceled'. Mario Lang alsa_io time calculation overflow patch. Shared memory manager was calling abort in case of fatal error, now return an error in caller. Change JackEngineProfiling and JackAudioAdapterInterface gnuplot scripts to output SVG instead of PDF. 1.9.6 : Improve JackCoreAudioDriver and JackCoreAudioAdapter : when no devices are described, takes default input and output and aggregate them.Correct JackGraphManager::DeactivatePort. Correct JackMachServerChannel::Execute : keep running even in error cases. Raise JACK_PROTOCOL_VERSION number. Arnold Krille firewire patch. Raise JACK_DRIVER_PARAM_STRING_MAX and JACK_PARAM_STRING_MAX to 127 otherwise some audio drivers cannot be loaded on OSX. Fix some file header to have library side code use LGPL. On Windows, now use TRE library for regexp (BSD license instead of GPL license). ffado-portname-sync.patch from ticket #163 applied. Remove call to exit in library code. Make jack_connect/jack_disconnect wait for effective port connection/disconnection. Add tests to validate intclient.h API. On Linux, inter-process synchronization primitive switched to POSIX semaphore. In JackCoreAudioDriver, move code called in MeasureCallback to be called once in IO thread. David Garcia Garzon netone patch. Fix from Fernando Lopez-Lezcano for compilation on fc13. Fix JackPosixSemaphore::TimedWait : same behavior as JackPosixSemaphore::Wait regarding EINTR. David Garcia Garzon unused_pkt_buf_field_jack2 netone patch. Arnold Krille firewire snooping patch. Jan Engelhardt patch for get_cycles on SPARC. Adrian Knoth hurd.patch, kfreebsd-fix.patch and alpha_ia64-sigsegv.patch from ticket 177. Adrian Knoth fix for linux cycle.h (ticket 188). In JackCoreAudioDriver, fix an issue when no value is given for input. +1.9.7 : Sync JackAlsaDriver::alsa_driver_check_card_type with JACK1 backend. Correct JackServer::Open to avoid a race when control API is used on OSX. Improve backend error handling: fatal error returned by Read/Write now cause a Process failure (so a thread exit for blocking backends). Recoverable ones (XRuns..) are now treated internally in ALSA, FreeBob and FFADO backends. In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. Correct symbols export in backends on OSX. ALSA backend : suspend/resume handling. Correct dummy driver. Adrian Knoth jack_lsp patch. Remove JackPortIsActive flag. New latency API implementation. ComputeTotalLatencies now a client/server call. Add latent test client for latency API. Also print playback and capture latency in jack_lsp. jack_client_has_session_callback implementation. Check requested buffer size and limit to 1..8192 - avoids weird behaviour caused by jack_bufsize foobar. jack_port_type_get_buffer_size implementation. Stop using alloca and allocate buffer on the heap for alsa_io. Rename jdelay to jack_iodelay as per Fons' request. Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). Add jack_midi_dump client. Synchronize net JACK1 with JACK1 version. Synchronize jack_connect/jack_disconnect with JACK1 version. Correct JackNetMaster::SetBufferSize. Use jack_default_audio_sample_t instead of float consistently, fix ticket #201. -X now allows to add several slave backends, add -I to load several internal clients. Rework internal slave driver management, JackServerGlobals now handle same parameters as jackdmp. Correct JackEngine::NotifyGraphReorder, update JackDebugClient with latest API. Devin Anderson server-ctl-proposal branch merged on trunk: improved control API, slave backend reworked. Implement renaming in JackDriver::Open to avoid name collision (thanks Devin Anderson). Correct alsa_driver_restart (thanks Devin Anderson). Correction of jack_connect/jack_disconnect: use of jack_activate and volatile keyword for thread shared variable. Correction of JackNetOneDriver for latest CELT API. Synchronize JackWeakAPI.cpp with new APIs. -This is a work in progress but the implementation is now stable enough to be tested. jackdmp has been used successfully with the following applications : Ardour, Hydrogen, Jamin, Qjackctl, Jack-Rack, SooperLooper, AlsaPlayer... +This is a work in progress but the implementation is now stable enough to be tested. jackdmp has been used successfully with the following applications : Ardour, Hydrogen, Jamin, QjackCtl, Jack-Rack, SooperLooper, AlsaPlayer... ------------------------------------ General known problems, limitations @@ -225,9 +222,7 @@ General known problems, limitations - zombification of clients is not implemented -- the number of server audio ports is fixed - -- memory locking is not implemented +- memory locking is implemented for shared data only The package is available at http://www.grame.fr/~letz/jackdmp.html diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index 550133cb..5c0d4cb1 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -116,7 +116,7 @@ extern "C" EXPORT int jack_set_xrun_callback(jack_client_t *, JackXRunCallback xrun_callback, void *arg); EXPORT int jack_set_latency_callback(jack_client_t *client, - JackLatencyCallback callback, void *arg); + JackLatencyCallback latency_callback, void *arg); EXPORT int jack_activate(jack_client_t *client); EXPORT int jack_deactivate(jack_client_t *client); diff --git a/common/JackAudioAdapter.cpp b/common/JackAudioAdapter.cpp index 03f4605f..9319b0f7 100644 --- a/common/JackAudioAdapter.cpp +++ b/common/JackAudioAdapter.cpp @@ -36,17 +36,17 @@ namespace Jack int JackAudioAdapter::Process (jack_nframes_t frames, void* arg) { JackAudioAdapter* adapter = static_cast(arg); - float* inputBuffer[adapter->fAudioAdapter->GetInputs()]; - float* outputBuffer[adapter->fAudioAdapter->GetOutputs()]; + jack_default_audio_sample_t* inputBuffer[adapter->fAudioAdapter->GetInputs()]; + jack_default_audio_sample_t* outputBuffer[adapter->fAudioAdapter->GetOutputs()]; // Always clear output for (int i = 0; i < adapter->fAudioAdapter->GetInputs(); i++) { - inputBuffer[i] = (float*)jack_port_get_buffer(adapter->fCapturePortList[i], frames); - memset(inputBuffer[i], 0, frames * sizeof(float)); + inputBuffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(adapter->fCapturePortList[i], frames); + memset(inputBuffer[i], 0, frames * sizeof(jack_default_audio_sample_t)); } for (int i = 0; i < adapter->fAudioAdapter->GetOutputs(); i++) { - outputBuffer[i] = (float*)jack_port_get_buffer(adapter->fPlaybackPortList[i], frames); + outputBuffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(adapter->fPlaybackPortList[i], frames); } adapter->fAudioAdapter->PullAndPush(inputBuffer, outputBuffer, frames); diff --git a/common/JackAudioAdapterInterface.h b/common/JackAudioAdapterInterface.h index a661598f..9573a68d 100644 --- a/common/JackAudioAdapterInterface.h +++ b/common/JackAudioAdapterInterface.h @@ -88,18 +88,18 @@ namespace Jack JackResampler** fCaptureRingBuffer; JackResampler** fPlaybackRingBuffer; - + unsigned int fQuality; unsigned int fRingbufferCurSize; jack_time_t fPullAndPushTime; - + bool fRunning; bool fAdaptative; - + void ResetRingBuffers(); void AdaptRingBufferSize(); void GrowRingBufferSize(); - + public: JackAudioAdapterInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, jack_nframes_t ring_buffer_size = DEFAULT_ADAPTATIVE_SIZE): @@ -140,15 +140,15 @@ namespace Jack {} virtual void Reset(); - + virtual void Create(); virtual void Destroy(); - + virtual int Open() { return 0; } - + virtual int Close() { return 0; @@ -157,7 +157,7 @@ namespace Jack virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) { fHostBufferSize = buffer_size; - if (fAdaptative) + if (fAdaptative) AdaptRingBufferSize(); return 0; } @@ -165,7 +165,7 @@ namespace Jack virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) { fAdaptedBufferSize = buffer_size; - if (fAdaptative) + if (fAdaptative) AdaptRingBufferSize(); return 0; } @@ -197,7 +197,7 @@ namespace Jack SetAdaptedSampleRate ( sample_rate ); return 0; } - + void SetInputs ( int inputs ) { jack_log ( "JackAudioAdapterInterface::SetInputs %d", inputs ); @@ -222,8 +222,8 @@ namespace Jack return fPlaybackChannels; } - int PushAndPull(float** inputBuffer, float** outputBuffer, unsigned int frames); - int PullAndPush(float** inputBuffer, float** outputBuffer, unsigned int frames); + int PushAndPull(jack_default_audio_sample_t** inputBuffer, jack_default_audio_sample_t** outputBuffer, unsigned int frames); + int PullAndPush(jack_default_audio_sample_t** inputBuffer, jack_default_audio_sample_t** outputBuffer, unsigned int frames); }; diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp index 1e02f213..272c1e66 100644 --- a/common/JackAudioDriver.cpp +++ b/common/JackAudioDriver.cpp @@ -138,14 +138,13 @@ int JackAudioDriver::Attach() // Monitor ports if (fWithMonitorPorts) { - jack_log("Create monitor port "); + jack_log("Create monitor port"); snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("Cannot register monitor port for %s", name); return -1; } else { port = fGraphManager->GetPort(port_index); - port->SetAlias(alias); range.min = range.max = fEngineControl->fBufferSize; port->SetLatencyRange(JackCaptureLatency, &range); fMonitorPortList[i] = port_index; @@ -178,8 +177,8 @@ int JackAudioDriver::Write() { for (int i = 0; i < fPlaybackChannels; i++) { if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { - float* buffer = GetOutputBuffer(i); - int size = sizeof(float) * fEngineControl->fBufferSize; + jack_default_audio_sample_t* buffer = GetOutputBuffer(i); + int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize; // Monitor ports if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) memcpy(GetMonitorBuffer(i), buffer, size); @@ -313,6 +312,26 @@ int JackAudioDriver::ProcessGraphSync() return res; } +int JackAudioDriver::Start() +{ + int res = JackDriver::Start(); + if ((res >= 0) && fIsMaster) { + res = StartSlaves(); + } + return res; +} + +int JackAudioDriver::Stop() +{ + int res = JackDriver::Stop(); + if (fIsMaster) { + if (StopSlaves() < 0) { + res = -1; + } + } + return res; +} + void JackAudioDriver::WaitUntilNextCycle() { int wait_time_usec = (int((float(fEngineControl->fBufferSize) / (float(fEngineControl->fSampleRate))) * 1000000.0f)); diff --git a/common/JackAudioDriver.h b/common/JackAudioDriver.h index 3127f4c1..8eaca692 100644 --- a/common/JackAudioDriver.h +++ b/common/JackAudioDriver.h @@ -92,6 +92,9 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver virtual int Attach(); virtual int Detach(); + virtual int Start(); + virtual int Stop(); + virtual int Write(); virtual int SetBufferSize(jack_nframes_t buffer_size); diff --git a/common/JackAudioPort.cpp b/common/JackAudioPort.cpp index c006b1cf..25483181 100644 --- a/common/JackAudioPort.cpp +++ b/common/JackAudioPort.cpp @@ -38,11 +38,11 @@ static void AudioBufferInit(void* buffer, size_t buffer_size, jack_nframes_t) memset(buffer, 0, buffer_size); } -static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_t frames) +static inline void MixAudioBuffer(jack_default_audio_sample_t* mixbuffer, jack_default_audio_sample_t* buffer, jack_nframes_t frames) { #ifdef __APPLE__ // It seems that a vector mult only operation does not exist... - float gain = 1.0f; + jack_default_audio_sample_t gain = jack_default_audio_sample_t(1.0); vDSP_vsma(buffer, 1, &gain, mixbuffer, 1, mixbuffer, 1, frames); #else jack_nframes_t frames_group = frames / 4; @@ -57,14 +57,14 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_ buffer += 4; frames_group--; #else - register float mixFloat1 = *mixbuffer; - register float sourceFloat1 = *buffer; - register float mixFloat2 = *(mixbuffer + 1); - register float sourceFloat2 = *(buffer + 1); - register float mixFloat3 = *(mixbuffer + 2); - register float sourceFloat3 = *(buffer + 2); - register float mixFloat4 = *(mixbuffer + 3); - register float sourceFloat4 = *(buffer + 3); + register jack_default_audio_sample_t mixFloat1 = *mixbuffer; + register jack_default_audio_sample_t sourceFloat1 = *buffer; + register jack_default_audio_sample_t mixFloat2 = *(mixbuffer + 1); + register jack_default_audio_sample_t sourceFloat2 = *(buffer + 1); + register jack_default_audio_sample_t mixFloat3 = *(mixbuffer + 2); + register jack_default_audio_sample_t sourceFloat3 = *(buffer + 2); + register jack_default_audio_sample_t mixFloat4 = *(mixbuffer + 3); + register jack_default_audio_sample_t sourceFloat4 = *(buffer + 3); buffer += 4; frames_group--; @@ -84,8 +84,8 @@ static inline void MixAudioBuffer(float* mixbuffer, float* buffer, jack_nframes_ } while (frames > 0) { - register float mixFloat1 = *mixbuffer; - register float sourceFloat1 = *buffer; + register jack_default_audio_sample_t mixFloat1 = *mixbuffer; + register jack_default_audio_sample_t sourceFloat1 = *buffer; buffer++; frames--; mixFloat1 += sourceFloat1; @@ -104,8 +104,8 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun jack_nframes_t frames_group = nframes / 4; jack_nframes_t remaining_frames = nframes % 4; - float * source = static_cast(src_buffers[0]); - float * target = static_cast(mixbuffer); + jack_default_audio_sample_t * source = static_cast(src_buffers[0]); + jack_default_audio_sample_t * target = static_cast(mixbuffer); while (frames_group > 0) { @@ -120,19 +120,19 @@ static void AudioBufferMixdown(void* mixbuffer, void** src_buffers, int src_coun target[i] = source[i]; #else - memcpy(mixbuffer, src_buffers[0], nframes * sizeof(float)); + memcpy(mixbuffer, src_buffers[0], nframes * sizeof(jack_default_audio_sample_t)); #endif // Mix remaining buffers for (int i = 1; i < src_count; ++i) { buffer = src_buffers[i]; - MixAudioBuffer(static_cast(mixbuffer), static_cast(buffer), nframes); + MixAudioBuffer(static_cast(mixbuffer), static_cast(buffer), nframes); } } static size_t AudioBufferSize() { - return GetEngineControl()->fBufferSize * sizeof(float); + return GetEngineControl()->fBufferSize * sizeof(jack_default_audio_sample_t); } const JackPortType gAudioPortType = diff --git a/common/JackClient.cpp b/common/JackClient.cpp index ae244688..8c3c6de5 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -496,8 +496,8 @@ bool JackClient::Init() // Setup RT if (GetEngineControl()->fRealTime) { - if (fThread.AcquireRealTime(GetEngineControl()->fClientPriority) < 0) { - jack_error("JackClient::AcquireRealTime error"); + if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) { + jack_error("JackClient::AcquireSelfRealTime error"); } } diff --git a/common/JackClient.h b/common/JackClient.h index 230edf53..a03e17d2 100644 --- a/common/JackClient.h +++ b/common/JackClient.h @@ -44,7 +44,7 @@ struct JackEngineControl; \brief The base class for clients: share part of the implementation for JackInternalClient and JackLibClient. */ -class JackClient : public JackClientInterface, public JackRunnableInterface +class SERVER_EXPORT JackClient : public JackClientInterface, public JackRunnableInterface { friend class JackDebugClient; @@ -195,15 +195,15 @@ class JackClient : public JackClientInterface, public JackRunnableInterface // RT Thread jack_nframes_t CycleWait(); void CycleSignal(int status); - int SetProcessThread(JackThreadCallback fun, void *arg); + virtual int SetProcessThread(JackThreadCallback fun, void *arg); // Session API virtual jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path); virtual int SessionReply(jack_session_event_t* ev); - char* GetUUIDForClientName(const char* client_name); - char* GetClientNameByUUID(const char* uuid); - int ReserveClientName(const char* client_name, const char* uuid); - int ClientHasSessionCallback(const char* client_name); + virtual char* GetUUIDForClientName(const char* client_name); + virtual char* GetClientNameByUUID(const char* uuid); + virtual int ReserveClientName(const char* client_name, const char* uuid); + virtual int ClientHasSessionCallback(const char* client_name); // JackRunnableInterface interface bool Init(); diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index cd0ec2bf..4ff69adc 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -78,15 +78,15 @@ struct jackctl_server /* int32_t, msecs; if zero, use period size. */ union jackctl_parameter_value client_timeout; union jackctl_parameter_value default_client_timeout; - + /* uint32_t, clock source type */ union jackctl_parameter_value clock_source; union jackctl_parameter_value default_clock_source; - + /* uint32_t, max port number */ union jackctl_parameter_value port_max; union jackctl_parameter_value default_port_max; - + /* bool */ union jackctl_parameter_value replace_registry; union jackctl_parameter_value default_replace_registry; @@ -366,7 +366,7 @@ jackctl_internals_load( } while (descriptor_node_ptr != NULL) - { + { internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal)); if (internal_ptr == NULL) { @@ -450,21 +450,21 @@ sigset_t jackctl_setup_signals( unsigned int flags) { - if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { + if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { jack_error("CreateEvent fails err = %ld", GetLastError()); return 0; } - (void) signal(SIGINT, do_nothing_handler); + (void) signal(SIGINT, do_nothing_handler); (void) signal(SIGABRT, do_nothing_handler); (void) signal(SIGTERM, do_nothing_handler); - return (sigset_t)waitEvent; + return (sigset_t)waitEvent; } void jackctl_wait_signals(sigset_t signals) { - if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { + if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { jack_error("WaitForSingleObject fails err = %ld", GetLastError()); } } @@ -539,7 +539,7 @@ jackctl_setup_signals( * explicitly reset it */ - pthread_sigmask(SIG_BLOCK, &signals, 0); + pthread_sigmask(SIG_BLOCK, &signals, 0); /* install a do-nothing handler because otherwise pthreads behaviour is undefined when we enter sigwait. @@ -745,7 +745,7 @@ EXPORT jackctl_server_t * jackctl_server_create( { goto fail_free_parameters; } - + value.ui = PORT_NUM; if (jackctl_add_parameter( &server_ptr->parameters, @@ -795,7 +795,7 @@ EXPORT jackctl_server_t * jackctl_server_create( { goto fail_free_parameters; } - + /* Allowed to fail */ jackctl_internals_load(server_ptr); @@ -826,6 +826,11 @@ EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr EXPORT bool jackctl_server_stop(jackctl_server *server_ptr) { server_ptr->engine->Stop(); + return true; +} + +EXPORT bool jackctl_server_close(jackctl_server *server_ptr) +{ server_ptr->engine->Close(); delete server_ptr->engine; @@ -853,7 +858,7 @@ EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr) } EXPORT bool -jackctl_server_start( +jackctl_server_open( jackctl_server *server_ptr, jackctl_driver *driver_ptr) { @@ -882,7 +887,7 @@ jackctl_server_start( if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ - + /* check port max value before allocating server */ if (server_ptr->port_max.ui > PORT_NUM_MAX) { jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); @@ -896,7 +901,7 @@ jackctl_server_start( server_ptr->client_timeout.i, server_ptr->realtime.b, server_ptr->realtime_priority.i, - server_ptr->port_max.ui, + server_ptr->port_max.ui, server_ptr->verbose.b, (jack_timer_type_t)server_ptr->clock_source.ui, server_ptr->name.str); @@ -913,18 +918,8 @@ jackctl_server_start( goto fail_delete; } - rc = server_ptr->engine->Start(); - if (rc < 0) - { - jack_error("JackServer::Start() failed with %d", rc); - goto fail_close; - } - return true; -fail_close: - server_ptr->engine->Close(); - fail_delete: delete server_ptr->engine; server_ptr->engine = NULL; @@ -946,6 +941,19 @@ fail: return false; } +EXPORT bool +jackctl_server_start( + jackctl_server *server_ptr) +{ + int rc = server_ptr->engine->Start(); + bool result = rc >= 0; + if (! result) + { + jack_error("JackServer::Start() failed with %d", rc); + } + return result; +} + EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr) { return driver_ptr->desc_ptr->name; @@ -1179,7 +1187,7 @@ EXPORT bool jackctl_server_load_internal( { int status; if (server_ptr->engine != NULL) { - server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, -1, &status); + server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, -1, &status); return (internal->refnum > 0); } else { return false; @@ -1192,6 +1200,7 @@ EXPORT bool jackctl_server_unload_internal( { int status; if (server_ptr->engine != NULL && internal->refnum > 0) { + // Client object is internally kept in JackEngine, and will be desallocated in InternalClientUnload return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0); } else { return false; @@ -1201,8 +1210,13 @@ EXPORT bool jackctl_server_unload_internal( EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) { if (server_ptr->engine != NULL) { - driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); - return (driver_ptr->info != 0); + if (server_ptr->engine->IsRunning()) { + jack_error("cannot add a slave in a running server"); + return false; + } else { + driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); + return (driver_ptr->info != 0); + } } else { return false; } @@ -1211,9 +1225,14 @@ EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) { if (server_ptr->engine != NULL) { - server_ptr->engine->RemoveSlave(driver_ptr->info); - delete driver_ptr->info; - return true; + if (server_ptr->engine->IsRunning()) { + jack_error("cannot remove a slave from a running server"); + return false; + } else { + server_ptr->engine->RemoveSlave(driver_ptr->info); + delete driver_ptr->info; + return true; + } } else { return false; } diff --git a/common/JackControlAPI.h b/common/JackControlAPI.h index d0b0cbc1..8e87d513 100644 --- a/common/JackControlAPI.h +++ b/common/JackControlAPI.h @@ -101,13 +101,21 @@ jackctl_server_get_drivers_list( jackctl_server_t * server); EXPORT bool -jackctl_server_start( +jackctl_server_open( jackctl_server_t * server, jackctl_driver_t * driver); +EXPORT bool +jackctl_server_start( + jackctl_server_t * server); + EXPORT bool jackctl_server_stop( - jackctl_server_t * server); + jackctl_server_t * server); + +EXPORT bool +jackctl_server_close( + jackctl_server_t * server); EXPORT const JSList * jackctl_server_get_parameters( diff --git a/common/JackDebugClient.cpp b/common/JackDebugClient.cpp index 3c389abc..a1a2fe69 100644 --- a/common/JackDebugClient.cpp +++ b/common/JackDebugClient.cpp @@ -505,6 +505,54 @@ int JackDebugClient::SetPortRenameCallback(JackPortRenameCallback callback, void return fClient->SetPortRenameCallback(callback, arg); } +int JackDebugClient::SetSessionCallback(JackSessionCallback callback, void *arg) +{ + CheckClient("SetSessionCallback"); + return fClient->SetSessionCallback(callback, arg); +} + +int JackDebugClient::SetLatencyCallback(JackLatencyCallback callback, void *arg) +{ + CheckClient("SetLatencyCallback"); + return fClient->SetLatencyCallback(callback, arg); +} + +jack_session_command_t* JackDebugClient::SessionNotify(const char* target, jack_session_event_type_t type, const char* path) +{ + CheckClient("SessionNotify"); + return fClient->SessionNotify(target, type, path); +} + +int JackDebugClient::SessionReply(jack_session_event_t* ev) +{ + CheckClient("SessionReply"); + return fClient->SessionReply(ev); +} + +char* JackDebugClient::GetUUIDForClientName(const char* client_name) +{ + CheckClient("GetUUIDForClientName"); + return fClient->GetUUIDForClientName(client_name); +} + +char* JackDebugClient::GetClientNameByUUID(const char* uuid) +{ + CheckClient("GetClientNameByUUID"); + return fClient->GetClientNameByUUID(uuid); +} + +int JackDebugClient::ReserveClientName(const char* client_name, const char* uuid) +{ + CheckClient("ReserveClientName"); + return fClient->ReserveClientName(client_name, uuid); +} + +int JackDebugClient::ClientHasSessionCallback(const char* client_name) +{ + CheckClient("ClientHasSessionCallback"); + return fClient->ClientHasSessionCallback(client_name); +} + JackClientControl* JackDebugClient::GetClientControl() const { CheckClient("GetClientControl"); diff --git a/common/JackDebugClient.h b/common/JackDebugClient.h index 6a19deca..465d9465 100644 --- a/common/JackDebugClient.h +++ b/common/JackDebugClient.h @@ -46,7 +46,7 @@ PortFollower; \brief A "decorator" debug client to validate API use. */ -class JackDebugClient : public JackClient +class SERVER_EXPORT JackDebugClient : public JackClient { protected: @@ -121,6 +121,8 @@ class JackDebugClient : public JackClient int SetPortRegistrationCallback(JackPortRegistrationCallback callback, void* arg); int SetPortConnectCallback(JackPortConnectCallback callback, void *arg); int SetPortRenameCallback(JackPortRenameCallback callback, void *arg); + int SetSessionCallback(JackSessionCallback callback, void *arg); + int SetLatencyCallback(JackLatencyCallback callback, void *arg); // Internal clients char* GetInternalClientName(int ref); @@ -128,6 +130,14 @@ class JackDebugClient : public JackClient int InternalClientLoad(const char* client_name, jack_options_t options, jack_status_t* status, jack_varargs_t* va); void InternalClientUnload(int ref, jack_status_t* status); + // Session API + jack_session_command_t* SessionNotify(const char* target, jack_session_event_type_t type, const char* path); + int SessionReply(jack_session_event_t* ev); + char* GetUUIDForClientName(const char* client_name); + char* GetClientNameByUUID(const char* uuid); + int ReserveClientName(const char* client_name, const char* uuid); + int ClientHasSessionCallback(const char* client_name); + JackClientControl* GetClientControl() const; void CheckClient(const char* function_name) const; diff --git a/common/JackDriver.cpp b/common/JackDriver.cpp index a2c6ccd6..ce860468 100644 --- a/common/JackDriver.cpp +++ b/common/JackDriver.cpp @@ -47,6 +47,7 @@ JackDriver::JackDriver(const char* name, const char* alias, JackLockedEngine* en fBeginDateUst = 0; fDelayedUsecs = 0.f; fIsMaster = true; + fIsRunning = false; } JackDriver::JackDriver() @@ -56,6 +57,7 @@ JackDriver::JackDriver() fGraphManager = NULL; fBeginDateUst = 0; fIsMaster = true; + fIsRunning = false; } JackDriver::~JackDriver() @@ -80,7 +82,7 @@ int JackDriver::Open() return 0; } -int JackDriver::Open (bool capturing, +int JackDriver::Open(bool capturing, bool playing, int inchannels, int outchannels, @@ -93,6 +95,15 @@ int JackDriver::Open (bool capturing, jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name); jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name); int refnum = -1; + char name_res[JACK_CLIENT_NAME_SIZE + 1]; + int status; + + // Check name and possibly rename + if (fEngine->ClientCheck(fClientControl.fName, -1, name_res, JACK_PROTOCOL_VERSION, (int)JackNullOption, (int*)&status) < 0) { + jack_error("Client name = %s conflits with another running client", fClientControl.fName); + return -1; + } + strcpy(fClientControl.fName, name_res); if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { jack_error("Cannot allocate internal client for driver"); @@ -135,6 +146,15 @@ int JackDriver::Open(jack_nframes_t buffer_size, jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name); jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name); int refnum = -1; + char name_res[JACK_CLIENT_NAME_SIZE + 1]; + int status; + + // Check name and possibly rename + if (fEngine->ClientCheck(fClientControl.fName, -1, name_res, JACK_PROTOCOL_VERSION, (int)JackNullOption, (int*)&status) < 0) { + jack_error("Client name = %s conflits with another running client", fClientControl.fName); + return -1; + } + strcpy(fClientControl.fName, name_res); if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { jack_error("Cannot allocate internal client for driver"); @@ -288,6 +308,7 @@ int JackDriver::ProcessSlaves() JackDriverInterface* slave = *it; if (slave->Process() < 0) res = -1; + } return res; } @@ -324,15 +345,49 @@ int JackDriver::Write() int JackDriver::Start() { - fEngineControl->InitFrameTime(); + if (fIsMaster) { + fEngineControl->InitFrameTime(); + } + fIsRunning = true; return 0; } +int JackDriver::StartSlaves() +{ + int res = 0; + list::const_iterator it; + for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { + JackDriverInterface* slave = *it; + if (slave->Start() < 0) { + res = -1; + + // XXX: We should attempt to stop all of the slaves that we've + // started here. + + break; + } + } + return res; +} + int JackDriver::Stop() { + fIsRunning = false; return 0; } +int JackDriver::StopSlaves() +{ + int res = 0; + list::const_iterator it; + for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { + JackDriverInterface* slave = *it; + if (slave->Stop() < 0) + res = -1; + } + return res; +} + bool JackDriver::IsFixedBufferSize() { return true; diff --git a/common/JackDriver.h b/common/JackDriver.h index 6f230831..68f937c2 100644 --- a/common/JackDriver.h +++ b/common/JackDriver.h @@ -97,6 +97,7 @@ class SERVER_EXPORT JackDriverInterface virtual int ProcessSlaves() = 0; virtual bool IsRealTime() const = 0; + virtual bool IsRunning() const = 0; }; /*! @@ -134,6 +135,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface JackClientControl fClientControl; std::list fSlaveList; bool fIsMaster; + bool fIsRunning; void CycleIncTime(); void CycleTakeBeginTime(); @@ -198,7 +200,9 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface virtual int Write(); virtual int Start(); + virtual int StartSlaves(); virtual int Stop(); + virtual int StopSlaves(); virtual bool IsFixedBufferSize(); virtual int SetBufferSize(jack_nframes_t buffer_size); @@ -208,6 +212,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface virtual JackClientControl* GetClientControl() const; virtual bool IsRealTime() const; + virtual bool IsRunning() const { return fIsRunning; } virtual bool Initialize(); // To be called by the wrapping thread Init method when the driver is a "blocking" one }; diff --git a/common/JackDriverLoader.cpp b/common/JackDriverLoader.cpp index 80ea3318..2d270656 100644 --- a/common/JackDriverLoader.cpp +++ b/common/JackDriverLoader.cpp @@ -119,7 +119,7 @@ jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSL desc->name); } - printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name); + jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name); jack_print_driver_options (desc, stdout); return 1; } @@ -263,7 +263,7 @@ jackctl_parse_driver_params (jackctl_driver *driver_ptr, int argc, char* argv[]) desc->name); } - printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name); + jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name); jack_print_driver_options (desc, stdout); return 1; } @@ -446,7 +446,7 @@ jack_get_descriptor (JSList * drivers, const char * sofile, const char * symbol) free(filename); return NULL; } - + if ((descriptor = so_get_descriptor ()) == NULL) { jack_error("driver from '%s' returned NULL descriptor", filename); UnloadDriverModule(dlhandle); @@ -467,7 +467,7 @@ jack_get_descriptor (JSList * drivers, const char * sofile, const char * symbol) /* check it doesn't exist already */ for (node = drivers; node; node = jack_slist_next (node)) { other_descriptor = (jack_driver_desc_t *) node->data; - + if (strcmp(descriptor->name, other_descriptor->name) == 0) { jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first", other_descriptor->file, filename, other_descriptor->name); @@ -603,7 +603,7 @@ jack_drivers_load (JSList * drivers) { } while ((dir_entry = readdir(dir_stream))) { - + /* check the filename is of the right format */ if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { continue; @@ -619,7 +619,7 @@ jack_drivers_load (JSList * drivers) { } desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor"); - + if (desc) { driver_list = jack_slist_append (driver_list, desc); } else { @@ -771,9 +771,9 @@ jack_internals_load (JSList * internals) { #endif -Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc, - Jack::JackLockedEngine* engine, - Jack::JackSynchro* synchro, +Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc, + Jack::JackLockedEngine* engine, + Jack::JackSynchro* synchro, const JSList* params) { #ifdef WIN32 @@ -783,7 +783,7 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver #endif fHandle = LoadDriverModule (driver_desc->file); - + if (fHandle == NULL) { #ifdef WIN32 if ((errstr = GetLastError ()) != 0) { @@ -809,8 +809,14 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver jack_error("no initialize function in shared object %s\n", driver_desc->file); return NULL; } - + fBackend = fInitialize(engine, synchro, params); return fBackend; } +JackDriverInfo::~JackDriverInfo() +{ + delete fBackend; + if (fHandle) + UnloadDriverModule(fHandle); +} diff --git a/common/JackDriverLoader.h b/common/JackDriverLoader.h index 17777e54..c194304d 100644 --- a/common/JackDriverLoader.h +++ b/common/JackDriverLoader.h @@ -24,14 +24,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "driver_interface.h" #include "JackControlAPI.h" #include "JackPlatformPlug.h" +#include "JackDriver.h" #include "JackSystemDeps.h" -namespace Jack -{ - class JackDriverClientInterface; - class JackLockedEngine; -}; - typedef jack_driver_desc_t * (*JackDriverDescFunction) (); typedef Jack::JackDriverClientInterface* (*driverInitialize) (Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); @@ -39,34 +34,30 @@ class JackDriverInfo { private: - + driverInitialize fInitialize; DRIVER_HANDLE fHandle; Jack::JackDriverClientInterface* fBackend; - + public: - - JackDriverInfo():fInitialize(NULL),fHandle(NULL) + + JackDriverInfo():fInitialize(NULL),fHandle(NULL),fBackend(NULL) {} - ~JackDriverInfo() - { - if (fHandle) - UnloadDriverModule(fHandle); - } - + ~JackDriverInfo(); + Jack::JackDriverClientInterface* Open(jack_driver_desc_t* driver_desc, Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); - + Jack::JackDriverClientInterface* GetBackend() { return fBackend; } - + }; -jack_driver_desc_t * jack_find_driver_descriptor (JSList * drivers, const char * name); +jack_driver_desc_t * jack_find_driver_descriptor(JSList * drivers, const char * name); -JSList * jack_drivers_load (JSList * drivers); -JSList * jack_internals_load (JSList * internals); +JSList * jack_drivers_load(JSList * drivers); +JSList * jack_internals_load(JSList * internals); EXPORT int jackctl_parse_driver_params (jackctl_driver * driver_ptr, int argc, char* argv[]); EXPORT void jack_free_driver_params(JSList * param_ptr); diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp index 338e5a42..2c7db9e3 100644 --- a/common/JackEngine.cpp +++ b/common/JackEngine.cpp @@ -223,7 +223,6 @@ int JackEngine::ComputeTotalLatencies() */ for (it = sorted.begin(); it != sorted.end(); it++) { - jack_log("Sorted %d", *it); NotifyClient(*it, kLatencyCallback, true, "", 0, 0); } @@ -322,8 +321,8 @@ void JackEngine::NotifyXRun(int refnum) void JackEngine::NotifyGraphReorder() { - ComputeTotalLatencies(); NotifyClients(kGraphOrderCallback, false, "", 0, 0); + ComputeTotalLatencies(); } void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size) @@ -520,7 +519,7 @@ void JackEngine::EnsureUUID(int uuid) for (int i = 0; i < CLIENT_NUM; i++) { JackClientInterface* client = fClientTable[i]; - if (client && (client->GetClientControl()->fSessionID==uuid)) { + if (client && (client->GetClientControl()->fSessionID == uuid)) { client->GetClientControl()->fSessionID = GetNewUUID(); } } @@ -551,13 +550,13 @@ int JackEngine::GetClientRefNum(const char* name) // Used for external clients int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager) { - char real_name[JACK_CLIENT_NAME_SIZE+1]; + char real_name[JACK_CLIENT_NAME_SIZE + 1]; if (uuid < 0) { uuid = GetNewUUID(); strncpy(real_name, name, JACK_CLIENT_NAME_SIZE); } else { - std::map::iterator res = fReservationMap.find(uuid); + std::map::iterator res = fReservationMap.find(uuid); if (res != fReservationMap.end()) { strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE); fReservationMap.erase(uuid); @@ -568,7 +567,7 @@ int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref EnsureUUID(uuid); } - jack_log("JackEngine::ClientExternalOpen: uuid=%d, name = %s ", uuid, real_name); + jack_log("JackEngine::ClientExternalOpen: uuid = %d, name = %s ", uuid, real_name); int refnum = AllocateRefnum(); if (refnum < 0) { @@ -762,7 +761,7 @@ int JackEngine::ClientDeactivate(int refnum) fGraphManager->GetInputPorts(refnum, input_ports); fGraphManager->GetOutputPorts(refnum, output_ports); - // First disconnect all ports and remove their JackPortIsActive state + // First disconnect all ports for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { PortDisconnect(refnum, input_ports[i], ALL_PORTS); } @@ -959,7 +958,7 @@ void JackEngine::SessionNotify(int refnum, const char *target, jack_session_even if (client && client->GetClientControl()->fCallback[kSessionCallback]) { // check if this is a notification to a specific client. - if (target!=NULL && strlen(target)!=0) { + if (target != NULL && strlen(target) != 0) { if (strcmp(target, client->GetClientControl()->fName)) { continue; } @@ -1019,7 +1018,7 @@ void JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res, i for (int i = 0; i < CLIENT_NUM; i++) { JackClientInterface* client = fClientTable[i]; - if (client && (strcmp(client_name, client->GetClientControl()->fName)==0)) { + if (client && (strcmp(client_name, client->GetClientControl()->fName) == 0)) { snprintf(uuid_res, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID); *result = 0; return; diff --git a/common/JackGraphManager.cpp b/common/JackGraphManager.cpp index 451d8cce..1366316a 100644 --- a/common/JackGraphManager.cpp +++ b/common/JackGraphManager.cpp @@ -77,7 +77,7 @@ JackPort* JackGraphManager::GetPort(jack_port_id_t port_index) return &fPortArray[port_index]; } -float* JackGraphManager::GetBuffer(jack_port_id_t port_index) +jack_default_audio_sample_t* JackGraphManager::GetBuffer(jack_port_id_t port_index) { return fPortArray[port_index].GetBuffer(); } diff --git a/common/JackGraphManager.h b/common/JackGraphManager.h index 5db84209..df6237e5 100644 --- a/common/JackGraphManager.h +++ b/common/JackGraphManager.h @@ -49,7 +49,7 @@ class SERVER_EXPORT JackGraphManager : public JackShmMem, public JackAtomicState jack_port_id_t AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags); void GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index); void GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags); - float* GetBuffer(jack_port_id_t port_index); + jack_default_audio_sample_t* GetBuffer(jack_port_id_t port_index); void* GetBufferAux(JackConnectionManager* manager, jack_port_id_t port_index, jack_nframes_t frames); jack_nframes_t ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count); void RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode); diff --git a/common/JackInternalClient.cpp b/common/JackInternalClient.cpp index 0f0e3e2a..550db2ef 100644 --- a/common/JackInternalClient.cpp +++ b/common/JackInternalClient.cpp @@ -123,7 +123,7 @@ int JackLoadableInternalClient::Init(const char* so_name) { char path_to_so[JACK_PATH_MAX + 1]; BuildClientPath(path_to_so, sizeof(path_to_so), so_name); - + fHandle = LoadJackModule(path_to_so); jack_log("JackLoadableInternalClient::JackLoadableInternalClient path_to_so = %s", path_to_so); @@ -151,7 +151,7 @@ int JackLoadableInternalClient1::Init(const char* so_name) if (JackLoadableInternalClient::Init(so_name) < 0) { return -1; } - + fInitialize = (InitializeCallback)GetJackProc(fHandle, "jack_initialize"); if (fInitialize == NULL) { UnloadJackModule(fHandle); @@ -167,7 +167,7 @@ int JackLoadableInternalClient2::Init(const char* so_name) if (JackLoadableInternalClient::Init(so_name) < 0) { return -1; } - + fInitialize = (InternalInitializeCallback)GetJackProc(fHandle, "jack_internal_initialize"); if (fInitialize == NULL) { UnloadJackModule(fHandle); @@ -181,7 +181,7 @@ int JackLoadableInternalClient2::Init(const char* so_name) JackLoadableInternalClient1::JackLoadableInternalClient1(JackServer* server, JackSynchro* table, const char* object_data) : JackLoadableInternalClient(server, table) { - strncpy(fObjectData, object_data, JACK_LOAD_INIT_LIMIT); + strncpy(fObjectData, object_data, JACK_LOAD_INIT_LIMIT); } JackLoadableInternalClient2::JackLoadableInternalClient2(JackServer* server, JackSynchro* table, const JSList* parameters) @@ -201,7 +201,7 @@ JackLoadableInternalClient::~JackLoadableInternalClient() int JackLoadableInternalClient1::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status) { int res = -1; - + if (JackInternalClient::Open(server_name, name, uuid, options, status) == 0) { if (fInitialize((jack_client_t*)this, fObjectData) == 0) { res = 0; @@ -210,14 +210,14 @@ int JackLoadableInternalClient1::Open(const char* server_name, const char* name, fFinish = NULL; } } - + return res; } int JackLoadableInternalClient2::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status) { int res = -1; - + if (JackInternalClient::Open(server_name, name, uuid, options, status) == 0) { if (fInitialize((jack_client_t*)this, fParameters) == 0) { res = 0; @@ -226,7 +226,7 @@ int JackLoadableInternalClient2::Open(const char* server_name, const char* name, fFinish = NULL; } } - + return res; } diff --git a/common/JackInternalClientChannel.h b/common/JackInternalClientChannel.h index 6b0772ce..dc81ac8c 100644 --- a/common/JackInternalClientChannel.h +++ b/common/JackInternalClientChannel.h @@ -136,7 +136,7 @@ class JackInternalClientChannel : public detail::JackClientChannelInterface void InternalClientLoad(int refnum, const char* client_name, const char* so_name, const char* objet_data, int options, int* status, int* int_ref, int uuid, int* result) { - *result = fServer->InternalClientLoad(client_name, so_name, objet_data, options, int_ref, uuid, status); + *result = fServer->InternalClientLoad1(client_name, so_name, objet_data, options, int_ref, uuid, status); } void InternalClientUnload(int refnum, int int_ref, int* status, int* result) diff --git a/common/JackLibClient.h b/common/JackLibClient.h index f2820601..ef07581c 100644 --- a/common/JackLibClient.h +++ b/common/JackLibClient.h @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -32,7 +32,7 @@ namespace Jack \brief Client on the library side. */ -class JackLibClient : public JackClient +class SERVER_EXPORT JackLibClient : public JackClient { private: diff --git a/common/JackLibGlobals.h b/common/JackLibGlobals.h index 5ef8b9e9..8d312295 100644 --- a/common/JackLibGlobals.h +++ b/common/JackLibGlobals.h @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackError.h" #include #include - + namespace Jack { @@ -42,13 +42,13 @@ class JackClient; \brief Global library static structure: singleton kind of pattern. */ -struct JackLibGlobals +struct SERVER_EXPORT JackLibGlobals { JackShmReadWritePtr fGraphManager; /*! Shared memory Port manager */ JackShmReadWritePtr fEngineControl; /*! Shared engine control */ // transport engine has to be writable JackSynchro fSynchroTable[CLIENT_NUM]; /*! Shared synchro table */ sigset_t fProcessSignals; - + static int fClientCount; static JackLibGlobals* fGlobals; @@ -67,7 +67,7 @@ struct JackLibGlobals sigemptyset(&signals); sigaddset(&signals, SIGPIPE); sigprocmask(SIG_BLOCK, &signals, &fProcessSignals); - #endif + #endif } ~JackLibGlobals() @@ -83,13 +83,13 @@ struct JackLibGlobals // TODO #else sigprocmask(SIG_BLOCK, &fProcessSignals, 0); - #endif + #endif } static void Init() { if (!JackGlobals::fServerRunning && fClientCount > 0) { - + // Cleanup remaining clients jack_error("Jack server was closed but clients are still allocated, cleanup..."); for (int i = 0; i < CLIENT_NUM; i++) { @@ -101,13 +101,13 @@ struct JackLibGlobals JackGlobals::fClientTable[CLIENT_NUM] = NULL; } } - + // Cleanup global context fClientCount = 0; delete fGlobals; fGlobals = NULL; } - + if (fClientCount++ == 0 && !fGlobals) { jack_log("JackLibGlobals Init %x", fGlobals); InitTime(); diff --git a/common/JackLibSampleRateResampler.cpp b/common/JackLibSampleRateResampler.cpp index 7475282a..ea70438d 100644 --- a/common/JackLibSampleRateResampler.cpp +++ b/common/JackLibSampleRateResampler.cpp @@ -27,7 +27,7 @@ JackLibSampleRateResampler::JackLibSampleRateResampler() { int error; fResampler = src_new(SRC_LINEAR, 1, &error); - if (error != 0) + if (error != 0) jack_error("JackLibSampleRateResampler::JackLibSampleRateResampler err = %s", src_strerror(error)); } @@ -50,7 +50,7 @@ JackLibSampleRateResampler::JackLibSampleRateResampler(unsigned int quality) case 4: quality = SRC_SINC_BEST_QUALITY; break; - default: + default: quality = SRC_LINEAR; jack_error("Out of range resample quality"); break; @@ -58,7 +58,7 @@ JackLibSampleRateResampler::JackLibSampleRateResampler(unsigned int quality) int error; fResampler = src_new(quality, 1, &error); - if (error != 0) + if (error != 0) jack_error("JackLibSampleRateResampler::JackLibSampleRateResampler err = %s", src_strerror(error)); } @@ -73,103 +73,103 @@ void JackLibSampleRateResampler::Reset(unsigned int new_size) src_reset(fResampler); } -unsigned int JackLibSampleRateResampler::ReadResample(float* buffer, unsigned int frames) +unsigned int JackLibSampleRateResampler::ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames) { jack_ringbuffer_data_t ring_buffer_data[2]; SRC_DATA src_data; unsigned int frames_to_write = frames; unsigned int written_frames = 0; int res; - + jack_ringbuffer_get_read_vector(fRingBuffer, ring_buffer_data); - unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); + unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(jack_default_audio_sample_t); jack_log("Output available = %ld", available_frames); - + for (int j = 0; j < 2; j++) { - + if (ring_buffer_data[j].len > 0) { - - src_data.data_in = (float*)ring_buffer_data[j].buf; + + src_data.data_in = (jack_default_audio_sample_t*)ring_buffer_data[j].buf; src_data.data_out = &buffer[written_frames]; - src_data.input_frames = ring_buffer_data[j].len / sizeof(float); + src_data.input_frames = ring_buffer_data[j].len / sizeof(jack_default_audio_sample_t); src_data.output_frames = frames_to_write; src_data.end_of_input = 0; src_data.src_ratio = fRatio; - + res = src_process(fResampler, &src_data); if (res != 0) { jack_error("JackLibSampleRateResampler::ReadResample ratio = %f err = %s", fRatio, src_strerror(res)); return 0; } - + frames_to_write -= src_data.output_frames_gen; written_frames += src_data.output_frames_gen; - + if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { jack_log("Output : j = %d input_frames_used = %ld output_frames_gen = %ld frames1 = %lu frames2 = %lu" , j, src_data.input_frames_used, src_data.output_frames_gen, ring_buffer_data[0].len, ring_buffer_data[1].len); } - + jack_log("Output : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - jack_ringbuffer_read_advance(fRingBuffer, src_data.input_frames_used * sizeof(float)); + jack_ringbuffer_read_advance(fRingBuffer, src_data.input_frames_used * sizeof(jack_default_audio_sample_t)); } } - + if (written_frames < frames) { jack_error("Output available = %ld", available_frames); jack_error("JackLibSampleRateResampler::ReadResample error written_frames = %ld", written_frames); } - + return written_frames; } -unsigned int JackLibSampleRateResampler::WriteResample(float* buffer, unsigned int frames) +unsigned int JackLibSampleRateResampler::WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames) { jack_ringbuffer_data_t ring_buffer_data[2]; SRC_DATA src_data; unsigned int frames_to_read = frames; unsigned int read_frames = 0; int res; - + jack_ringbuffer_get_write_vector(fRingBuffer, ring_buffer_data); - unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float); + unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(jack_default_audio_sample_t); jack_log("Input available = %ld", available_frames); - + for (int j = 0; j < 2; j++) { - + if (ring_buffer_data[j].len > 0) { - + src_data.data_in = &buffer[read_frames]; - src_data.data_out = (float*)ring_buffer_data[j].buf; + src_data.data_out = (jack_default_audio_sample_t*)ring_buffer_data[j].buf; src_data.input_frames = frames_to_read; - src_data.output_frames = (ring_buffer_data[j].len / sizeof(float)); + src_data.output_frames = (ring_buffer_data[j].len / sizeof(jack_default_audio_sample_t)); src_data.end_of_input = 0; src_data.src_ratio = fRatio; - + res = src_process(fResampler, &src_data); if (res != 0) { jack_error("JackLibSampleRateResampler::ReadResample ratio = %f err = %s", fRatio, src_strerror(res)); return 0; } - + frames_to_read -= src_data.input_frames_used; read_frames += src_data.input_frames_used; - + if ((src_data.input_frames_used == 0 || src_data.output_frames_gen == 0) && j == 0) { jack_log("Input : j = %d input_frames_used = %ld output_frames_gen = %ld frames1 = %lu frames2 = %lu" , j, src_data.input_frames_used, src_data.output_frames_gen, ring_buffer_data[0].len, ring_buffer_data[1].len); } - + jack_log("Input : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen); - jack_ringbuffer_write_advance(fRingBuffer, src_data.output_frames_gen * sizeof(float)); + jack_ringbuffer_write_advance(fRingBuffer, src_data.output_frames_gen * sizeof(jack_default_audio_sample_t)); } } - + if (read_frames < frames) { jack_error("Input available = %ld", available_frames); jack_error("JackLibSampleRateResampler::ReadResample error read_frames = %ld", read_frames); } - + return read_frames; } diff --git a/common/JackLibSampleRateResampler.h b/common/JackLibSampleRateResampler.h index e51a7442..4d6821d8 100644 --- a/common/JackLibSampleRateResampler.h +++ b/common/JackLibSampleRateResampler.h @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define __JackLibSampleRateResampler__ #include "JackResampler.h" +#include "types.h" + #include namespace Jack @@ -34,20 +36,20 @@ class JackLibSampleRateResampler : public JackResampler { private: - + SRC_STATE* fResampler; - + public: - + JackLibSampleRateResampler(); JackLibSampleRateResampler(unsigned int quality); virtual ~JackLibSampleRateResampler(); - - unsigned int ReadResample(float* buffer, unsigned int frames); - unsigned int WriteResample(float* buffer, unsigned int frames); - + + unsigned int ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames); + unsigned int WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames); + void Reset(unsigned int new_size); - + }; } diff --git a/common/JackLoopbackDriver.cpp b/common/JackLoopbackDriver.cpp index 48a9d253..e91cce1e 100644 --- a/common/JackLoopbackDriver.cpp +++ b/common/JackLoopbackDriver.cpp @@ -34,7 +34,7 @@ int JackLoopbackDriver::Process() { // Loopback copy for (int i = 0; i < fCaptureChannels; i++) { - memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(float) * fEngineControl->fBufferSize); + memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); } fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); // Signal all clients @@ -54,7 +54,7 @@ extern "C" { #endif - SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() + SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() { jack_driver_desc_t * desc; unsigned int i; @@ -65,7 +65,7 @@ extern "C" desc->nparams = 1; desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); - + i = 0; strcpy(desc->params[i].name, "channels"); desc->params[i].character = 'c'; @@ -77,12 +77,12 @@ extern "C" return desc; } - SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { const JSList * node; const jack_driver_param_t * param; int channels = 2; - + for (node = params; node; node = jack_slist_next (node)) { param = (const jack_driver_param_t *) node->data; @@ -93,7 +93,7 @@ extern "C" break; } } - + Jack::JackDriverClientInterface* driver = new Jack::JackLoopbackDriver(engine, table); if (driver->Open(1, 1, channels, channels, false, "loopback", "loopback", 0, 0) == 0) { return driver; diff --git a/common/JackMidiDriver.cpp b/common/JackMidiDriver.cpp index 4ddf417c..15d507b1 100644 --- a/common/JackMidiDriver.cpp +++ b/common/JackMidiDriver.cpp @@ -60,11 +60,11 @@ int JackMidiDriver::Open(bool capturing, { fCaptureChannels = inchannels; fPlaybackChannels = outchannels; - + for (int i = 0; i < fCaptureChannels; i++) { - fRingBuffer[i] = jack_ringbuffer_create(sizeof(float) * BUFFER_SIZE_MAX); + fRingBuffer[i] = jack_ringbuffer_create(sizeof(jack_default_audio_sample_t) * BUFFER_SIZE_MAX); } - + return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); } @@ -141,11 +141,11 @@ int JackMidiDriver::ProcessNull() int JackMidiDriver::Process() { // Read input buffers for the current cycle - if (Read() < 0) { + if (Read() < 0) { jack_error("JackMidiDriver::Process: read error, skip cycle"); return 0; // Skip cycle, but continue processing... } - + fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); if (fEngineControl->fSyncMode) { if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0) { @@ -153,13 +153,13 @@ int JackMidiDriver::Process() return -1; } } - + // Write output buffers for the current cycle - if (Write() < 0) { + if (Write() < 0) { jack_error("JackMidiDriver::Process: write error, skip cycle"); return 0; // Skip cycle, but continue processing... } - + return 0; } diff --git a/common/JackMidiPort.cpp b/common/JackMidiPort.cpp index 117b7a70..42ee245c 100644 --- a/common/JackMidiPort.cpp +++ b/common/JackMidiPort.cpp @@ -72,7 +72,7 @@ static void MidiBufferInit(void* buffer, size_t buffer_size, jack_nframes_t nfra JackMidiBuffer* midi = (JackMidiBuffer*)buffer; midi->magic = JackMidiBuffer::MAGIC; /* Since port buffer has actually always BUFFER_SIZE_MAX frames, we can safely use all the size */ - midi->buffer_size = BUFFER_SIZE_MAX * sizeof(float); + midi->buffer_size = BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t); midi->Reset(nframes); } @@ -135,7 +135,7 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count static size_t MidiBufferSize() { - return BUFFER_SIZE_MAX * sizeof(float); + return BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t); } const JackPortType gMidiPortType = diff --git a/common/JackMidiPort.h b/common/JackMidiPort.h index 0dbfcb9a..3c24542b 100644 --- a/common/JackMidiPort.h +++ b/common/JackMidiPort.h @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -71,7 +71,7 @@ struct SERVER_EXPORT JackMidiEvent * but their data (if not inlined) is stored from the end of the same buffer. */ -struct JackMidiBuffer +struct SERVER_EXPORT JackMidiBuffer { enum { MAGIC = 0x900df00d }; diff --git a/common/JackNetOneDriver.cpp b/common/JackNetOneDriver.cpp index 5b1b8cdd..93adecdd 100644 --- a/common/JackNetOneDriver.cpp +++ b/common/JackNetOneDriver.cpp @@ -36,7 +36,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #endif #if HAVE_CELT -#include "celt/celt.h" +#include #endif #define MIN(x,y) ((x)<(y) ? (x) : (y)) @@ -153,12 +153,15 @@ namespace Jack } //port = fGraphManager->GetPort ( port_id ); - netj.capture_ports = - jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); + netj.capture_ports = jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); if( netj.bitdepth == CELT_MODE ) { #if HAVE_CELT - #if HAVE_CELT_API_0_7 + #if HAVE_CELT_API_0_11 + celt_int32 lookahead; + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) ); + #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 celt_int32 lookahead; CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); @@ -202,12 +205,13 @@ namespace Jack } //port = fGraphManager->GetPort ( port_id ); - netj.playback_ports = - jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); - + netj.playback_ports = jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); if( netj.bitdepth == CELT_MODE ) { #if HAVE_CELT - #if HAVE_CELT_API_0_7 + #if HAVE_CELT_API_0_11 + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create_custom( celt_mode, 1, NULL ) ); + #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); #else @@ -697,10 +701,18 @@ namespace Jack { // audio port, decode celt data. CELTDecoder *decoder = (CELTDecoder *)src_node->data; + + #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 + if( !packet_payload ) + celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); + else + celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); + #else if( !packet_payload ) - celt_decode_float( decoder, NULL, net_period_down, buf ); + celt_decode_float( decoder, NULL, net_period_down, buf ); else - celt_decode_float( decoder, packet_bufX, net_period_down, buf ); + celt_decode_float( decoder, packet_bufX, net_period_down, buf ); + #endif src_node = jack_slist_next (src_node); } @@ -743,11 +755,15 @@ namespace Jack // audio port, encode celt data. int encoded_bytes; - float *floatbuf = (float *)alloca (sizeof(float) * nframes ); - memcpy( floatbuf, buf, nframes*sizeof(float) ); + jack_default_audio_sample_t *floatbuf = (jack_default_audio_sample_t *)alloca (sizeof(jack_default_audio_sample_t) * nframes ); + memcpy( floatbuf, buf, nframes * sizeof(jack_default_audio_sample_t) ); CELTEncoder *encoder = (CELTEncoder *)src_node->data; + #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 + encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up ); +#else encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); - if( encoded_bytes != (int)net_period_up ) +#endif + if( encoded_bytes != (int)net_period_up ) jack_error( "something in celt changed. netjack needs to be changed to handle this." ); src_node = jack_slist_next( src_node ); } diff --git a/common/JackPort.cpp b/common/JackPort.cpp index e3dd12f6..870d6ee8 100644 --- a/common/JackPort.cpp +++ b/common/JackPort.cpp @@ -286,7 +286,7 @@ int JackPort::UnsetAlias(const char* alias) void JackPort::ClearBuffer(jack_nframes_t frames) { const JackPortType* type = GetPortType(fTypeId); - (type->init)(GetBuffer(), frames * sizeof(float), frames); + (type->init)(GetBuffer(), frames * sizeof(jack_default_audio_sample_t), frames); } void JackPort::MixBuffers(void** src_buffers, int src_count, jack_nframes_t buffer_size) diff --git a/common/JackPort.h b/common/JackPort.h index 758e402b..8e8c1667 100644 --- a/common/JackPort.h +++ b/common/JackPort.h @@ -57,7 +57,7 @@ class SERVER_EXPORT JackPort bool fInUse; jack_port_id_t fTied; // Locally tied source port - float fBuffer[BUFFER_SIZE_MAX + 4]; + jack_default_audio_sample_t fBuffer[BUFFER_SIZE_MAX + 4]; bool IsUsed() const { @@ -105,9 +105,9 @@ class SERVER_EXPORT JackPort } // Since we are in shared memory, the resulting pointer cannot be cached, so align it here... - float* GetBuffer() + jack_default_audio_sample_t* GetBuffer() { - return (float*)((long)fBuffer & ~15L) + 4; + return (jack_default_audio_sample_t*)((long)fBuffer & ~15L) + 4; } int GetRefNum() const; diff --git a/common/JackResampler.cpp b/common/JackResampler.cpp index b9a26f44..e2d32520 100644 --- a/common/JackResampler.cpp +++ b/common/JackResampler.cpp @@ -26,8 +26,8 @@ namespace Jack JackResampler::JackResampler() :fRatio(1),fRingBufferSize(DEFAULT_RB_SIZE) { - fRingBuffer = jack_ringbuffer_create(sizeof(float) * fRingBufferSize); - jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize) / 2); + fRingBuffer = jack_ringbuffer_create(sizeof(jack_default_audio_sample_t) * fRingBufferSize); + jack_ringbuffer_read_advance(fRingBuffer, (sizeof(jack_default_audio_sample_t) * fRingBufferSize) / 2); } JackResampler::~JackResampler() @@ -40,44 +40,44 @@ void JackResampler::Reset(unsigned int new_size) { fRingBufferSize = new_size; jack_ringbuffer_reset(fRingBuffer); - jack_ringbuffer_reset_size(fRingBuffer, sizeof(float) * fRingBufferSize); - jack_ringbuffer_read_advance(fRingBuffer, (sizeof(float) * fRingBufferSize / 2)); + jack_ringbuffer_reset_size(fRingBuffer, sizeof(jack_default_audio_sample_t) * fRingBufferSize); + jack_ringbuffer_read_advance(fRingBuffer, (sizeof(jack_default_audio_sample_t) * fRingBufferSize / 2)); } unsigned int JackResampler::ReadSpace() { - return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(float)); + return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(jack_default_audio_sample_t)); } unsigned int JackResampler::WriteSpace() { - return (jack_ringbuffer_write_space(fRingBuffer) / sizeof(float)); + return (jack_ringbuffer_write_space(fRingBuffer) / sizeof(jack_default_audio_sample_t)); } -unsigned int JackResampler::Read(float* buffer, unsigned int frames) +unsigned int JackResampler::Read(jack_default_audio_sample_t* buffer, unsigned int frames) { size_t len = jack_ringbuffer_read_space(fRingBuffer); - jack_log("JackResampler::Read input available = %ld", len / sizeof(float)); - - if (len < frames * sizeof(float)) { + jack_log("JackResampler::Read input available = %ld", len / sizeof(jack_default_audio_sample_t)); + + if (len < frames * sizeof(jack_default_audio_sample_t)) { jack_error("JackResampler::Read : producer too slow, missing frames = %d", frames); return 0; } else { - jack_ringbuffer_read(fRingBuffer, (char*)buffer, frames * sizeof(float)); + jack_ringbuffer_read(fRingBuffer, (char*)buffer, frames * sizeof(jack_default_audio_sample_t)); return frames; } } -unsigned int JackResampler::Write(float* buffer, unsigned int frames) +unsigned int JackResampler::Write(jack_default_audio_sample_t* buffer, unsigned int frames) { size_t len = jack_ringbuffer_write_space(fRingBuffer); - jack_log("JackResampler::Write output available = %ld", len / sizeof(float)); - - if (len < frames * sizeof(float)) { + jack_log("JackResampler::Write output available = %ld", len / sizeof(jack_default_audio_sample_t)); + + if (len < frames * sizeof(jack_default_audio_sample_t)) { jack_error("JackResampler::Write : consumer too slow, skip frames = %d", frames); return 0; } else { - jack_ringbuffer_write(fRingBuffer, (char*)buffer, frames * sizeof(float)); + jack_ringbuffer_write(fRingBuffer, (char*)buffer, frames * sizeof(jack_default_audio_sample_t)); return frames; } } @@ -110,12 +110,12 @@ unsigned int JackResampler::Write(void* buffer, unsigned int bytes) } } -unsigned int JackResampler::ReadResample(float* buffer, unsigned int frames) +unsigned int JackResampler::ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames) { return Read(buffer, frames); } -unsigned int JackResampler::WriteResample(float* buffer, unsigned int frames) +unsigned int JackResampler::WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames) { return Write(buffer, frames); } diff --git a/common/JackResampler.h b/common/JackResampler.h index bfb93f04..3b9877a5 100644 --- a/common/JackResampler.h +++ b/common/JackResampler.h @@ -21,19 +21,20 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define __JackResampler__ #include "ringbuffer.h" +#include "types.h" #include "JackError.h" namespace Jack { #define DEFAULT_RB_SIZE 32768 -#define DEFAULT_ADAPTATIVE_SIZE 2048 +#define DEFAULT_ADAPTATIVE_SIZE 2048 inline float Range(float min, float max, float val) { return (val < min) ? min : ((val > max) ? max : val); } - + /*! \brief Base class for Resampler. */ @@ -42,30 +43,30 @@ class JackResampler { protected: - + jack_ringbuffer_t* fRingBuffer; double fRatio; unsigned int fRingBufferSize; - + public: - + JackResampler(); virtual ~JackResampler(); - + virtual void Reset(unsigned int new_size); - - virtual unsigned int ReadResample(float* buffer, unsigned int frames); - virtual unsigned int WriteResample(float* buffer, unsigned int frames); - - virtual unsigned int Read(float* buffer, unsigned int frames); - virtual unsigned int Write(float* buffer, unsigned int frames); - + + virtual unsigned int ReadResample(jack_default_audio_sample_t* buffer, unsigned int frames); + virtual unsigned int WriteResample(jack_default_audio_sample_t* buffer, unsigned int frames); + + virtual unsigned int Read(jack_default_audio_sample_t* buffer, unsigned int frames); + virtual unsigned int Write(jack_default_audio_sample_t* buffer, unsigned int frames); + virtual unsigned int Read(void* buffer, unsigned int bytes); virtual unsigned int Write(void* buffer, unsigned int bytes); virtual unsigned int ReadSpace(); virtual unsigned int WriteSpace(); - + unsigned int GetError() { return (jack_ringbuffer_read_space(fRingBuffer) / sizeof(float)) - (fRingBufferSize / 2); @@ -75,12 +76,12 @@ class JackResampler { fRatio = Range(0.25, 4.0, ratio); } - + double GetRatio() { return fRatio; } - + }; } diff --git a/common/JackServer.cpp b/common/JackServer.cpp index 50894529..cd1915fb 100644 --- a/common/JackServer.cpp +++ b/common/JackServer.cpp @@ -49,7 +49,16 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio fGraphManager = JackGraphManager::Allocate(port_max); fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); - fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable())); + + // A distinction is made between the threaded freewheel driver and the + // regular freewheel driver because the freewheel driver needs to run in + // threaded mode when freewheel mode is active and needs to run as a slave + // when freewheel mode isn't active. + JackFreewheelDriver *freewheelDriver = + new JackFreewheelDriver(fEngine, GetSynchroTable()); + fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver); + + fFreewheelDriver = freewheelDriver; fDriverInfo = new JackDriverInfo(); fAudioDriver = NULL; fFreewheel = false; @@ -61,9 +70,8 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio JackServer::~JackServer() { JackGraphManager::Destroy(fGraphManager); - delete fAudioDriver; delete fDriverInfo; - delete fFreewheelDriver; + delete fThreadedFreewheelDriver; delete fEngine; delete fEngineControl; } @@ -88,8 +96,8 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) goto fail_close3; } - if (fFreewheelDriver->Open() < 0) { // before engine open - jack_error("Cannot open driver"); + if (fFreewheelDriver->Open() < 0) { + jack_error("Cannot open freewheel driver"); goto fail_close4; } @@ -100,7 +108,7 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) fFreewheelDriver->SetMaster(false); fAudioDriver->SetMaster(true); - fAudioDriver->AddSlave(fFreewheelDriver); // After ??? + fAudioDriver->AddSlave(fFreewheelDriver); InitTime(); SetClockSource(fEngineControl->fClockSource); return 0; @@ -136,14 +144,14 @@ int JackServer::Close() return 0; } -int JackServer::InternalClientLoad(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status) +int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status) { JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data); assert(client); return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status); } -int JackServer::InternalClientLoad(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status) +int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status) { JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters); assert(client); @@ -154,6 +162,8 @@ int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const { // Clear status *status = 0; + + // Client object is internally kept in JackEngine if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name, uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) { delete client; int my_status1 = *status | JackFailure; @@ -178,7 +188,18 @@ int JackServer::Start() int JackServer::Stop() { jack_log("JackServer::Stop"); - return fAudioDriver->Stop(); + if (fFreewheel) { + return fThreadedFreewheelDriver->Stop(); + } else { + return fAudioDriver->Stop(); + } +} + +bool JackServer::IsRunning() +{ + jack_log("JackServer::IsRunning"); + assert(fAudioDriver); + return fAudioDriver->IsRunning(); } int JackServer::SetBufferSize(jack_nframes_t buffer_size) @@ -236,10 +257,11 @@ int JackServer::SetFreewheel(bool onoff) return -1; } else { fFreewheel = false; - fFreewheelDriver->Stop(); + fThreadedFreewheelDriver->Stop(); fGraphManager->Restore(&fConnectionState); // Restore previous connection state fEngine->NotifyFreewheel(onoff); fFreewheelDriver->SetMaster(false); + fAudioDriver->SetMaster(true); return fAudioDriver->Start(); } } else { @@ -249,8 +271,9 @@ int JackServer::SetFreewheel(bool onoff) fGraphManager->Save(&fConnectionState); // Save connection state fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum); fEngine->NotifyFreewheel(onoff); + fAudioDriver->SetMaster(false); fFreewheelDriver->SetMaster(true); - return fFreewheelDriver->Start(); + return fThreadedFreewheelDriver->Start(); } else { return -1; } @@ -269,7 +292,6 @@ void JackServer::Notify(int refnum, int notify, int value) case kXRunCallback: fEngine->NotifyXRun(refnum); break; - } } @@ -295,11 +317,11 @@ JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* dr if (slave == NULL) { delete info; return NULL; - } else { - slave->Attach(); - fAudioDriver->AddSlave(slave); - return info; } + slave->Attach(); + slave->SetMaster(false); + fAudioDriver->AddSlave(slave); + return info; } void JackServer::RemoveSlave(JackDriverInfo* info) @@ -321,33 +343,30 @@ int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_par JackDriverInfo* info = new JackDriverInfo(); JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); - if (master == NULL || info == NULL) { + if (master == NULL) { delete info; - delete master; return -1; - } else { + } - // Get slaves list - std::list slave_list = fAudioDriver->GetSlaves(); - std::list::const_iterator it; + // Get slaves list + std::list slave_list = fAudioDriver->GetSlaves(); + std::list::const_iterator it; - // Move slaves in new master - for (it = slave_list.begin(); it != slave_list.end(); it++) { - JackDriverInterface* slave = *it; - master->AddSlave(slave); - } + // Move slaves in new master + for (it = slave_list.begin(); it != slave_list.end(); it++) { + JackDriverInterface* slave = *it; + master->AddSlave(slave); + } - // Delete old master - delete fAudioDriver; - delete fDriverInfo; + // Delete old master + delete fDriverInfo; - // Activate master - fAudioDriver = master; - fDriverInfo = info; - fAudioDriver->Attach(); - fAudioDriver->SetMaster(true); - return fAudioDriver->Start(); - } + // Activate master + fAudioDriver = master; + fDriverInfo = info; + fAudioDriver->Attach(); + fAudioDriver->SetMaster(true); + return fAudioDriver->Start(); } //---------------------- diff --git a/common/JackServer.h b/common/JackServer.h index 9b07d60f..bdbd8ea8 100644 --- a/common/JackServer.h +++ b/common/JackServer.h @@ -50,6 +50,7 @@ class SERVER_EXPORT JackServer JackDriverInfo* fDriverInfo; JackDriverClientInterface* fAudioDriver; JackDriverClientInterface* fFreewheelDriver; + JackDriverClientInterface* fThreadedFreewheelDriver; JackLockedEngine* fEngine; JackEngineControl* fEngineControl; JackGraphManager* fGraphManager; @@ -57,7 +58,7 @@ class SERVER_EXPORT JackServer JackConnectionManager fConnectionState; JackSynchro fSynchroTable[CLIENT_NUM]; bool fFreewheel; - + int InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status); public: @@ -70,6 +71,7 @@ class SERVER_EXPORT JackServer int Start(); int Stop(); + bool IsRunning(); // RT thread void Notify(int refnum, int notify, int value); @@ -77,19 +79,19 @@ class SERVER_EXPORT JackServer // Command thread : API int SetBufferSize(jack_nframes_t buffer_size); int SetFreewheel(bool onoff); - int InternalClientLoad(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status); - int InternalClientLoad(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status); + int InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status); + int InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status); void ClientKill(int refnum); // Transport management int ReleaseTimebase(int refnum); int SetTimebaseCallback(int refnum, int conditional); - + // Backend management JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); void RemoveSlave(JackDriverInfo* info); int SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params); - + // Object access JackLockedEngine* GetEngine(); JackEngineControl* GetEngineControl(); diff --git a/common/JackServerAPI.cpp b/common/JackServerAPI.cpp index 5561f154..49cc4a58 100644 --- a/common/JackServerAPI.cpp +++ b/common/JackServerAPI.cpp @@ -63,7 +63,7 @@ jack_client_t* jack_client_new_aux(const char* client_name, jack_options_t optio } jack_log("jack_client_new %s", client_name); - + if (status == NULL) /* no status from caller? */ status = &my_status; /* use local status word */ *status = (jack_status_t)0; @@ -77,13 +77,13 @@ jack_client_t* jack_client_new_aux(const char* client_name, jack_options_t optio /* parse variable arguments */ jack_varargs_init(&va); - + if (!JackServerGlobals::Init()) { // jack server initialisation int my_status1 = (JackFailure | JackServerError); *status = (jack_status_t)my_status1; return NULL; } - + if (JACK_DEBUG) { client = new JackDebugClient(new JackInternalClient(JackServerGlobals::fInstance, GetSynchroTable())); // Debug mode } else { @@ -114,7 +114,7 @@ jack_client_t* jack_client_open_aux(const char* client_name, jack_options_t opti } jack_log("jack_client_open %s", client_name); - + if (status == NULL) /* no status from caller? */ status = &my_status; /* use local status word */ *status = (jack_status_t)0; @@ -128,13 +128,13 @@ jack_client_t* jack_client_open_aux(const char* client_name, jack_options_t opti /* parse variable arguments */ jack_varargs_parse(options, ap, &va); - + if (!JackServerGlobals::Init()) { // jack server initialisation int my_status1 = (JackFailure | JackServerError); *status = (jack_status_t)my_status1; return NULL; } - + if (JACK_DEBUG) { client = new JackDebugClient(new JackInternalClient(JackServerGlobals::fInstance, GetSynchroTable())); // Debug mode } else { @@ -180,7 +180,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client) { #ifdef __CLIENTDEBUG__ JackGlobals::CheckContext("jack_client_close"); -#endif +#endif assert(JackGlobals::fOpenMutex); JackGlobals::fOpenMutex->Lock(); int res = -1; @@ -200,7 +200,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client) EXPORT int jack_get_client_pid(const char *name) { - return (JackServerGlobals::fInstance != NULL) + return (JackServerGlobals::fInstance != NULL) ? JackServerGlobals::fInstance->GetEngine()->GetClientPID(name) : 0; } diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp index 04489190..00127fa6 100644 --- a/common/JackServerGlobals.cpp +++ b/common/JackServerGlobals.cpp @@ -18,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "JackServerGlobals.h" +#include "JackLockedEngine.h" #include "JackTools.h" #include "shm.h" #include @@ -31,6 +32,8 @@ namespace Jack JackServer* JackServerGlobals::fInstance; unsigned int JackServerGlobals::fUserCount; int JackServerGlobals::fRTNotificationSocket; +std::map JackServerGlobals::fSlavesList; +std::map JackServerGlobals::fInternalsList; bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; @@ -63,6 +66,30 @@ void JackServerGlobals::Stop() void JackServerGlobals::Delete() { jack_log("Jackdmp: delete server"); + + // Slave drivers + std::map::iterator it1; + for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) { + JackDriverInfo* info = (*it1).second; + if (info) { + fInstance->RemoveSlave((info)); + delete (info); + } + } + fSlavesList.clear(); + + // Internal clients + std::map ::iterator it2; + for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) { + int status; + int refnum = (*it2).second; + if (refnum > 0) { + // Client object is internally kept in JackEngine, and will be desallocated in InternalClientUnload + fInstance->GetEngine()->InternalClientUnload(refnum, &status); + } + } + fInternalsList.clear(); + delete fInstance; fInstance = NULL; } @@ -80,49 +107,62 @@ bool JackServerGlobals::Init() int opt = 0; int option_index = 0; - int seen_driver = 0; - char *driver_name = NULL; - char **driver_args = NULL; - JSList* driver_params = NULL; + char *master_driver_name = NULL; + char **master_driver_args = NULL; + JSList* master_driver_params = NULL; + jack_driver_desc_t* driver_desc; + jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; int driver_nargs = 1; JSList* drivers = NULL; - int show_version = 0; + int loopback = 0; int sync = 0; int rc, i; int ret; + int replace_registry = 0; FILE* fp = 0; char filename[255]; char buffer[255]; int argc = 0; char* argv[32]; - jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; // First user starts the server if (fUserCount++ == 0) { jack_log("JackServerGlobals Init"); - jack_driver_desc_t* driver_desc; - const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:c:"; - static struct option long_options[] = { - { "clock-source", 1, 0, 'c' }, - { "driver", 1, 0, 'd' }, - { "verbose", 0, 0, 'v' }, - { "help", 0, 0, 'h' }, - { "port-max", 1, 0, 'p' }, - { "no-mlock", 0, 0, 'm' }, - { "name", 0, 0, 'n' }, - { "unlock", 0, 0, 'u' }, - { "realtime", 0, 0, 'R' }, - { "realtime-priority", 1, 0, 'P' }, - { "timeout", 1, 0, 't' }, - { "temporary", 0, 0, 'T' }, - { "version", 0, 0, 'V' }, - { "silent", 0, 0, 's' }, - { "sync", 0, 0, 'S' }, - { 0, 0, 0, 0 } - }; + const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" + #ifdef __linux__ + "c:" + #endif + ; + + struct option long_options[] = { + #ifdef __linux__ + { "clock-source", 1, 0, 'c' }, + #endif + { "loopback-driver", 1, 0, 'L' }, + { "audio-driver", 1, 0, 'd' }, + { "midi-driver", 1, 0, 'X' }, + { "internal-client", 1, 0, 'I' }, + { "verbose", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, + { "port-max", 1, 0, 'p' }, + { "no-mlock", 0, 0, 'm' }, + { "name", 1, 0, 'n' }, + { "unlock", 0, 0, 'u' }, + { "realtime", 0, 0, 'R' }, + { "no-realtime", 0, 0, 'r' }, + { "replace-registry", 0, &replace_registry, 0 }, + { "loopback", 0, 0, 'L' }, + { "realtime-priority", 1, 0, 'P' }, + { "timeout", 1, 0, 't' }, + { "temporary", 0, 0, 'T' }, + { "version", 0, 0, 'V' }, + { "silent", 0, 0, 's' }, + { "sync", 0, 0, 'S' }, + { 0, 0, 0, 0 } + }; snprintf(filename, 255, "%s/.jackdrc", getenv("HOME")); fp = fopen(filename, "r"); @@ -156,7 +196,7 @@ bool JackServerGlobals::Init() opterr = 0; optind = 1; // Important : to reset argv parsing - while (!seen_driver && + while (!master_driver_name && (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { @@ -174,34 +214,53 @@ bool JackServerGlobals::Init() break; case 'd': - seen_driver = 1; - driver_name = optarg; + master_driver_name = optarg; break; - case 'v': - verbose_aux = 1; + case 'L': + loopback = atoi(optarg); break; - case 'S': - sync = 1; + case 'X': + fSlavesList[optarg] = NULL; break; - case 'n': - server_name = optarg; + case 'I': + fInternalsList[optarg] = -1; + break; + + case 'p': + port_max = (unsigned int)atol(optarg); break; case 'm': do_mlock = 0; break; - case 'p': - port_max = (unsigned int)atol(optarg); + case 'u': + do_unlock = 1; + break; + + case 'v': + verbose_aux = 1; + break; + + case 'S': + sync = 1; + break; + + case 'n': + server_name = optarg; break; case 'P': realtime_priority = atoi(optarg); break; + case 'r': + realtime = 0; + break; + case 'R': realtime = 1; break; @@ -214,14 +273,6 @@ bool JackServerGlobals::Init() client_timeout = atoi(optarg); break; - case 'u': - do_unlock = 1; - break; - - case 'V': - show_version = 1; - break; - default: jack_error("unknown option character %c", optopt); break; @@ -234,9 +285,9 @@ bool JackServerGlobals::Init() goto error; } - driver_desc = jack_find_driver_descriptor(drivers, driver_name); + driver_desc = jack_find_driver_descriptor(drivers, master_driver_name); if (!driver_desc) { - jack_error("jackdmp: unknown driver '%s'", driver_name); + jack_error("jackdmp: unknown master driver '%s'", master_driver_name); goto error; } @@ -252,14 +303,14 @@ bool JackServerGlobals::Init() goto error; } - driver_args = (char**)malloc(sizeof(char*) * driver_nargs); - driver_args[0] = driver_name; + master_driver_args = (char**)malloc(sizeof(char*) * driver_nargs); + master_driver_args[0] = master_driver_name; for (i = 1; i < driver_nargs; i++) { - driver_args[i] = argv[optind++]; + master_driver_args[i] = argv[optind++]; } - if (jack_parse_driver_params(driver_desc, driver_nargs, driver_args, &driver_params)) { + if (jack_parse_driver_params(driver_desc, driver_nargs, master_driver_args, &master_driver_params)) { goto error; } @@ -294,7 +345,7 @@ bool JackServerGlobals::Init() free(argv[i]); } - int res = Start(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source); + int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source); if (res < 0) { jack_error("Cannot start server... exit"); Delete(); @@ -303,16 +354,48 @@ bool JackServerGlobals::Init() jack_unregister_server(server_name); goto error; } + + // Slave drivers + std::map::iterator it1; + for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) { + const char* name = ((*it1).first).c_str(); + driver_desc = jack_find_driver_descriptor(drivers, name); + if (!driver_desc) { + jack_error("jackdmp: unknown slave driver '%s'", name); + } else { + (*it1).second = fInstance->AddSlave(driver_desc, NULL); + } + } + + // Loopback driver + if (loopback > 0) { + driver_desc = jack_find_driver_descriptor(drivers, "loopback"); + if (!driver_desc) { + jack_error("jackdmp: unknown driver '%s'", "loopback"); + } else { + fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL); + } + } + + // Internal clients + std::map::iterator it2; + for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) { + int status, refnum; + const char* name = ((*it2).first).c_str(); + fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status); + (*it2).second = refnum; + } } - if (driver_params) - jack_free_driver_params(driver_params); + if (master_driver_params) + jack_free_driver_params(master_driver_params); return true; error: - if (driver_params) - jack_free_driver_params(driver_params); - fUserCount--; + jack_log("JackServerGlobals Init error"); + if (master_driver_params) + jack_free_driver_params(master_driver_params); + Destroy(); return false; } diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h index f7d6e439..69b8979e 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackDriverLoader.h" #include "JackCompilerDeps.h" #include "JackServer.h" +#include namespace Jack { @@ -39,6 +40,9 @@ struct SERVER_EXPORT JackServerGlobals static JackServer* fInstance; static unsigned int fUserCount; static int fRTNotificationSocket; // For debugging purpose + static std::map fSlavesList; + static std::map fInternalsList; + static bool (* on_device_acquire)(const char* device_name); static void (* on_device_release)(const char* device_name); diff --git a/common/JackThreadedDriver.cpp b/common/JackThreadedDriver.cpp index 52e49197..88323fe5 100644 --- a/common/JackThreadedDriver.cpp +++ b/common/JackThreadedDriver.cpp @@ -152,6 +152,11 @@ bool JackThreadedDriver::IsRealTime() const return fDriver->IsRealTime(); } +bool JackThreadedDriver::IsRunning() const +{ + return fDriver->IsRunning(); +} + int JackThreadedDriver::Start() { jack_log("JackThreadedDriver::Start"); @@ -171,9 +176,9 @@ int JackThreadedDriver::Start() int JackThreadedDriver::Stop() { jack_log("JackThreadedDriver::Stop"); - + switch (fThread.GetStatus()) { - + // Kill the thread in Init phase case JackThread::kStarting: case JackThread::kIniting: @@ -182,15 +187,15 @@ int JackThreadedDriver::Stop() return -1; } break; - + // Stop when the thread cycle is finished case JackThread::kRunning: if (fThread.Stop() < 0) { - jack_error("Cannot stop thread"); + jack_error("Cannot stop thread"); return -1; } break; - + default: break; } @@ -218,7 +223,7 @@ bool JackThreadedDriver::Init() if (fThread.AcquireSelfRealTime(GetEngineControl()->fServerPriority) < 0) { jack_error("AcquireSelfRealTime error"); } else { - set_threaded_log_function(); + set_threaded_log_function(); } } return true; diff --git a/common/JackThreadedDriver.h b/common/JackThreadedDriver.h index f7bbf2d0..92ec1d26 100644 --- a/common/JackThreadedDriver.h +++ b/common/JackThreadedDriver.h @@ -38,14 +38,14 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi JackThread fThread; JackDriver* fDriver; - + public: JackThreadedDriver(JackDriver* driver); virtual ~JackThreadedDriver(); virtual int Open(); - + virtual int Open (bool capturing, bool playing, int inchannels, @@ -54,7 +54,7 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi const char* capture_driver_name, const char* playback_driver_name, jack_nframes_t capture_latency, - jack_nframes_t playback_latency) + jack_nframes_t playback_latency) { return -1; } @@ -70,34 +70,35 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi jack_nframes_t capture_latency, jack_nframes_t playback_latency); virtual int Close(); - + virtual int Process(); virtual int ProcessNull(); - + virtual int Attach(); virtual int Detach(); - + virtual int Read(); virtual int Write(); - + virtual int Start(); virtual int Stop(); virtual bool IsFixedBufferSize(); virtual int SetBufferSize(jack_nframes_t buffer_size); virtual int SetSampleRate(jack_nframes_t sample_rate); - + virtual void SetMaster(bool onoff); virtual bool GetMaster(); virtual void AddSlave(JackDriverInterface* slave); virtual void RemoveSlave(JackDriverInterface* slave); virtual std::list GetSlaves(); virtual int ProcessSlaves(); - + virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); virtual JackClientControl* GetClientControl() const; virtual bool IsRealTime() const; - + virtual bool IsRunning() const; + // JackRunnableInterface interface virtual bool Execute(); virtual bool Init(); diff --git a/common/JackWeakAPI.cpp b/common/JackWeakAPI.cpp index d516be76..6ff5af85 100644 --- a/common/JackWeakAPI.cpp +++ b/common/JackWeakAPI.cpp @@ -33,7 +33,7 @@ #include #include -/* dynamically load libjack and forward all registered calls to libjack +/* dynamically load libjack and forward all registered calls to libjack (similar to what relaytool is trying to do, but more portably..) */ @@ -61,15 +61,15 @@ static void __attribute__((constructor)) tryload_libjack() #else libjack_handle = dlopen("libjack.so.0", RTLD_LAZY); #endif - + } libjack_is_present = (libjack_handle != 0); } -void *load_jack_function(const char *fn_name) +void *load_jack_function(const char *fn_name) { void *fn = 0; - if (!libjack_handle) { + if (!libjack_handle) { fprintf (stderr, "libjack not found, so do not try to load %s ffs !\n", fn_name); return 0; } @@ -78,13 +78,13 @@ void *load_jack_function(const char *fn_name) #else fn = dlsym(libjack_handle, fn_name); #endif - if (!fn) { + if (!fn) { #ifdef WIN32 char* lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf,0,NULL ); fprintf (stderr, "could not GetProcAddress( %s ), %s \n", fn_name, lpMsgBuf) ; -#else - fprintf (stderr, "could not dlsym( %s ), %s \n", fn_name, dlerror()) ; +#else + fprintf (stderr, "could not dlsym( %s ), %s \n", fn_name, dlerror()) ; #endif } return fn; @@ -107,7 +107,7 @@ void *load_jack_function(const char *fn_name) if (fn) return (*fn)arguments; \ else return (return_type)0; \ } - + #define DECL_VOID_FUNCTION(fn_name, arguments_types, arguments) \ typedef void (*fn_name##_ptr_t)arguments_types; \ void fn_name arguments_types { \ @@ -118,8 +118,8 @@ void *load_jack_function(const char *fn_name) DECL_VOID_FUNCTION(jack_get_version, (int *major_ptr, int *minor_ptr, int *micro_ptr, int *proto_ptr), (major_ptr, minor_ptr, micro_ptr, proto_ptr)); -DECL_FUNCTION_NULL(const char *, jack_get_version_string, (), ()); -DECL_FUNCTION_NULL(jack_client_t *, jack_client_open, (const char *client_name, jack_options_t options, jack_status_t *status, ...), +DECL_FUNCTION_NULL(const char *, jack_get_version_string, (), ()); +DECL_FUNCTION_NULL(jack_client_t *, jack_client_open, (const char *client_name, jack_options_t options, jack_status_t *status, ...), (client_name, options, status)); DECL_FUNCTION(int, jack_client_close, (jack_client_t *client), (client)); DECL_FUNCTION_NULL(jack_client_t *, jack_client_new, (const char *client_name), (client_name)); @@ -135,11 +135,11 @@ DECL_VOID_FUNCTION(jack_on_info_shutdown, (jack_client_t* client, JackInfoShutdo DECL_FUNCTION(int, jack_set_process_callback, (jack_client_t *client, JackProcessCallback process_callback, void *arg), (client, process_callback, arg)); -DECL_FUNCTION(jack_nframes_t, jack_thread_wait, (jack_client_t *client, int status), (client, status)); - +DECL_FUNCTION(jack_nframes_t, jack_thread_wait, (jack_client_t *client, int status), (client, status)); + // -DECL_FUNCTION(jack_nframes_t, jack_cycle_wait, (jack_client_t *client), (client)); -DECL_VOID_FUNCTION(jack_cycle_signal, (jack_client_t *client, int status), (client, status)); +DECL_FUNCTION(jack_nframes_t, jack_cycle_wait, (jack_client_t *client), (client)); +DECL_VOID_FUNCTION(jack_cycle_signal, (jack_client_t *client, int status), (client, status)); DECL_FUNCTION(int, jack_set_process_thread, (jack_client_t *client, JackThreadCallback fun, void *arg), (client, fun, arg)); @@ -149,8 +149,8 @@ DECL_FUNCTION(int, jack_set_thread_init_callback, (jack_client_t *client, DECL_FUNCTION(int, jack_set_freewheel_callback, (jack_client_t *client, JackFreewheelCallback freewheel_callback, void *arg), (client, freewheel_callback, arg)); -DECL_FUNCTION(int, jack_set_freewheel, (jack_client_t *client, int onoff), (client, onoff)); -DECL_FUNCTION(int, jack_set_buffer_size, (jack_client_t *client, jack_nframes_t nframes), (client, nframes)); +DECL_FUNCTION(int, jack_set_freewheel, (jack_client_t *client, int onoff), (client, onoff)); +DECL_FUNCTION(int, jack_set_buffer_size, (jack_client_t *client, jack_nframes_t nframes), (client, nframes)); DECL_FUNCTION(int, jack_set_buffer_size_callback, (jack_client_t *client, JackBufferSizeCallback bufsize_callback, void *arg), (client, bufsize_callback, arg)); @@ -175,6 +175,9 @@ DECL_FUNCTION(int, jack_set_graph_order_callback, (jack_client_t *client, DECL_FUNCTION(int, jack_set_xrun_callback, (jack_client_t *client, JackXRunCallback xrun_callback, void *arg), (client, xrun_callback, arg)); +DECL_FUNCTION(int, jack_set_latency_callback, (jack_client_t *client, + JackLatencyCallback latency_callback, + void *arg), (client, latency_callback, arg)); DECL_FUNCTION(int, jack_activate, (jack_client_t *client), (client)); DECL_FUNCTION(int, jack_deactivate, (jack_client_t *client), (client)); DECL_FUNCTION_NULL(jack_port_t *, jack_port_register, (jack_client_t *client, const char *port_name, const char *port_type, @@ -198,6 +201,8 @@ DECL_FUNCTION(jack_nframes_t, jack_port_get_latency, (jack_port_t *port), (port) DECL_FUNCTION(jack_nframes_t, jack_port_get_total_latency ,(jack_client_t * client, jack_port_t *port), (client, port)); DECL_VOID_FUNCTION(jack_port_set_latency, (jack_port_t * port, jack_nframes_t frames), (port, frames)); DECL_FUNCTION(int, jack_recompute_total_latency, (jack_client_t* client, jack_port_t* port), (client, port)); +DECL_VOID_FUNCTION(jack_port_get_latency_range, (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range), (port, mode, range)); +DECL_VOID_FUNCTION(jack_port_set_latency_range, (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range), (port, mode, range)); DECL_FUNCTION(int, jack_recompute_total_latencies, (jack_client_t* client),(client)); DECL_FUNCTION(int, jack_port_set_name, (jack_port_t *port, const char *port_name), (port, port_name)); @@ -213,10 +218,11 @@ DECL_FUNCTION(int, jack_disconnect, (jack_client_t * client, const char *source_ DECL_FUNCTION(int, jack_port_disconnect, (jack_client_t * client, jack_port_t * port), (client, port)); DECL_FUNCTION(int, jack_port_name_size,(),()); DECL_FUNCTION(int, jack_port_type_size,(),()); - +DECL_FUNCTION(size_t, jack_port_type_get_buffer_size, (jack_client_t *client, const char* port_type), (client, port_type)); + DECL_FUNCTION(jack_nframes_t, jack_get_sample_rate, (jack_client_t *client), (client)); DECL_FUNCTION(jack_nframes_t, jack_get_buffer_size, (jack_client_t *client), (client)); -DECL_FUNCTION_NULL(const char**, jack_get_ports, (jack_client_t *client, const char *port_name_pattern, const char * type_name_pattern, +DECL_FUNCTION_NULL(const char**, jack_get_ports, (jack_client_t *client, const char *port_name_pattern, const char * type_name_pattern, unsigned long flags), (client, port_name_pattern, type_name_pattern, flags)); DECL_FUNCTION_NULL(jack_port_t *, jack_port_by_name, (jack_client_t * client, const char *port_name), (client, port_name)); DECL_FUNCTION_NULL(jack_port_t *, jack_port_by_id, (jack_client_t *client, jack_port_id_t port_id), (client, port_id)); @@ -240,7 +246,7 @@ DECL_VOID_FUNCTION(jack_reset_max_delayed_usecs, (jack_client_t *client), (clien DECL_FUNCTION(int, jack_release_timebase, (jack_client_t *client), (client)); DECL_FUNCTION(int, jack_set_sync_callback, (jack_client_t *client, JackSyncCallback sync_callback, void *arg), (client, sync_callback, arg)); DECL_FUNCTION(int, jack_set_sync_timeout, (jack_client_t *client, jack_time_t timeout), (client, timeout)); -DECL_FUNCTION(int, jack_set_timebase_callback, (jack_client_t *client, +DECL_FUNCTION(int, jack_set_timebase_callback, (jack_client_t *client, int conditional, JackTimebaseCallback timebase_callback, void *arg), (client, conditional, timebase_callback, arg)); @@ -272,17 +278,27 @@ DECL_VOID_FUNCTION(jack_set_thread_creator, (jack_thread_creator_t jtc), (jtc)); DECL_FUNCTION(char *, jack_get_internal_client_name, (jack_client_t *client, jack_intclient_t intclient), (client, intclient)); DECL_FUNCTION(jack_intclient_t, jack_internal_client_handle, (jack_client_t *client, const char *client_name, jack_status_t *status), (client, client_name, status)); /* -DECL_FUNCTION(jack_intclient_t, jack_internal_client_load, (jack_client_t *client, - const char *client_name, - jack_options_t options, +DECL_FUNCTION(jack_intclient_t, jack_internal_client_load, (jack_client_t *client, + const char *client_name, + jack_options_t options, jack_status_t *status , ...), (client, client_name, options, status, ...)); */ DECL_FUNCTION(jack_status_t, jack_internal_client_unload, (jack_client_t *client, jack_intclient_t intclient), (client, intclient)); DECL_VOID_FUNCTION(jack_free, (void* ptr), (ptr)); -// MIDI +// session +DECL_FUNCTION(int, jack_set_session_callback, (jack_client_t* ext_client, JackSessionCallback session_callback, void* arg), (ext_client, session_callback, arg)); +DECL_FUNCTION(jack_session_command_t*, jack_session_notify, (jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path), (ext_client, target, ev_type, path)à); +DECL_FUNCTION(int jack_session_reply, (jack_client_t* ext_client, jack_session_event_t *event), (ext_client, event)); +DECL_VOID_FUNCTION(jack_session_event_free, (jack_session_event_t* ev), (ev)); +DECL_FUNCTION(char*, jack_get_uuid_for_client_name, (jack_client_t* ext_client, const char* client_name),(ext_client, client_name)); +DECL_FUNCTION(char*, jack_get_client_name_by_uuid, (jack_client_t* ext_client, const char* client_uuid),(ext_client, client_uuid)); +DECL_FUNCTION(int, jack_reserve_client_name, (jack_client_t* ext_client, const char* name, const char* uuid),(ext_client, name, uuid)); +DECL_VOID_FUNCTION(jack_session_commands_free, (jack_session_command_t *cmds),(cmds)); +DECL_FUNCTION(int, jack_client_has_session_callback, (jack_client_t *client, const char* client_name),(client, client_name)); +// MIDI DECL_FUNCTION(jack_nframes_t, jack_midi_get_event_count, (void* port_buffer), (port_buffer)); DECL_FUNCTION(int, jack_midi_event_get, (jack_midi_event_t* event, void* port_buffer, jack_nframes_t event_index), (event, port_buffer, event_index)) ; DECL_VOID_FUNCTION(jack_midi_clear_buffer, (void* port_buffer), (port_buffer)); diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp index 1d05eeb8..602aca31 100644 --- a/common/Jackdmp.cpp +++ b/common/Jackdmp.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include #include +#include #include "types.h" #include "jack.h" @@ -101,7 +102,8 @@ static void usage(FILE* file) " [ --timeout OR -t client-timeout-in-msecs ]\n" " [ --loopback OR -L loopback-port-number ]\n" " [ --port-max OR -p maximum-number-of-ports]\n" - " [ --midi OR -X midi-driver ]\n" + " [ --slave-backend OR -X slave-backend-name ]\n" + " [ --internal-client OR -I internal-client-name ]\n" " [ --verbose OR -v ]\n" #ifdef __linux__ " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" @@ -111,21 +113,21 @@ static void usage(FILE* file) " [ --sync OR -S ]\n" " [ --temporary OR -T ]\n" " [ --version OR -V ]\n" - " -d backend [ ... backend args ... ]\n" + " -d master-backend-name [ ... master-backend args ... ]\n" #ifdef __APPLE__ - " Available backends may include: coreaudio, dummy or net.\n\n" + " Available master backends may include: coreaudio, dummy or net.\n\n" #endif #ifdef WIN32 - " Available backends may include: portaudio, dummy or net.\n\n" + " Available master backends may include: portaudio, dummy or net.\n\n" #endif #ifdef __linux__ - " Available backends may include: alsa, dummy, freebob, firewire or net\n\n" + " Available master backends may include: alsa, dummy, freebob, firewire or net\n\n" #endif #if defined(__sun__) || defined(sun) - " Available backends may include: boomer, oss, dummy or net.\n\n" + " Available master backends may include: boomer, oss, dummy or net.\n\n" #endif - " jackdmp -d backend --help\n" - " to display options for each backend\n\n"); + " jackdmp -d master-backend-name --help\n" + " to display options for each master backend\n\n"); } // To put in the control.h interface?? @@ -151,6 +153,20 @@ jackctl_server_get_driver( return NULL; } +static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name) +{ + const JSList * node_ptr = jackctl_server_get_internals_list(server); + + while (node_ptr) { + if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) { + return (jackctl_internal_t *)node_ptr->data; + } + node_ptr = jack_slist_next(node_ptr); + } + + return NULL; +} + static jackctl_parameter_t * jackctl_get_parameter( const JSList * parameters_list, @@ -174,12 +190,11 @@ int main(int argc, char* argv[]) jackctl_server_t * server_ctl; const JSList * server_parameters; const char* server_name = "default"; - jackctl_driver_t * audio_driver_ctl; - jackctl_driver_t * midi_driver_ctl; + jackctl_driver_t * master_driver_ctl; jackctl_driver_t * loopback_driver_ctl; int replace_registry = 0; - const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" + const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" #ifdef __linux__ "c:" #endif @@ -192,6 +207,7 @@ int main(int argc, char* argv[]) { "loopback-driver", 1, 0, 'L' }, { "audio-driver", 1, 0, 'd' }, { "midi-driver", 1, 0, 'X' }, + { "internal-client", 1, 0, 'I' }, { "verbose", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { "port-max", 1, 0, 'p' }, @@ -213,14 +229,9 @@ int main(int argc, char* argv[]) int i,opt = 0; int option_index = 0; - bool seen_audio_driver = false; - bool seen_midi_driver = false; - char *audio_driver_name = NULL; - char **audio_driver_args = NULL; - int audio_driver_nargs = 1; - char *midi_driver_name = NULL; - char **midi_driver_args = NULL; - int midi_driver_nargs = 1; + char* master_driver_name = NULL; + char** master_driver_args = NULL; + int master_driver_nargs = 1; int do_mlock = 1; int do_unlock = 0; int loopback = 0; @@ -229,6 +240,14 @@ int main(int argc, char* argv[]) jackctl_parameter_t* param; union jackctl_parameter_value value; + std::list internals_list; + std::list slaves_list; + std::list::iterator it; + + // Assume that we fail. + int return_value = -1; + bool notify_sent = false; + copyright(stdout); #if defined(JACK_DBUS) && defined(__linux__) server_ctl = jackctl_server_create(audio_acquire, audio_release); @@ -250,7 +269,7 @@ int main(int argc, char* argv[]) } opterr = 0; - while (!seen_audio_driver && + while (!master_driver_name && (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { @@ -270,15 +289,14 @@ int main(int argc, char* argv[]) jackctl_parameter_set_value(param, &value); } else { usage(stdout); - goto fail_free1; + goto destroy_server; } } break; #endif case 'd': - seen_audio_driver = true; - audio_driver_name = optarg; + master_driver_name = optarg; break; case 'L': @@ -286,8 +304,11 @@ int main(int argc, char* argv[]) break; case 'X': - seen_midi_driver = true; - midi_driver_name = optarg; + slaves_list.push_back(optarg); + break; + + case 'I': + internals_list.push_back(optarg); break; case 'p': @@ -385,7 +406,7 @@ int main(int argc, char* argv[]) case 'h': usage(stdout); - goto fail_free1; + goto destroy_server; } } @@ -404,64 +425,65 @@ int main(int argc, char* argv[]) return -1; } - if (!seen_audio_driver) { + if (!master_driver_name) { usage(stderr); - goto fail_free1; + goto destroy_server; } - // Audio driver - audio_driver_ctl = jackctl_server_get_driver(server_ctl, audio_driver_name); - if (audio_driver_ctl == NULL) { - fprintf(stderr, "Unknown driver \"%s\"\n", audio_driver_name); - goto fail_free1; + // Master driver + master_driver_ctl = jackctl_server_get_driver(server_ctl, master_driver_name); + if (master_driver_ctl == NULL) { + fprintf(stderr, "Unknown driver \"%s\"\n", master_driver_name); + goto destroy_server; } if (optind < argc) { - audio_driver_nargs = 1 + argc - optind; + master_driver_nargs = 1 + argc - optind; } else { - audio_driver_nargs = 1; + master_driver_nargs = 1; } - if (audio_driver_nargs == 0) { + if (master_driver_nargs == 0) { fprintf(stderr, "No driver specified ... hmm. JACK won't do" " anything when run like this.\n"); - goto fail_free1; + goto destroy_server; } - audio_driver_args = (char **) malloc(sizeof(char *) * audio_driver_nargs); - audio_driver_args[0] = audio_driver_name; + master_driver_args = (char **) malloc(sizeof(char *) * master_driver_nargs); + master_driver_args[0] = master_driver_name; - for (i = 1; i < audio_driver_nargs; i++) { - audio_driver_args[i] = argv[optind++]; + for (i = 1; i < master_driver_nargs; i++) { + master_driver_args[i] = argv[optind++]; } - if (jackctl_parse_driver_params(audio_driver_ctl, audio_driver_nargs, audio_driver_args)) { - goto fail_free1; + if (jackctl_parse_driver_params(master_driver_ctl, master_driver_nargs, master_driver_args)) { + goto destroy_server; } - // Setup signals then start server + // Setup signals signals = jackctl_setup_signals(0); - if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { - fprintf(stderr, "Failed to start server\n"); - goto fail_free1; + // Open server + if (! jackctl_server_open(server_ctl, master_driver_ctl)) { + fprintf(stderr, "Failed to open server\n"); + goto destroy_server; } - // MIDI driver - if (seen_midi_driver) { - - midi_driver_ctl = jackctl_server_get_driver(server_ctl, midi_driver_name); - if (midi_driver_ctl == NULL) { - fprintf(stderr, "Unknown driver \"%s\"\n", midi_driver_name); - goto fail_free2; + // Slave drivers + for (it = slaves_list.begin(); it != slaves_list.end(); it++) { + jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it); + if (slave_driver_ctl == NULL) { + fprintf(stderr, "Unknown driver \"%s\"\n", *it); + goto close_server; } - - jackctl_server_add_slave(server_ctl, midi_driver_ctl); + jackctl_server_add_slave(server_ctl, slave_driver_ctl); } // Loopback driver if (loopback > 0) { loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); + + // XX: What if this fails? if (loopback_driver_ctl != NULL) { const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl); param = jackctl_get_parameter(loopback_parameters, "channels"); @@ -471,27 +493,42 @@ int main(int argc, char* argv[]) } jackctl_server_add_slave(server_ctl, loopback_driver_ctl); } + + } + + // Start the server + if (!jackctl_server_start(server_ctl)) { + fprintf(stderr, "Failed to start server\n"); + goto close_server; + } + + // Internal clients + for (it = internals_list.begin(); it != internals_list.end(); it++) { + jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it); + if (internal_driver_ctl == NULL) { + fprintf(stderr, "Unknown internal \"%s\"\n", *it); + goto stop_server; + } + jackctl_server_load_internal(server_ctl, internal_driver_ctl); } notify_server_start(server_name); + notify_sent = true; + return_value = 0; // Waits for signal jackctl_wait_signals(signals); - if (!jackctl_server_stop(server_ctl)) + stop_server: + if (! jackctl_server_stop(server_ctl)) { fprintf(stderr, "Cannot stop server...\n"); - - jackctl_server_destroy(server_ctl); - notify_server_stop(server_name); - return 0; - -fail_free1: - jackctl_server_destroy(server_ctl); - return -1; - -fail_free2: - jackctl_server_stop(server_ctl); + } + if (notify_sent) { + notify_server_stop(server_name); + } + close_server: + jackctl_server_close(server_ctl); + destroy_server: jackctl_server_destroy(server_ctl); - notify_server_stop(server_name); - return -1; + return return_value; } diff --git a/common/jack/control.h b/common/jack/control.h index caeb931d..b2c53ab0 100644 --- a/common/jack/control.h +++ b/common/jack/control.h @@ -4,7 +4,7 @@ Copyright (C) 2008 Nedko Arnaudov Copyright (C) 2008 GRAME - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. @@ -86,10 +86,10 @@ extern "C" { * @{ */ -/** +/** * Call this function to setup process signal handling. As a general * rule, it is required for proper operation for the server object. - * + * * @param flags signals setup flags, use 0 for none. Currently no * flags are defined * @@ -99,9 +99,9 @@ sigset_t jackctl_setup_signals( unsigned int flags); -/** +/** * Call this function to wait on a signal set. - * + * * @param signals signals set to wait on */ void @@ -123,43 +123,65 @@ jackctl_server_create( bool (* on_device_acquire)(const char * device_name), void (* on_device_release)(const char * device_name)); -/** +/** * Call this function to destroy server object. - * + * * @param server server object handle to destroy */ void jackctl_server_destroy( jackctl_server_t * server); -/** - * Call this function to start JACK server - * +/** + * Call this function to open JACK server + * * @param server server object handle * @param driver driver to use - * + * * @return success status: true - success, false - fail */ bool -jackctl_server_start( +jackctl_server_open( jackctl_server_t * server, jackctl_driver_t * driver); -/** +/** + * Call this function to start JACK server + * + * @param server server object handle + * + * @return success status: true - success, false - fail + */ +bool +jackctl_server_start( + jackctl_server_t * server); + +/** * Call this function to stop JACK server - * + * * @param server server object handle - * + * * @return success status: true - success, false - fail */ bool jackctl_server_stop( jackctl_server_t * server); -/** +/** + * Call this function to close JACK server + * + * @param server server object handle + * + * @return success status: true - success, false - fail + */ +bool +jackctl_server_close( + jackctl_server_t * server); + +/** * Call this function to get list of available drivers. List node data * pointers is a driver object handle (::jackctl_driver_t). - * + * * @param server server object handle to get drivers for * * @return Single linked list of driver object handles. Must not be @@ -169,10 +191,10 @@ const JSList * jackctl_server_get_drivers_list( jackctl_server_t * server); -/** +/** * Call this function to get list of server parameters. List node data * pointers is a parameter object handle (::jackctl_parameter_t). - * + * * @param server server object handle to get parameters for * * @return Single linked list of parameter object handles. Must not be @@ -182,10 +204,10 @@ const JSList * jackctl_server_get_parameters( jackctl_server_t * server); -/** +/** * Call this function to get list of available internal clients. List node data * pointers is a internal client object handle (::jackctl_internal_t). - * + * * @param server server object handle to get internal clients for * * @return Single linked list of internal client object handles. Must not be @@ -195,12 +217,13 @@ const JSList * jackctl_server_get_internals_list( jackctl_server_t * server); -/** +/** * Call this function to load one internal client. - * + * (can be used when the server is running) + * * @param server server object handle * @param internal internal to use - * + * * @return success status: true - success, false - fail */ bool @@ -208,12 +231,13 @@ jackctl_server_load_internal( jackctl_server_t * server, jackctl_internal_t * internal); -/** +/** * Call this function to unload one internal client. - * + * (can be used when the server is running) + * * @param server server object handle * @param internal internal to unload - * + * * @return success status: true - success, false - fail */ bool @@ -221,46 +245,50 @@ jackctl_server_unload_internal( jackctl_server_t * server, jackctl_internal_t * internal); -/** +/** * Call this function to add a slave in the driver slave list. - * + * (cannot be used when the server is running that is between + * jackctl_server_start and jackctl_server_stop) + * * @param server server object handle * @param driver driver to add in the driver slave list. - * + * * @return success status: true - success, false - fail - */ -bool + */ +bool jackctl_server_add_slave(jackctl_server_t * server, jackctl_driver_t * driver); -/** +/** * Call this function to remove a slave from the driver slave list. - * + * (cannot be used when the server is running that is between + * jackctl_server_start and jackctl_server_stop) + * * @param server server object handle * @param driver driver to remove from the driver slave list. - * + * * @return success status: true - success, false - fail - */ -bool + */ +bool jackctl_server_remove_slave(jackctl_server_t * server, jackctl_driver_t * driver); -/** +/** * Call this function to switch master driver. - * + * * @param server server object handle * @param driver driver to switch to - * + * * @return success status: true - success, false - fail - */ -bool + */ +bool jackctl_server_switch_master(jackctl_server_t * server, jackctl_driver_t * driver); - -/** + +/** * Call this function to get name of driver. - * + * * @param driver driver object handle to get name of * * @return driver name. Must not be modified. Always same for same @@ -270,10 +298,10 @@ const char * jackctl_driver_get_name( jackctl_driver_t * driver); -/** +/** * Call this function to get list of driver parameters. List node data * pointers is a parameter object handle (::jackctl_parameter_t). - * + * * @param driver driver object handle to get parameters for * * @return Single linked list of parameter object handles. Must not be @@ -283,9 +311,9 @@ const JSList * jackctl_driver_get_parameters( jackctl_driver_t * driver); -/** +/** * Call this function to get name of internal client. - * + * * @param internal internal object handle to get name of * * @return internal name. Must not be modified. Always same for same @@ -295,10 +323,10 @@ const char * jackctl_internal_get_name( jackctl_internal_t * internal); -/** +/** * Call this function to get list of internal parameters. List node data * pointers is a parameter object handle (::jackctl_parameter_t). - * + * * @param internal internal object handle to get parameters for * * @return Single linked list of parameter object handles. Must not be @@ -308,9 +336,9 @@ const JSList * jackctl_internal_get_parameters( jackctl_internal_t * internal); -/** +/** * Call this function to get parameter name. - * + * * @param parameter parameter object handle to get name of * * @return parameter name. Must not be modified. Always same for same @@ -320,9 +348,9 @@ const char * jackctl_parameter_get_name( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter short description. - * + * * @param parameter parameter object handle to get short description of * * @return parameter short description. Must not be modified. Always @@ -332,9 +360,9 @@ const char * jackctl_parameter_get_short_description( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter long description. - * + * * @param parameter parameter object handle to get long description of * * @return parameter long description. Must not be modified. Always @@ -344,9 +372,9 @@ const char * jackctl_parameter_get_long_description( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter type. - * + * * @param parameter parameter object handle to get type of * * @return parameter type. Always same for same parameter object. @@ -355,21 +383,21 @@ jackctl_param_type_t jackctl_parameter_get_type( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter character. - * + * * @param parameter parameter object handle to get character of * - * @return character. + * @return character. */ char jackctl_parameter_get_id( jackctl_parameter_t * parameter); -/** +/** * Call this function to check whether parameter has been set, or its * default value is being used. - * + * * @param parameter parameter object handle to check * * @return true - parameter is set, false - parameter is using default @@ -379,9 +407,9 @@ bool jackctl_parameter_is_set( jackctl_parameter_t * parameter); -/** +/** * Call this function to reset parameter to its default value. - * + * * @param parameter parameter object handle to reset value of * * @return success status: true - success, false - fail @@ -390,9 +418,9 @@ bool jackctl_parameter_reset( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter value. - * + * * @param parameter parameter object handle to get value of * * @return parameter value. @@ -401,9 +429,9 @@ union jackctl_parameter_value jackctl_parameter_get_value( jackctl_parameter_t * parameter); -/** +/** * Call this function to set parameter value. - * + * * @param parameter parameter object handle to get value of * @param value_ptr pointer to variable containing parameter value * @@ -414,9 +442,9 @@ jackctl_parameter_set_value( jackctl_parameter_t * parameter, const union jackctl_parameter_value * value_ptr); -/** +/** * Call this function to get parameter default value. - * + * * @param parameter parameter object handle to get default value of * * @return parameter default value. @@ -424,10 +452,10 @@ jackctl_parameter_set_value( union jackctl_parameter_value jackctl_parameter_get_default_value( jackctl_parameter_t * parameter); - -/** + +/** * Call this function check whether parameter has range constraint. - * + * * @param parameter object handle of parameter to check * * @return whether parameter has range constraint. @@ -436,9 +464,9 @@ bool jackctl_parameter_has_range_constraint( jackctl_parameter_t * parameter); -/** +/** * Call this function check whether parameter has enumeration constraint. - * + * * @param parameter object handle of parameter to check * * @return whether parameter has enumeration constraint. @@ -447,9 +475,9 @@ bool jackctl_parameter_has_enum_constraint( jackctl_parameter_t * parameter); -/** +/** * Call this function get how many enumeration values parameter has. - * + * * @param parameter object handle of parameter * * @return number of enumeration values @@ -458,9 +486,9 @@ uint32_t jackctl_parameter_get_enum_constraints_count( jackctl_parameter_t * parameter); -/** +/** * Call this function to get parameter enumeration value. - * + * * @param parameter object handle of parameter * @param index index of parameter enumeration value * @@ -471,9 +499,9 @@ jackctl_parameter_get_enum_constraint_value( jackctl_parameter_t * parameter, uint32_t index); -/** +/** * Call this function to get parameter enumeration value description. - * + * * @param parameter object handle of parameter * @param index index of parameter enumeration value * @@ -484,9 +512,9 @@ jackctl_parameter_get_enum_constraint_description( jackctl_parameter_t * parameter, uint32_t index); -/** +/** * Call this function to get parameter range. - * + * * @param parameter object handle of parameter * @param min_ptr pointer to variable receiving parameter minimum value * @param max_ptr pointer to variable receiving parameter maximum value @@ -497,10 +525,10 @@ jackctl_parameter_get_range_constraint( union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr); -/** +/** * Call this function to check whether parameter constraint is strict, * i.e. whether supplying non-matching value will not work for sure. - * + * * @param parameter parameter object handle to check * * @return whether parameter constraint is strict. @@ -509,11 +537,11 @@ bool jackctl_parameter_constraint_is_strict( jackctl_parameter_t * parameter); -/** +/** * Call this function to check whether parameter has fake values, * i.e. values have no user meaningful meaning and only value * description is meaningful to user. - * + * * @param parameter parameter object handle to check * * @return whether parameter constraint is strict. @@ -522,9 +550,9 @@ bool jackctl_parameter_constraint_is_fake_value( jackctl_parameter_t * parameter); -/** +/** * Call this function to log an error message. - * + * * @param format string */ void @@ -532,9 +560,9 @@ jack_error( const char *format, ...); -/** +/** * Call this function to log an information message. - * + * * @param format string */ void @@ -542,10 +570,10 @@ jack_info( const char *format, ...); -/** +/** * Call this function to log an information message but only when * verbose mode is enabled. - * + * * @param format string */ void diff --git a/common/netjack.c b/common/netjack.c index ce97da5c..e3ec0c33 100644 --- a/common/netjack.c +++ b/common/netjack.c @@ -365,7 +365,7 @@ void netjack_attach( netjack_driver_state_t *netj ) if( netj->bitdepth == CELT_MODE ) { #if HAVE_CELT -#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 +#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 celt_int32 lookahead; netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); #else @@ -398,7 +398,9 @@ void netjack_attach( netjack_driver_state_t *netj ) if( netj->bitdepth == CELT_MODE ) { #if HAVE_CELT -#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 +#if HAVE_CELT_API_0_11 + netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create_custom( netj->celt_mode, 1, NULL ) ); +#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) ); #else netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) ); @@ -444,7 +446,10 @@ void netjack_attach( netjack_driver_state_t *netj ) jack_slist_append (netj->playback_ports, port); if( netj->bitdepth == CELT_MODE ) { #if HAVE_CELT -#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 +#if HAVE_CELT_API_0_11 + CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); + netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) ); +#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL ); netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); #else @@ -545,18 +550,18 @@ void netjack_detach( netjack_driver_state_t *netj ) netjack_driver_state_t *netjack_init (netjack_driver_state_t *netj, jack_client_t * client, - const char *name, - unsigned int capture_ports, - unsigned int playback_ports, - unsigned int capture_ports_midi, - unsigned int playback_ports_midi, - jack_nframes_t sample_rate, - jack_nframes_t period_size, - unsigned int listen_port, - unsigned int transport_sync, - unsigned int resample_factor, - unsigned int resample_factor_up, - unsigned int bitdepth, + const char *name, + unsigned int capture_ports, + unsigned int playback_ports, + unsigned int capture_ports_midi, + unsigned int playback_ports_midi, + jack_nframes_t sample_rate, + jack_nframes_t period_size, + unsigned int listen_port, + unsigned int transport_sync, + unsigned int resample_factor, + unsigned int resample_factor_up, + unsigned int bitdepth, unsigned int use_autoconfig, unsigned int latency, unsigned int redundancy, @@ -663,74 +668,74 @@ netjack_startup( netjack_driver_state_t *netj ) netj->srcaddress_valid = 0; if (netj->use_autoconfig) { - jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header)); -#ifdef WIN32 - int address_size = sizeof( struct sockaddr_in ); -#else - socklen_t address_size = sizeof (struct sockaddr_in); -#endif - //jack_info ("Waiting for an incoming packet !!!"); - //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); - - while(1) { - if( ! netjack_poll( netj->sockfd, 1000 ) ) { - jack_info ("Waiting aborted"); - return -1; - } - first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); -#ifdef WIN32 - if( first_pack_len == -1 ) { - first_pack_len = sizeof(jacknet_packet_header); - break; + jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header)); + #ifdef WIN32 + int address_size = sizeof( struct sockaddr_in ); + #else + socklen_t address_size = sizeof (struct sockaddr_in); + #endif + //jack_info ("Waiting for an incoming packet !!!"); + //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); + + while(1) { + if( ! netjack_poll( netj->sockfd, 1000 ) ) { + jack_info ("Waiting aborted"); + return -1; + } + first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); + #ifdef WIN32 + if( first_pack_len == -1 ) { + first_pack_len = sizeof(jacknet_packet_header); + break; + } + #else + if (first_pack_len == sizeof (jacknet_packet_header)) + break; + #endif } -#else - if (first_pack_len == sizeof (jacknet_packet_header)) - break; -#endif - } - netj->srcaddress_valid = 1; + netj->srcaddress_valid = 1; - if (first_pack_len == sizeof (jacknet_packet_header)) - { - packet_header_ntoh (first_packet); - - jack_info ("AutoConfig Override !!!"); - if (netj->sample_rate != first_packet->sample_rate) - { - jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate); - netj->sample_rate = first_packet->sample_rate; - } - - if (netj->period_size != first_packet->period_size) - { - jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size); - netj->period_size = first_packet->period_size; - } - if (netj->capture_channels_audio != first_packet->capture_channels_audio) - { - jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio); - netj->capture_channels_audio = first_packet->capture_channels_audio; - } - if (netj->capture_channels_midi != first_packet->capture_channels_midi) - { - jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi); - netj->capture_channels_midi = first_packet->capture_channels_midi; - } - if (netj->playback_channels_audio != first_packet->playback_channels_audio) - { - jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio); - netj->playback_channels_audio = first_packet->playback_channels_audio; - } - if (netj->playback_channels_midi != first_packet->playback_channels_midi) - { - jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi); - netj->playback_channels_midi = first_packet->playback_channels_midi; - } - - netj->mtu = first_packet->mtu; - jack_info ("MTU is set to %d bytes", first_packet->mtu); - netj->latency = first_packet->latency; - } + if (first_pack_len == sizeof (jacknet_packet_header)) + { + packet_header_ntoh (first_packet); + + jack_info ("AutoConfig Override !!!"); + if (netj->sample_rate != first_packet->sample_rate) + { + jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate); + netj->sample_rate = first_packet->sample_rate; + } + + if (netj->period_size != first_packet->period_size) + { + jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size); + netj->period_size = first_packet->period_size; + } + if (netj->capture_channels_audio != first_packet->capture_channels_audio) + { + jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio); + netj->capture_channels_audio = first_packet->capture_channels_audio; + } + if (netj->capture_channels_midi != first_packet->capture_channels_midi) + { + jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi); + netj->capture_channels_midi = first_packet->capture_channels_midi; + } + if (netj->playback_channels_audio != first_packet->playback_channels_audio) + { + jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio); + netj->playback_channels_audio = first_packet->playback_channels_audio; + } + if (netj->playback_channels_midi != first_packet->playback_channels_midi) + { + jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi); + netj->playback_channels_midi = first_packet->playback_channels_midi; + } + + netj->mtu = first_packet->mtu; + jack_info ("MTU is set to %d bytes", first_packet->mtu); + netj->latency = first_packet->latency; + } } netj->capture_channels = netj->capture_channels_audio + netj->capture_channels_midi; netj->playback_channels = netj->playback_channels_audio + netj->playback_channels_midi; @@ -762,21 +767,21 @@ netjack_startup( netjack_driver_state_t *netj ) * 1000000.0f); if( netj->latency == 0 ) - netj->deadline_offset = 50*netj->period_usecs; + netj->deadline_offset = 50*netj->period_usecs; else - netj->deadline_offset = netj->period_usecs + 10*netj->latency*netj->period_usecs/100; + netj->deadline_offset = netj->period_usecs + 10*netj->latency*netj->period_usecs/100; if( netj->bitdepth == CELT_MODE ) { - // celt mode. - // TODO: this is a hack. But i dont want to change the packet header. - netj->resample_factor = (netj->resample_factor * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); - netj->resample_factor_up = (netj->resample_factor_up * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); + // celt mode. + // TODO: this is a hack. But i dont want to change the packet header. + netj->resample_factor = (netj->resample_factor * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); + netj->resample_factor_up = (netj->resample_factor_up * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); - netj->net_period_down = netj->resample_factor; - netj->net_period_up = netj->resample_factor_up; + netj->net_period_down = netj->resample_factor; + netj->net_period_up = netj->resample_factor_up; } else { - netj->net_period_down = (float) netj->period_size / (float) netj->resample_factor; - netj->net_period_up = (float) netj->period_size / (float) netj->resample_factor_up; + netj->net_period_down = (float) netj->period_size / (float) netj->resample_factor; + netj->net_period_up = (float) netj->period_size / (float) netj->resample_factor_up; } netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); @@ -790,9 +795,9 @@ netjack_startup( netjack_driver_state_t *netj ) // Special handling for latency=0 if( netj->latency == 0 ) - netj->resync_threshold = 0; + netj->resync_threshold = 0; else - netj->resync_threshold = MIN( 15, netj->latency-1 ); + netj->resync_threshold = MIN( 15, netj->latency-1 ); netj->running_free = 0; diff --git a/common/netjack.h b/common/netjack.h index 2bdd092c..bb745829 100644 --- a/common/netjack.h +++ b/common/netjack.h @@ -127,19 +127,19 @@ void netjack_detach( netjack_driver_state_t *netj ); netjack_driver_state_t *netjack_init (netjack_driver_state_t *netj, jack_client_t * client, - const char *name, - unsigned int capture_ports, - unsigned int playback_ports, - unsigned int capture_ports_midi, - unsigned int playback_ports_midi, - jack_nframes_t sample_rate, - jack_nframes_t period_size, - unsigned int listen_port, - unsigned int transport_sync, - unsigned int resample_factor, - unsigned int resample_factor_up, - unsigned int bitdepth, - unsigned int use_autoconfig, + const char *name, + unsigned int capture_ports, + unsigned int playback_ports, + unsigned int capture_ports_midi, + unsigned int playback_ports_midi, + jack_nframes_t sample_rate, + jack_nframes_t period_size, + unsigned int listen_port, + unsigned int transport_sync, + unsigned int resample_factor, + unsigned int resample_factor_up, + unsigned int bitdepth, + unsigned int use_autoconfig, unsigned int latency, unsigned int redundancy, int dont_htonl_floats, diff --git a/common/netjack_packet.c b/common/netjack_packet.c index d03d49f0..638e3d82 100644 --- a/common/netjack_packet.c +++ b/common/netjack_packet.c @@ -130,7 +130,7 @@ int get_sample_size (int bitdepth) //JN: why? is this for buffer sizes before or after encoding? //JN: if the former, why not int16_t, if the latter, shouldn't it depend on -c N? if( bitdepth == CELT_MODE ) - return sizeof( unsigned char ); + return sizeof( unsigned char ); return sizeof (int32_t); } @@ -328,7 +328,6 @@ cache_packet_add_fragment (cache_packet *pack, char *packet_buf, int rcv_len) return; } - if (fragment_nr == 0) { memcpy (pack->packet_buf, packet_buf, rcv_len); @@ -374,7 +373,6 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline) int timeout; #endif - jack_time_t now = jack_get_time(); if( now >= deadline ) return 0; @@ -389,7 +387,6 @@ netjack_poll_deadline (int sockfd, jack_time_t deadline) timeout = lrintf( (float)(deadline - now) / 1000.0 ); #endif - fds.fd = sockfd; fds.events = POLLIN; @@ -600,24 +597,24 @@ packet_cache_retreive_packet_pointer( packet_cache *pcache, jack_nframes_t frame for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) { - cpack = &(pcache->packets[i]); + cpack = &(pcache->packets[i]); break; - } + } } if( cpack == NULL ) { - //printf( "retreive packet: %d....not found\n", framecnt ); - return -1; + //printf( "retreive packet: %d....not found\n", framecnt ); + return -1; } if( !cache_packet_is_complete( cpack ) ) { - return -1; + return -1; } // ok. cpack is the one we want and its complete. *packet_buf = cpack->packet_buf; if( timestamp ) - *timestamp = cpack->recv_timestamp; + *timestamp = cpack->recv_timestamp; pcache->last_framecnt_retreived_valid = 1; pcache->last_framecnt_retreived = framecnt; @@ -634,18 +631,18 @@ packet_cache_release_packet( packet_cache *pcache, jack_nframes_t framecnt ) for (i = 0; i < pcache->size; i++) { if (pcache->packets[i].valid && (pcache->packets[i].framecnt == framecnt)) { - cpack = &(pcache->packets[i]); + cpack = &(pcache->packets[i]); break; - } + } } if( cpack == NULL ) { - //printf( "retreive packet: %d....not found\n", framecnt ); - return -1; + //printf( "retreive packet: %d....not found\n", framecnt ); + return -1; } if( !cache_packet_is_complete( cpack ) ) { - return -1; + return -1; } cache_packet_reset (cpack); @@ -661,13 +658,13 @@ packet_cache_get_fill( packet_cache *pcache, jack_nframes_t expected_framecnt ) for (i = 0; i < pcache->size; i++) { - cache_packet *cpack = &(pcache->packets[i]); + cache_packet *cpack = &(pcache->packets[i]); if (cpack->valid && cache_packet_is_complete( cpack )) - if( cpack->framecnt >= expected_framecnt ) - num_packets_before_us += 1; + if( cpack->framecnt >= expected_framecnt ) + num_packets_before_us += 1; } - return 100.0 * (float)num_packets_before_us / (float)( pcache->size ) ; + return 100.0 * (float)num_packets_before_us / (float)( pcache->size ); } // Returns 0 when no valid packet is inside the cache. @@ -680,29 +677,29 @@ packet_cache_get_next_available_framecnt( packet_cache *pcache, jack_nframes_t e for (i = 0; i < pcache->size; i++) { - cache_packet *cpack = &(pcache->packets[i]); - //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); + cache_packet *cpack = &(pcache->packets[i]); + //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { - //printf( "invalid\n" ); - continue; - } + //printf( "invalid\n" ); + continue; + } - if( cpack->framecnt < expected_framecnt ) - continue; + if( cpack->framecnt < expected_framecnt ) + continue; - if( (cpack->framecnt - expected_framecnt) > best_offset ) { - continue; + if( (cpack->framecnt - expected_framecnt) > best_offset ) { + continue; } best_offset = cpack->framecnt - expected_framecnt; retval = 1; - if( best_offset == 0 ) + if (best_offset == 0) break; } - if( retval && framecnt ) - *framecnt = expected_framecnt + best_offset; + if (retval && framecnt) + *framecnt = expected_framecnt + best_offset; return retval; } @@ -716,12 +713,12 @@ packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_ for (i = 0; i < pcache->size; i++) { - cache_packet *cpack = &(pcache->packets[i]); - //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); + cache_packet *cpack = &(pcache->packets[i]); + //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { - //printf( "invalid\n" ); - continue; + //printf( "invalid\n" ); + continue; } if (cpack->framecnt < best_value) { @@ -732,8 +729,8 @@ packet_cache_get_highest_available_framecnt( packet_cache *pcache, jack_nframes_ retval = 1; } - if( retval && framecnt ) - *framecnt = best_value; + if (retval && framecnt) + *framecnt = best_value; return retval; } @@ -748,15 +745,15 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn for (i = 0; i < pcache->size; i++) { - cache_packet *cpack = &(pcache->packets[i]); - //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); + cache_packet *cpack = &(pcache->packets[i]); + //printf( "p%d: valid=%d, frame %d\n", i, cpack->valid, cpack->framecnt ); if (!cpack->valid || !cache_packet_is_complete( cpack )) { - //printf( "invalid\n" ); - continue; + //printf( "invalid\n" ); + continue; } - if( (cpack->framecnt - expected_framecnt) < best_offset ) { + if ((cpack->framecnt - expected_framecnt) < best_offset) { continue; } @@ -766,8 +763,8 @@ packet_cache_find_latency( packet_cache *pcache, jack_nframes_t expected_framecn if( best_offset == 0 ) break; } - if( retval && framecnt ) - *framecnt = JACK_MAX_FRAMES - best_offset; + if (retval && framecnt) + *framecnt = JACK_MAX_FRAMES - best_offset; return retval; } @@ -786,18 +783,18 @@ netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct so int fragment_payload_size = mtu - sizeof (jacknet_packet_header); if (pkt_size <= mtu) { - int err; - pkthdr = (jacknet_packet_header *) packet_buf; + int err; + pkthdr = (jacknet_packet_header *) packet_buf; pkthdr->fragment_nr = htonl (0); err = sendto(sockfd, packet_buf, pkt_size, flags, addr, addr_size); - if( err<0 ) { - //printf( "error in send\n" ); - perror( "send" ); - } + if( err<0 ) { + //printf( "error in send\n" ); + perror( "send" ); + } } else { - int err; + int err; // Copy the packet header to the tx pack first. memcpy(tx_packet, packet_buf, sizeof (jacknet_packet_header)); @@ -819,14 +816,13 @@ netjack_sendto (int sockfd, char *packet_buf, int pkt_size, int flags, struct so // sendto(last_pack_size); err = sendto(sockfd, tx_packet, last_payload_size + sizeof(jacknet_packet_header), flags, addr, addr_size); - if( err<0 ) { - //printf( "error in send\n" ); - perror( "send" ); - } + if( err<0 ) { + //printf( "error in send\n" ); + perror( "send" ); + } } } - void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf) { @@ -907,8 +903,8 @@ render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_pe uint32_t *packet_bufX = (uint32_t *)packet_payload; - if( !packet_payload ) - return; + if (!packet_payload) + return; while (node != NULL) { @@ -951,19 +947,19 @@ render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_pe else #endif { - if( dont_htonl_floats ) - { - memcpy( buf, packet_bufX, net_period_down*sizeof(jack_default_audio_sample_t)); - } - else - { - for (i = 0; i < net_period_down; i++) - { - val.i = packet_bufX[i]; - val.i = ntohl (val.i); - buf[i] = val.f; - } - } + if( dont_htonl_floats ) + { + memcpy( buf, packet_bufX, net_period_down*sizeof(jack_default_audio_sample_t)); + } + else + { + for (i = 0; i < net_period_down; i++) + { + val.i = packet_bufX[i]; + val.i = ntohl (val.i); + buf[i] = val.f; + } + } } } else if (jack_port_is_midi (porttype)) @@ -1031,19 +1027,19 @@ render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_src else #endif { - if( dont_htonl_floats ) - { - memcpy( packet_bufX, buf, net_period_up*sizeof(jack_default_audio_sample_t) ); - } - else - { - for (i = 0; i < net_period_up; i++) - { - val.f = buf[i]; - val.i = htonl (val.i); - packet_bufX[i] = val.i; - } - } + if( dont_htonl_floats ) + { + memcpy( packet_bufX, buf, net_period_up*sizeof(jack_default_audio_sample_t) ); + } + else + { + for (i = 0; i < net_period_up; i++) + { + val.f = buf[i]; + val.i = htonl (val.i); + packet_bufX[i] = val.i; + } + } } } else if (jack_port_is_midi (porttype)) @@ -1218,8 +1214,8 @@ render_payload_to_jack_ports_8bit (void *packet_payload, jack_nframes_t net_peri int8_t *packet_bufX = (int8_t *)packet_payload; - if( !packet_payload ) - return; + if (!packet_payload) + return; while (node != NULL) { @@ -1368,21 +1364,20 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri if (jack_port_is_audio (porttype)) { // audio port, decode celt data. + CELTDecoder *decoder = src_node->data; + #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 + if( !packet_payload ) + celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); + else + celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); + #else + if( !packet_payload ) + celt_decode_float( decoder, NULL, net_period_down, buf ); + else + celt_decode_float( decoder, packet_bufX, net_period_down, buf ); + #endif - CELTDecoder *decoder = src_node->data; -#if HAVE_CELT_API_0_8 - if( !packet_payload ) - celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); - else - celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); -#else - if( !packet_payload ) - celt_decode_float( decoder, NULL, net_period_down, buf ); - else - celt_decode_float( decoder, packet_bufX, net_period_down, buf ); -#endif - - src_node = jack_slist_next (src_node); + src_node = jack_slist_next (src_node); } else if (jack_port_is_midi (porttype)) { @@ -1390,8 +1385,8 @@ render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_peri // convert the data buffer to a standard format (uint32_t based) unsigned int buffer_size_uint32 = net_period_down / 2; uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; - if( packet_payload ) - decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); + if( packet_payload ) + decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } packet_bufX = (packet_bufX + net_period_down); node = jack_slist_next (node); @@ -1422,7 +1417,7 @@ render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs float *floatbuf = alloca (sizeof(float) * nframes ); memcpy( floatbuf, buf, nframes*sizeof(float) ); CELTEncoder *encoder = src_node->data; -#if HAVE_CELT_API_0_8 +#if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up ); #else encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); diff --git a/common/varargs.h b/common/varargs.h index b7df00f6..f4a50948 100644 --- a/common/varargs.h +++ b/common/varargs.h @@ -39,23 +39,23 @@ extern "C" } jack_varargs_t; - static const char* jack_default_server_name (void) - { + static const char* jack_default_server_name (void) + { const char *server_name; if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL) server_name = "default"; return server_name; } - static inline void jack_varargs_init (jack_varargs_t *va) - { + static inline void jack_varargs_init (jack_varargs_t *va) + { memset (va, 0, sizeof(jack_varargs_t)); va->server_name = (char*)jack_default_server_name(); va->session_id = -1; } - static inline void jack_varargs_parse (jack_options_t options, va_list ap, jack_varargs_t *va) - { + static inline void jack_varargs_parse (jack_options_t options, va_list ap, jack_varargs_t *va) + { // initialize default settings jack_varargs_init (va); diff --git a/dbus/controller.c b/dbus/controller.c index 9c2bf3a5..77acef39 100644 --- a/dbus/controller.c +++ b/dbus/controller.c @@ -153,14 +153,21 @@ jack_controller_start_server( controller_ptr->xruns = 0; - if (!jackctl_server_start( + if (!jackctl_server_open( controller_ptr->server, controller_ptr->driver)) { - jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to start server"); + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server"); goto fail; } + if (!jackctl_server_start( + controller_ptr->server)) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to start server"); + goto fail_close_server; + } + controller_ptr->client = jack_client_open( "dbusapi", JackNoStartServer, @@ -213,6 +220,12 @@ fail_stop_server: jack_error("failed to stop jack server"); } +fail_close_server: + if (!jackctl_server_close(controller_ptr->server)) + { + jack_error("failed to close jack server"); + } + fail: return FALSE; } @@ -250,6 +263,12 @@ jack_controller_stop_server( return FALSE; } + if (!jackctl_server_close(controller_ptr->server)) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to close server"); + return FALSE; + } + controller_ptr->started = false; return TRUE; diff --git a/doxyfile b/doxyfile index 8f1342a4..45b36fda 100644 --- a/doxyfile +++ b/doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.2.8.1 +# Doxyfile 1.6.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -11,592 +11,1158 @@ # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- -# General configuration options +# Project related configuration options #--------------------------------------------------------------------------- -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "Jack2" -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 1.9.7 -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = build/default/ +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, -# German, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, -# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. -EXTRACT_ALL = NO +BRIEF_MEMBER_DESC = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. -EXTRACT_PRIVATE = NO +REPEAT_BRIEF = YES -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" -EXTRACT_STATIC = NO +ABBREVIATE_BRIEF = -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. -HIDE_UNDOC_MEMBERS = NO +ALWAYS_DETAILED_SEC = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these class will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. -HIDE_UNDOC_CLASSES = NO +INLINE_INHERITED_MEMB = NO -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. -BRIEF_MEMBER_DESC = YES +FULL_PATH_NAMES = NO -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. -REPEAT_BRIEF = YES +STRIP_FROM_PATH = -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. -ALWAYS_DETAILED_SEC = NO +STRIP_FROM_INC_PATH = -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. -FULL_PATH_NAMES = NO +SHORT_NAMES = NO -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. It is allowed to use relative paths in the argument list. +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) -STRIP_FROM_PATH = +JAVADOC_AUTOBRIEF = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) -INTERNAL_DOCS = NO +QT_AUTOBRIEF = NO -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a class diagram (in Html and LaTeX) for classes with base or -# super classes. Setting the tag to NO turns the diagrams off. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. -CLASS_DIAGRAMS = YES +MULTILINE_CPP_IS_BRIEF = NO -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. -SOURCE_BROWSER = YES +INHERIT_DOCS = YES -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. -INLINE_SOURCES = NO +SEPARATE_MEMBER_PAGES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. -STRIP_CODE_COMMENTS = YES +TAB_SIZE = 8 -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower case letters. If set to YES upper case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# users are adviced to set this option to NO. +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. -CASE_SENSE_NAMES = YES +ALIASES = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. -SHORT_NAMES = NO +OPTIMIZE_OUTPUT_FOR_C = NO -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. -HIDE_SCOPE_NAMES = NO +OPTIMIZE_OUTPUT_JAVA = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. -VERBATIM_HEADERS = YES +OPTIMIZE_FOR_FORTRAN = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put list of the files that are included by a file in the documentation -# of that file. +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. -SHOW_INCLUDE_FILES = YES +OPTIMIZE_OUTPUT_VHDL = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explict @brief command for a brief description. +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. -JAVADOC_AUTOBRIEF = NO +EXTENSION_MAPPING = -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# reimplements. +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. -INHERIT_DOCS = YES +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. -DISTRIBUTE_GROUP_DOC = NO +SORT_BRIEF_DOCS = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. -TAB_SIZE = 8 +SORT_MEMBERS_CTORS_1ST = NO -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO -ENABLED_SECTIONS = +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. -ALIASES = +GENERATE_DEPRECATEDLIST= YES -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consist of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. -MAX_INITIALIZER_LINES = 30 +ENABLED_SECTIONS = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. -# For instance some of the names that are used will be different. The list -# of all members will be omitted, etc. +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. -OPTIMIZE_OUTPUT_FOR_C = NO +MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO -WARN_FORMAT = +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +WARN_FORMAT = + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = common posix macosx macosx/coreaudio/ linux linux/alsa windows windows/portaudio common/jack/ - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -FILE_PATTERNS = *.cpp *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +INPUT = common \ + posix \ + macosx \ + macosx/coreaudio/ \ + linux \ + linux/alsa \ + windows \ + windows/portaudio \ + common/jack/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.cpp \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = RPC -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test -EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes # to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = -INPUT_FILTER = +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse. +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. -HTML_OUTPUT = +HTML_OUTPUT = + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a # standard header. -HTML_HEADER = +HTML_HEADER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a # standard footer. -HTML_FOOTER = +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = -# The HTML_STYLESHEET tag can be used to specify a user defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. -HTML_STYLESHEET = +HTML_TIMESTAMP = NO -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the Html help documentation and to the tree view. +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) +# This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript and frames is required (for instance Netscape 4.0+ -# or Internet explorer 4.0+). +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. -LATEX_OUTPUT = +LATEX_OUTPUT = + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimised for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. -RTF_OUTPUT = +RTF_OUTPUT = -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assigments. You only have to provide +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. -MAN_OUTPUT = +MAN_OUTPUT = -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) -MAN_EXTENSION = +MAN_EXTENSION = # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity @@ -607,202 +1173,388 @@ MAN_EXTENSION = MAN_LINKS = NO #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. -PREDEFINED = +PREDEFINED = -# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -#--------------------------------------------------------------------------- -# Configuration::addtions related to external references -#--------------------------------------------------------------------------- +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. -# The TAGFILES tag can be used to specify one or more tagfiles. +SKIP_FUNCTION_MACROS = YES -TAGFILES = +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO -# The PERL_PATH should be the absolute path and name of the perl script +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). -PERL_PATH = +PERL_PATH = #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. -GRAPHICAL_HIERARCHY = YES +CALL_GRAPH = NO -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found on the path. +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. -DOT_PATH = +CALLER_GRAPH = NO -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. -MAX_DOT_GRAPH_WIDTH = 1024 +GRAPHICAL_HIERARCHY = YES -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. -MAX_DOT_GRAPH_HEIGHT = 1024 +DIRECTORY_GRAPH = YES -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. -GENERATE_LEGEND = YES +DOT_IMAGE_FORMAT = png -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermedate dot files that are used to generate -# the various graphs. +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. -DOT_CLEANUP = YES +DOT_PATH = -#--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine -#--------------------------------------------------------------------------- +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO +DOTFILE_DIRS = -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. -CGI_NAME = +DOT_GRAPH_MAX_NODES = 50 -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. -CGI_URL = +MAX_DOT_GRAPH_DEPTH = 0 -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). -DOC_URL = +DOT_TRANSPARENT = NO -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. -DOC_ABSPATH = +DOT_MULTI_TARGETS = NO -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. -BIN_ABSPATH = +GENERATE_LEGEND = YES -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. -EXT_DOC_PATHS = +DOT_CLEANUP = YES diff --git a/example-clients/alsa_in.c b/example-clients/alsa_in.c index 7007fffd..43a030ef 100644 --- a/example-clients/alsa_in.c +++ b/example-clients/alsa_in.c @@ -15,7 +15,7 @@ #include #include -#include +#include "memops.h" #include "alsa/asoundlib.h" diff --git a/example-clients/alsa_out.c b/example-clients/alsa_out.c index 0dfb839f..be25e403 100644 --- a/example-clients/alsa_out.c +++ b/example-clients/alsa_out.c @@ -15,7 +15,7 @@ #include #include -#include +#include "memops.h" #include "alsa/asoundlib.h" diff --git a/example-clients/connect.c b/example-clients/connect.c index a4132cea..3c6de6b9 100644 --- a/example-clients/connect.c +++ b/example-clients/connect.c @@ -31,7 +31,7 @@ jack_port_t *input_port; jack_port_t *output_port; int connecting, disconnecting; -int done = 0; +volatile int done = 0; #define TRUE 1 #define FALSE 0 @@ -58,7 +58,6 @@ show_usage (char *my_name) fprintf (stderr, "For more information see http://jackaudio.org/\n"); } - int main (int argc, char *argv[]) { @@ -181,11 +180,11 @@ main (int argc, char *argv[]) if ((port1 = jack_port_by_name(client, portA)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portA); goto exit; - } + } if ((port2 = jack_port_by_name(client, portB)) == 0) { fprintf (stderr, "ERROR %s not a valid port\n", portB); goto exit; - } + } port1_flags = jack_port_flags (port1); port2_flags = jack_port_flags (port2); @@ -207,17 +206,25 @@ main (int argc, char *argv[]) goto exit; } + /* tell the JACK server that we are ready to roll */ + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + goto exit; + } + /* connect the ports. Note: you can't do this before the client is activated (this may change in the future). */ if (connecting) { if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) { + fprintf (stderr, "cannot connect client, already connected?\n"); goto exit; } } if (disconnecting) { if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) { + fprintf (stderr, "cannot disconnect client, already disconnected?\n"); goto exit; } } diff --git a/example-clients/control.c b/example-clients/control.c index 363b6b21..f22307b6 100644 --- a/example-clients/control.c +++ b/example-clients/control.c @@ -1,4 +1,4 @@ -/** @file simple_client.c +/** @file control.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. @@ -14,14 +14,14 @@ jack_client_t *client; static int reorder = 0; - + static int Jack_Graph_Order_Callback(void *arg) { const char **ports; int i; - + printf("Jack_Graph_Order_Callback count = %d\n", reorder++); - + ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); if (ports) { for (i = 0; ports[i]; ++i) { @@ -29,15 +29,15 @@ static int Jack_Graph_Order_Callback(void *arg) } free(ports); } - + ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - if (ports) { + if (ports) { for (i = 0; ports[i]; ++i) { printf("name: %s\n", ports[i]); } free(ports); } - + return 0; } @@ -46,7 +46,7 @@ main (int argc, char *argv[]) { jack_options_t options = JackNullOption; jack_status_t status; - + /* open a client connection to the JACK server */ client = jack_client_open("control_client", options, &status); @@ -54,7 +54,7 @@ main (int argc, char *argv[]) printf("jack_client_open() failed \n"); exit(1); } - + if (jack_set_graph_order_callback(client, Jack_Graph_Order_Callback, 0) != 0) { printf("Error when calling jack_set_graph_order_callback() !\n"); } @@ -66,10 +66,10 @@ main (int argc, char *argv[]) printf("cannot activate client"); exit(1); } - - printf("Type 'q' to quit\n"); + + printf("Type 'q' to quit\n"); while ((getchar() != 'q')) {} - + jack_client_close(client); exit (0); } diff --git a/example-clients/netsource.c b/example-clients/netsource.c index f3cd8274..5dd36265 100644 --- a/example-clients/netsource.c +++ b/example-clients/netsource.c @@ -139,21 +139,24 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int printf( "jack_netsource: cannot register %s port\n", buf); break; } - if( bitdepth == 1000 ) { -#if HAVE_CELT -#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 - CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); - capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); -#else - CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL ); - capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) ); -#endif -#endif - } else { -#if HAVE_SAMPLERATE - capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL)); -#endif - } + if (bitdepth == 1000) { + #if HAVE_CELT + #if HAVE_CELT_API_0_11 + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); + capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) ); + #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL ); + capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); + #else + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL ); + capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) ); + #endif + #endif + } else { + #if HAVE_SAMPLERATE + capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL)); + #endif + } capture_ports = jack_slist_append (capture_ports, port); } @@ -182,22 +185,25 @@ alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int printf ("jack_netsource: cannot register %s port\n", buf); break; } - if( bitdepth == 1000 ) { -#if HAVE_CELT -#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 - CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); - playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); -#else - CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL ); - playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) ); -#endif -#endif - } else { -#if HAVE_SAMPLERATE - playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL)); -#endif - } - playback_ports = jack_slist_append (playback_ports, port); + if( bitdepth == 1000 ) { + #if HAVE_CELT + #if HAVE_CELT_API_0_11 + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); + playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create_custom( celt_mode, 1, NULL ) ); + #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL ); + playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); + #else + CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL ); + playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) ); + #endif + #endif + } else { + #if HAVE_SAMPLERATE + playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL)); + #endif + } + playback_ports = jack_slist_append (playback_ports, port); } /* Allocate midi playback channels */ @@ -226,7 +232,7 @@ sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg) int retval = sync_state; if (! state_connected) { - return 1; + return 1; } if (latency_count) { latency_count--; @@ -275,14 +281,13 @@ process (jack_nframes_t nframes, void *arg) jack_time_t packet_recv_timestamp; if( bitdepth == 1000 ) - net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; + net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; else - net_period = (float) nframes / (float) factor; + net_period = (float) nframes / (float) factor; rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header); - /* Allocate a buffer where both In and Out Buffer will fit */ packet_buf_tx = alloca (tx_bufsize); @@ -346,29 +351,29 @@ process (jack_nframes_t nframes, void *arg) if( reply_port ) - input_fd = insockfd; + input_fd = insockfd; else - input_fd = outsockfd; + input_fd = outsockfd; // for latency == 0 we can poll. if( (latency == 0) || (freewheeling!=0) ) { - jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client)/jack_get_sample_rate(client); - // Now loop until we get the right packet. - while(1) { - jack_nframes_t got_frame; - if ( ! netjack_poll_deadline( input_fd, deadline ) ) - break; - - packet_cache_drain_socket(packcache, input_fd); - - if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) - if( got_frame == (framecnt - latency) ) - break; - } + jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client)/jack_get_sample_rate(client); + // Now loop until we get the right packet. + while(1) { + jack_nframes_t got_frame; + if ( ! netjack_poll_deadline( input_fd, deadline ) ) + break; + + packet_cache_drain_socket(packcache, input_fd); + + if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) + if( got_frame == (framecnt - latency) ) + break; + } } else { - // normally: - // only drain socket. - packet_cache_drain_socket(packcache, input_fd); + // normally: + // only drain socket. + packet_cache_drain_socket(packcache, input_fd); } size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); @@ -376,15 +381,15 @@ process (jack_nframes_t nframes, void *arg) * to the JACK ports so it can be played. */ if (size == rx_bufsize) { - uint32_t *packet_buf_rx = rx_packet_ptr; - jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx; - packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); - // calculate how much time there would have been, if this packet was sent at the deadline. + uint32_t *packet_buf_rx = rx_packet_ptr; + jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx; + packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); + // calculate how much time there would have been, if this packet was sent at the deadline. - int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp); - packet_header_ntoh (pkthdr_rx); - deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency; - //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset ); + int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp); + packet_header_ntoh (pkthdr_rx); + deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency; + //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset ); if (cont_miss) { @@ -394,26 +399,26 @@ process (jack_nframes_t nframes, void *arg) render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes, dont_htonl_floats); - state_currentframe = framecnt; - state_recv_packet_queue_time = recv_time_offset; - state_connected = 1; + state_currentframe = framecnt; + state_recv_packet_queue_time = recv_time_offset; + state_connected = 1; sync_state = pkthdr_rx->sync_state; - packet_cache_release_packet( packcache, framecnt - latency ); + packet_cache_release_packet( packcache, framecnt - latency ); } /* Second alternative : we've received something that's not * as big as expected or we missed a packet. We render silence * to the ouput ports */ else { - jack_nframes_t latency_estimate; - if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) - //if( (state_latency == 0) || (latency_estimate < state_latency) ) - state_latency = latency_estimate; + jack_nframes_t latency_estimate; + if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) + //if( (state_latency == 0) || (latency_estimate < state_latency) ) + state_latency = latency_estimate; - // Set the counters up. - state_currentframe = framecnt; - //state_latency = framecnt - pkthdr->framecnt; - state_netxruns += 1; + // Set the counters up. + state_currentframe = framecnt; + //state_latency = framecnt - pkthdr->framecnt; + state_netxruns += 1; //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size); //printf ("Frame %d \tPacket missed or incomplete\n", framecnt); @@ -434,7 +439,7 @@ process (jack_nframes_t nframes, void *arg) chn++; } } - if( latency != 0 ) { + if (latency != 0) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); @@ -624,15 +629,15 @@ main (int argc, char *argv[]) case 'b': bitdepth = atoi (optarg); break; - case 'c': + case 'c': #if HAVE_CELT - bitdepth = 1000; + bitdepth = 1000; factor = atoi (optarg); #else - printf( "not built with celt supprt\n" ); + printf( "not built with celt support\n" ); exit(10); #endif - break; + break; case 'm': mtu = atoi (optarg); break; @@ -673,24 +678,24 @@ main (int argc, char *argv[]) outsockfd = socket (AF_INET, SOCK_DGRAM, 0); insockfd = socket (AF_INET, SOCK_DGRAM, 0); - if( (outsockfd == -1) || (insockfd == -1) ) { + if ((outsockfd == -1) || (insockfd == -1)) { fprintf (stderr, "cant open sockets\n" ); return 1; } init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); - if(bind_port) { + if (bind_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { - fprintf (stderr, "bind failure\n" ); - } + fprintf (stderr, "bind failure\n" ); + } } - if(reply_port) + if (reply_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { - fprintf (stderr, "bind failure\n" ); - } + fprintf (stderr, "bind failure\n" ); + } } /* try to become a client of the JACK server */ @@ -711,9 +716,9 @@ main (int argc, char *argv[]) alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi); if( bitdepth == 1000 ) - net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; + net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ; else - net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); + net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); @@ -757,26 +762,26 @@ main (int argc, char *argv[]) if (statecopy_connected) { - if (statecopy_netxruns != state_netxruns) { - statecopy_netxruns = state_netxruns; - printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", + if (statecopy_netxruns != state_netxruns) { + statecopy_netxruns = state_netxruns; + printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", client_name, state_currentframe, statecopy_netxruns, 100*statecopy_netxruns/state_currentframe, state_recv_packet_queue_time); - fflush(stdout); + fflush(stdout); } - } - else + } + else + { + if (statecopy_latency != state_latency) { - if (statecopy_latency != state_latency) - { - statecopy_latency = state_latency; - if (statecopy_latency > 1) - printf ("current latency %d\n", statecopy_latency); - fflush(stdout); + statecopy_latency = state_latency; + if (statecopy_latency > 1) + printf ("current latency %d\n", statecopy_latency); + fflush(stdout); } } } diff --git a/example-clients/server_control.cpp b/example-clients/server_control.cpp index 64ec977c..46efa1bc 100644 --- a/example-clients/server_control.cpp +++ b/example-clients/server_control.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2008 Grame - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -74,23 +74,23 @@ jackctl_get_parameter( static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) { switch (type) { - + case JackParamInt: printf("parameter value = %d\n", value.i); break; - + case JackParamUInt: printf("parameter value = %u\n", value.ui); break; - + case JackParamChar: printf("parameter value = %c\n", value.c); break; - + case JackParamString: printf("parameter value = %s\n", value.str); break; - + case JackParamBool: printf("parameter value = %d\n", value.b); break; @@ -115,7 +115,7 @@ static void print_driver(jackctl_driver_t * driver) printf("\n--------------------------\n"); printf("driver = %s\n", jackctl_driver_get_name(driver)); printf("-------------------------- \n"); - print_parameters(jackctl_driver_get_parameters(driver)); + print_parameters(jackctl_driver_get_parameters(driver)); } static void print_internal(jackctl_internal_t * internal) @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) {"driver", 1, 0, 'd'}, {"client", 1, 0, 'c'}, }; - + while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'd': @@ -166,10 +166,10 @@ int main(int argc, char *argv[]) exit(0); } } - + server = jackctl_server_create(NULL, NULL); parameters = jackctl_server_get_parameters(server); - + /* jackctl_parameter_t* param; union jackctl_parameter_value value; @@ -179,58 +179,63 @@ int main(int argc, char *argv[]) jackctl_parameter_set_value(param, &value); } */ - + printf("\n========================== \n"); printf("List of server parameters \n"); printf("========================== \n"); - + print_parameters(parameters); - + printf("\n========================== \n"); printf("List of drivers \n"); printf("========================== \n"); - + drivers = jackctl_server_get_drivers_list(server); node_ptr = drivers; while (node_ptr != NULL) { print_driver((jackctl_driver_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } - + printf("\n========================== \n"); printf("List of internal clients \n"); printf("========================== \n"); - + internals = jackctl_server_get_internals_list(server); node_ptr = internals; while (node_ptr != NULL) { print_internal((jackctl_internal_t *)node_ptr->data); node_ptr = jack_slist_next(node_ptr); } - - jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); + + // No error checking in this simple example... + + jackctl_server_open(server, jackctl_server_get_driver(server, driver_name)); + jackctl_server_start(server); + jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); - + /* // Switch master test - + jackctl_driver_t* master; - + usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "coreaudio"); jackctl_server_switch_master(server, master); - + usleep(5000000); printf("jackctl_server_load_master\n"); master = jackctl_server_get_driver(server, "dummy"); jackctl_server_switch_master(server, master); - + */ - + signals = jackctl_setup_signals(0); jackctl_wait_signals(signals); - + jackctl_server_stop(server); + jackctl_server_close(server); jackctl_server_destroy(server); return 0; } diff --git a/example-clients/wscript b/example-clients/wscript index 54a6a599..d32c1f75 100644 --- a/example-clients/wscript +++ b/example-clients/wscript @@ -63,7 +63,7 @@ def configure(conf): conf.env['BUILD_EXAMPLE_CLIENT_REC'] = conf.is_defined('HAVE_SNDFILE') - conf.env['BUILD_EXAMPLE_ALSA_IO'] = conf.is_defined('HAVE_SAMPLERATE') and conf.is_defined('HAVE_ALSA') + conf.env['BUILD_EXAMPLE_ALSA_IO'] = conf.is_defined('HAVE_SAMPLERATE') and conf.env['BUILD_DRIVER_ALSA'] def build(bld): if bld.env['IS_LINUX']: @@ -137,21 +137,21 @@ def build(bld): prog.target = 'jack_netsource' if bld.env['IS_LINUX'] and bld.env['BUILD_EXAMPLE_ALSA_IO']: - prog = bld.new_task_gen('cc', 'program') - prog.includes = os_incdir + ['../common/jack', '../common'] - prog.source = ['alsa_in.c', '../common/memops.c'] - prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") - prog.uselib = 'ALSA SAMPLERATE' - prog.uselib_local = 'clientlib' - prog.target = 'alsa_in' - - prog = bld.new_task_gen('cc', 'program') - prog.includes = os_incdir + ['../common/jack', '../common'] - prog.source = ['alsa_out.c', '../common/memops.c'] - prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") - prog.uselib = 'ALSA SAMPLERATE' - prog.uselib_local = 'clientlib' - prog.target = 'alsa_out' + prog = bld.new_task_gen('cc', 'program') + prog.includes = os_incdir + ['../common/jack', '../common'] + prog.source = ['alsa_in.c', '../common/memops.c'] + prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") + prog.uselib = 'ALSA SAMPLERATE' + prog.uselib_local = 'clientlib' + prog.target = 'alsa_in' + + prog = bld.new_task_gen('cc', 'program') + prog.includes = os_incdir + ['../common/jack', '../common'] + prog.source = ['alsa_out.c', '../common/memops.c'] + prog.env.append_value("CCFLAGS", "-DNO_JACK_ERROR") + prog.uselib = 'ALSA SAMPLERATE' + prog.uselib_local = 'clientlib' + prog.target = 'alsa_out' for example_lib, example_lib_source in example_libs.items(): lib = bld.new_task_gen('cc', 'shlib') diff --git a/linux/JackLinuxTime.c b/linux/JackLinuxTime.c index d8b474eb..93f7f03f 100644 --- a/linux/JackLinuxTime.c +++ b/linux/JackLinuxTime.c @@ -14,7 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software +along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -82,7 +82,7 @@ static int jack_hpet_init () } /* this assumes period to be constant. if needed, - it can be moved to the clock access function + it can be moved to the clock access function */ hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD)); hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS)); @@ -93,7 +93,7 @@ static int jack_hpet_init () return 0; } -static jack_time_t jack_get_microseconds_from_hpet (void) +static jack_time_t jack_get_microseconds_from_hpet (void) { hpet_counter_t hpet_counter; long double hpet_time; @@ -116,7 +116,7 @@ static int jack_hpet_init () return -1; } -static jack_time_t jack_get_microseconds_from_hpet (void) +static jack_time_t jack_get_microseconds_from_hpet (void) { /* never called */ return 0; @@ -168,7 +168,7 @@ static jack_time_t jack_get_mhz (void) ret = sscanf(buf, "bogomips per cpu: %" SCNu64, &mhz); #else /* MIPS, ARM, alpha */ ret = sscanf(buf, "BogoMIPS : %" SCNu64, &mhz); -#endif +#endif if (ret == 1) { @@ -182,7 +182,7 @@ static jack_time_t jack_get_mhz (void) #ifndef HAVE_CLOCK_GETTIME -static jack_time_t jack_get_microseconds_from_system (void) +static jack_time_t jack_get_microseconds_from_system (void) { jack_time_t jackTime; struct timeval tv; @@ -194,7 +194,7 @@ static jack_time_t jack_get_microseconds_from_system (void) #else -static jack_time_t jack_get_microseconds_from_system (void) +static jack_time_t jack_get_microseconds_from_system (void) { jack_time_t jackTime; struct timespec time; @@ -208,7 +208,7 @@ static jack_time_t jack_get_microseconds_from_system (void) #endif /* HAVE_CLOCK_GETTIME */ -SERVER_EXPORT void JackSleep(long usec) +SERVER_EXPORT void JackSleep(long usec) { usleep(usec); } @@ -266,3 +266,9 @@ SERVER_EXPORT jack_time_t GetMicroSeconds() { return _jack_get_microseconds(); } + +SERVER_EXPORT jack_time_t jack_get_microseconds() +{ + return _jack_get_microseconds(); +} + diff --git a/linux/alsa/JackAlsaAdapter.cpp b/linux/alsa/JackAlsaAdapter.cpp index a046e1f2..ba847851 100644 --- a/linux/alsa/JackAlsaAdapter.cpp +++ b/linux/alsa/JackAlsaAdapter.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #endif #include "JackAlsaAdapter.h" -#include "JackServerGlobals.h" +#include "JackGlobals.h" #include "JackEngineControl.h" namespace Jack @@ -104,7 +104,7 @@ namespace Jack fAudioInterface.longinfo(); //turn the thread realtime - fThread.AcquireRealTime ( JackServerGlobals::fInstance->GetEngineControl()->fClientPriority ); + fThread.AcquireRealTime(GetEngineControl()->fClientPriority); return 0; } @@ -154,7 +154,7 @@ namespace Jack //read data from audio interface if (fAudioInterface.read() < 0) return false; - + PushAndPull(fAudioInterface.fInputSoftChannels, fAudioInterface.fOutputSoftChannels, fAdaptedBufferSize); //write data to audio interface @@ -273,7 +273,7 @@ extern "C" strcpy ( desc->params[i].short_desc, "Number of playback channels (defaults to hardware max)" ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); - + i++; strcpy(desc->params[i].name, "quality"); desc->params[i].character = 'q'; @@ -281,7 +281,7 @@ extern "C" desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "ring-buffer"); desc->params[i].character = 'g'; diff --git a/linux/alsa/JackAlsaAdapter.h b/linux/alsa/JackAlsaAdapter.h index 8cdde0ee..e4fbad26 100644 --- a/linux/alsa/JackAlsaAdapter.h +++ b/linux/alsa/JackAlsaAdapter.h @@ -145,8 +145,8 @@ namespace Jack void* fOutputCardChannels[256]; //non-interleaved mod, floating point software buffers - float* fInputSoftChannels[256]; - float* fOutputSoftChannels[256]; + jack_default_audio_sample_t* fInputSoftChannels[256]; + jack_default_audio_sample_t* fOutputSoftChannels[256]; //public methods --------------------------------------------------------- @@ -165,12 +165,12 @@ namespace Jack return fBuffering; } - float** inputSoftChannels() + jack_default_audio_sample_t** inputSoftChannels() { return fInputSoftChannels; } - float** outputSoftChannels() + jack_default_audio_sample_t** outputSoftChannels() { return fOutputSoftChannels; } @@ -182,10 +182,10 @@ namespace Jack fInputParams = 0; fOutputParams = 0; fPeriod = 2; - + fInputCardBuffer = 0; fOutputCardBuffer = 0; - + for ( int i = 0; i < 256; i++ ) { fInputCardChannels[i] = 0; @@ -222,18 +222,18 @@ namespace Jack //get hardware input parameters check_error ( snd_pcm_hw_params_malloc ( &fInputParams ) ); setAudioParams ( fInputDevice, fInputParams ); - + //get hardware output parameters check_error ( snd_pcm_hw_params_malloc ( &fOutputParams ) ) setAudioParams ( fOutputDevice, fOutputParams ); - + // set the number of physical input and output channels close to what we need fCardInputs = fSoftInputs; fCardOutputs = fSoftOutputs; - + snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs); snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs); - + //set input/output param check_error ( snd_pcm_hw_params ( fInputDevice, fInputParams ) ); check_error ( snd_pcm_hw_params ( fOutputDevice, fOutputParams ) ); @@ -260,14 +260,14 @@ namespace Jack for ( unsigned int i = 0; i < fSoftInputs; i++ ) { - fInputSoftChannels[i] = ( float* ) aligned_calloc ( fBuffering, sizeof ( float ) ); + fInputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) ); for ( int j = 0; j < fBuffering; j++ ) fInputSoftChannels[i][j] = 0.0; } for ( unsigned int i = 0; i < fSoftOutputs; i++ ) { - fOutputSoftChannels[i] = ( float* ) aligned_calloc ( fBuffering, sizeof ( float ) ); + fOutputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) ); for ( int j = 0; j < fBuffering; j++ ) fOutputSoftChannels[i][j] = 0.0; } @@ -376,14 +376,14 @@ namespace Jack short* buffer16b = ( short* ) fInputCardBuffer; for ( s = 0; s < fBuffering; s++ ) for ( c = 0; c < fCardInputs; c++ ) - fInputSoftChannels[c][s] = float ( buffer16b[c + s*fCardInputs] ) * ( 1.0/float ( SHRT_MAX ) ); + fInputSoftChannels[c][s] = jack_default_audio_sample_t(buffer16b[c + s*fCardInputs]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX)); } else // SND_PCM_FORMAT_S32 { int32_t* buffer32b = ( int32_t* ) fInputCardBuffer; for ( s = 0; s < fBuffering; s++ ) for ( c = 0; c < fCardInputs; c++ ) - fInputSoftChannels[c][s] = float ( buffer32b[c + s*fCardInputs] ) * ( 1.0/float ( INT_MAX ) ); + fInputSoftChannels[c][s] = jack_default_audio_sample_t(buffer32b[c + s*fCardInputs]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX)); } break; case SND_PCM_ACCESS_RW_NONINTERLEAVED : @@ -400,7 +400,7 @@ namespace Jack { chan16b = ( short* ) fInputCardChannels[c]; for ( s = 0; s < fBuffering; s++ ) - fInputSoftChannels[c][s] = float ( chan16b[s] ) * ( 1.0/float ( SHRT_MAX ) ); + fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan16b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX)); } } else // SND_PCM_FORMAT_S32 @@ -410,7 +410,7 @@ namespace Jack { chan32b = ( int32_t* ) fInputCardChannels[c]; for ( s = 0; s < fBuffering; s++ ) - fInputSoftChannels[c][s] = float ( chan32b[s] ) * ( 1.0/float ( INT_MAX ) ); + fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan32b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX)); } } break; @@ -440,8 +440,8 @@ namespace Jack { for ( unsigned int c = 0; c < fCardOutputs; c++ ) { - float x = fOutputSoftChannels[c][f]; - buffer16b[c + f * fCardOutputs] = short ( max ( min ( x, 1.0 ), -1.0 ) * float ( SHRT_MAX ) ); + jack_default_audio_sample_t x = fOutputSoftChannels[c][f]; + buffer16b[c + f * fCardOutputs] = short(max(min (x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(SHRT_MAX)); } } } @@ -452,8 +452,8 @@ namespace Jack { for ( unsigned int c = 0; c < fCardOutputs; c++ ) { - float x = fOutputSoftChannels[c][f]; - buffer32b[c + f * fCardOutputs] = int32_t ( max ( min ( x, 1.0 ), -1.0 ) * float ( INT_MAX ) ); + jack_default_audio_sample_t x = fOutputSoftChannels[c][f]; + buffer32b[c + f * fCardOutputs] = int32_t(max(min(x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(INT_MAX)); } } } @@ -474,8 +474,8 @@ namespace Jack short* chan16b = ( short* ) fOutputCardChannels[c]; for ( f = 0; f < fBuffering; f++ ) { - float x = fOutputSoftChannels[c][f]; - chan16b[f] = short ( max ( min ( x,1.0 ), -1.0 ) * float ( SHRT_MAX ) ) ; + jack_default_audio_sample_t x = fOutputSoftChannels[c][f]; + chan16b[f] = short(max(min (x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(SHRT_MAX)); } } } @@ -486,8 +486,8 @@ namespace Jack int32_t* chan32b = ( int32_t* ) fOutputCardChannels[c]; for ( f = 0; f < fBuffering; f++ ) { - float x = fOutputSoftChannels[c][f]; - chan32b[f] = int32_t ( max ( min ( x,1.0 ),-1.0 ) * float ( INT_MAX ) ) ; + jack_default_audio_sample_t x = fOutputSoftChannels[c][f]; + chan32b[f] = int32_t(max(min(x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(INT_MAX)); } } } diff --git a/linux/alsa/JackAlsaDriver.cpp b/linux/alsa/JackAlsaDriver.cpp index fdf5a0cb..b42e9693 100644 --- a/linux/alsa/JackAlsaDriver.cpp +++ b/linux/alsa/JackAlsaDriver.cpp @@ -42,1459 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackLockedEngine.h" #include "JackPosixThread.h" #include "JackCompilerDeps.h" -#include "hammerfall.h" -#include "hdsp.h" -#include "ice1712.h" -#include "usx2y.h" -#include "generic.h" -#include "memops.h" #include "JackServerGlobals.h" - -//#define DEBUG_WAKEUP 1 - -namespace Jack -{ - -#define jack_get_microseconds GetMicroSeconds - -/* Delay (in process calls) before jackd will report an xrun */ -#define XRUN_REPORT_DELAY 0 - -void -JackAlsaDriver::alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) -{ - bitset_destroy (&driver->channels_done); - bitset_destroy (&driver->channels_not_done); - - if (driver->playback_addr) { - free (driver->playback_addr); - driver->playback_addr = 0; - } - - if (driver->capture_addr) { - free (driver->capture_addr); - driver->capture_addr = 0; - } - - if (driver->playback_interleave_skip) { - free (driver->playback_interleave_skip); - driver->playback_interleave_skip = NULL; - } - - if (driver->capture_interleave_skip) { - free (driver->capture_interleave_skip); - driver->capture_interleave_skip = NULL; - } - - if (driver->silent) { - free (driver->silent); - driver->silent = 0; - } - - if (driver->dither_state) { - free (driver->dither_state); - driver->dither_state = 0; - } -} - -int -JackAlsaDriver::alsa_driver_check_capabilities (alsa_driver_t *driver) -{ - return 0; -} - -static -char * -get_control_device_name (const char * device_name) -{ - char * ctl_name; - regex_t expression; - - regcomp(&expression, "(plug)?hw:[0-9](,[0-9])?", REG_ICASE | REG_EXTENDED); - - if (!regexec(&expression, device_name, 0, NULL, 0)) { - /* the user wants a hw or plughw device, the ctl name - * should be hw:x where x is the card number */ - - char tmp[5]; - strncpy(tmp, strstr(device_name, "hw"), 4); - tmp[4] = '\0'; - jack_info("control device %s",tmp); - ctl_name = strdup(tmp); - } else { - ctl_name = strdup(device_name); - } - - regfree(&expression); - - if (ctl_name == NULL) { - jack_error("strdup(\"%s\") failed.", ctl_name); - } - - return ctl_name; -} - -int -JackAlsaDriver::alsa_driver_check_card_type (alsa_driver_t *driver) -{ - int err; - snd_ctl_card_info_t *card_info; - char * ctl_name; - - snd_ctl_card_info_alloca (&card_info); - - ctl_name = get_control_device_name(driver->alsa_name_playback); - - // XXX: I don't know the "right" way to do this. Which to use - // driver->alsa_name_playback or driver->alsa_name_capture. - if ((err = snd_ctl_open (&driver->ctl_handle, ctl_name, 0)) < 0) { - jack_error ("control open \"%s\" (%s)", ctl_name, - snd_strerror(err)); - } else if ((err = snd_ctl_card_info(driver->ctl_handle, card_info)) < 0) { - jack_error ("control hardware info \"%s\" (%s)", - driver->alsa_name_playback, snd_strerror (err)); - snd_ctl_close (driver->ctl_handle); - } - - driver->alsa_driver = strdup(snd_ctl_card_info_get_driver (card_info)); - jack_info("Using ALSA driver %s running on card %i - %s", driver->alsa_driver, snd_ctl_card_info_get_card(card_info), snd_ctl_card_info_get_longname(card_info)); - - free(ctl_name); - return alsa_driver_check_capabilities (driver); -} - -int -JackAlsaDriver::alsa_driver_hammerfall_hardware (alsa_driver_t *driver) -{ - driver->hw = jack_alsa_hammerfall_hw_new (driver); - return 0; -} - -int -JackAlsaDriver::alsa_driver_hdsp_hardware (alsa_driver_t *driver) -{ - driver->hw = jack_alsa_hdsp_hw_new (driver); - return 0; -} - -int -JackAlsaDriver::alsa_driver_ice1712_hardware (alsa_driver_t *driver) -{ - driver->hw = jack_alsa_ice1712_hw_new (driver); - return 0; -} - -int -JackAlsaDriver::alsa_driver_usx2y_hardware (alsa_driver_t *driver) -{ - // TODO : will need so deeped redesign - // driver->hw = jack_alsa_usx2y_hw_new (driver); - return 0; -} - -int -JackAlsaDriver::alsa_driver_generic_hardware (alsa_driver_t *driver) -{ - driver->hw = jack_alsa_generic_hw_new (driver); - return 0; -} - -int -JackAlsaDriver::alsa_driver_hw_specific (alsa_driver_t *driver, int hw_monitoring, - int hw_metering) -{ - int err; - - if (!strcmp(driver->alsa_driver, "RME9652")) { - if ((err = alsa_driver_hammerfall_hardware (driver)) != 0) { - return err; - } - } else if (!strcmp(driver->alsa_driver, "H-DSP")) { - if ((err = alsa_driver_hdsp_hardware (driver)) != 0) { - return err; - } - } else if (!strcmp(driver->alsa_driver, "ICE1712")) { - if ((err = alsa_driver_ice1712_hardware (driver)) != 0) { - return err; - } - } /*else if (!strcmp(driver->alsa_driver, "USB US-X2Y")) { - if ((err = alsa_driver_usx2y_hardware (driver)) != 0) { - return err; - } - } */else { - if ((err = alsa_driver_generic_hardware (driver)) != 0) { - return err; - } - } - - if (driver->hw->capabilities & Cap_HardwareMonitoring) { - driver->has_hw_monitoring = TRUE; - /* XXX need to ensure that this is really FALSE or - * TRUE or whatever*/ - driver->hw_monitoring = hw_monitoring; - } else { - driver->has_hw_monitoring = FALSE; - driver->hw_monitoring = FALSE; - } - - if (driver->hw->capabilities & Cap_ClockLockReporting) { - driver->has_clock_sync_reporting = TRUE; - } else { - driver->has_clock_sync_reporting = FALSE; - } - - if (driver->hw->capabilities & Cap_HardwareMetering) { - driver->has_hw_metering = TRUE; - driver->hw_metering = hw_metering; - } else { - driver->has_hw_metering = FALSE; - driver->hw_metering = FALSE; - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) -{ - if (driver->playback_handle) { - if (SND_PCM_FORMAT_FLOAT_LE == driver->playback_sample_format) { - if (driver->playback_interleaved) { - driver->channel_copy = memcpy_interleave_d32_s32; - } else { - driver->channel_copy = memcpy_fake; - } - driver->read_via_copy = sample_move_floatLE_sSs; - driver->write_via_copy = sample_move_dS_floatLE; - } else { - - switch (driver->playback_sample_bytes) { - case 2: - if (driver->playback_interleaved) { - driver->channel_copy = memcpy_interleave_d16_s16; - } else { - driver->channel_copy = memcpy_fake; - } - - switch (driver->dither) { - case Rectangular: - jack_info("Rectangular dithering at 16 bits"); - driver->write_via_copy = driver->quirk_bswap? - sample_move_dither_rect_d16_sSs: - sample_move_dither_rect_d16_sS; - break; - - case Triangular: - jack_info("Triangular dithering at 16 bits"); - driver->write_via_copy = driver->quirk_bswap? - sample_move_dither_tri_d16_sSs: - sample_move_dither_tri_d16_sS; - break; - - case Shaped: - jack_info("Noise-shaped dithering at 16 bits"); - driver->write_via_copy = driver->quirk_bswap? - sample_move_dither_shaped_d16_sSs: - sample_move_dither_shaped_d16_sS; - break; - - default: - driver->write_via_copy = driver->quirk_bswap? - sample_move_d16_sSs : - sample_move_d16_sS; - break; - } - break; - - case 3: /* NO DITHER */ - if (driver->playback_interleaved) { - driver->channel_copy = memcpy_interleave_d24_s24; - } else { - driver->channel_copy = memcpy_fake; - } - - driver->write_via_copy = driver->quirk_bswap? - sample_move_d24_sSs: - sample_move_d24_sS; - - break; - - case 4: /* NO DITHER */ - if (driver->playback_interleaved) { - driver->channel_copy = memcpy_interleave_d32_s32; - } else { - driver->channel_copy = memcpy_fake; - } - - driver->write_via_copy = driver->quirk_bswap? - sample_move_d32u24_sSs: - sample_move_d32u24_sS; - break; - - default: - jack_error ("impossible sample width (%d) discovered!", - driver->playback_sample_bytes); - return -1; - } - } - } - - if (driver->capture_handle) { - switch (driver->capture_sample_bytes) { - case 2: - driver->read_via_copy = driver->quirk_bswap? - sample_move_dS_s16s: - sample_move_dS_s16; - break; - case 3: - driver->read_via_copy = driver->quirk_bswap? - sample_move_dS_s24s: - sample_move_dS_s24; - break; - case 4: - driver->read_via_copy = driver->quirk_bswap? - sample_move_dS_s32u24s: - sample_move_dS_s32u24; - break; - } - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name, - const char *stream_name, - snd_pcm_t *handle, - snd_pcm_hw_params_t *hw_params, - snd_pcm_sw_params_t *sw_params, - unsigned int *nperiodsp, - unsigned long *nchns, - unsigned long sample_width) -{ - int err, format; - unsigned int frame_rate; - snd_pcm_uframes_t stop_th; - static struct { - char Name[32]; - snd_pcm_format_t format; - int swapped; - } formats[] = { - {"32bit float little-endian", SND_PCM_FORMAT_FLOAT_LE}, - {"32bit integer little-endian", SND_PCM_FORMAT_S32_LE, IS_LE}, - {"32bit integer big-endian", SND_PCM_FORMAT_S32_BE, IS_BE}, - {"24bit little-endian", SND_PCM_FORMAT_S24_3LE, IS_LE}, - {"24bit big-endian", SND_PCM_FORMAT_S24_3BE, IS_BE}, - {"16bit little-endian", SND_PCM_FORMAT_S16_LE, IS_LE}, - {"16bit big-endian", SND_PCM_FORMAT_S16_BE, IS_BE}, - }; -#define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) -#define FIRST_16BIT_FORMAT 5 - - if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { - jack_error ("ALSA: no playback configurations available (%s)", - snd_strerror (err)); - return -1; - } - - if ((err = snd_pcm_hw_params_set_periods_integer (handle, hw_params)) - < 0) { - jack_error ("ALSA: cannot restrict period size to integral" - " value."); - return -1; - } - - if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0) { - if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { - if ((err = snd_pcm_hw_params_set_access ( - handle, hw_params, - SND_PCM_ACCESS_MMAP_COMPLEX)) < 0) { - jack_error ("ALSA: mmap-based access is not possible" - " for the %s " - "stream of this audio interface", - stream_name); - return -1; - } - } - } - - format = (sample_width == 4) ? 0 : NUMFORMATS - 1; - - while (1) { - if ((err = snd_pcm_hw_params_set_format ( - handle, hw_params, formats[format].format)) < 0) { - - if ((sample_width == 4 - ? format++ >= NUMFORMATS - 1 - : format-- <= 0)) { - jack_error ("Sorry. The audio interface \"%s\"" - " doesn't support any of the" - " hardware sample formats that" - " JACK's alsa-driver can use.", - device_name); - return -1; - } - } else { - if (formats[format].swapped) { - driver->quirk_bswap = 1; - } else { - driver->quirk_bswap = 0; - } - jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); - break; - } - } - - frame_rate = driver->frame_rate ; - err = snd_pcm_hw_params_set_rate_near (handle, hw_params, - &frame_rate, NULL) ; - driver->frame_rate = frame_rate ; - if (err < 0) { - jack_error ("ALSA: cannot set sample/frame rate to %" - PRIu32 " for %s", driver->frame_rate, - stream_name); - return -1; - } - if (!*nchns) { - /*if not user-specified, try to find the maximum - * number of channels */ - unsigned int channels_max ; - err = snd_pcm_hw_params_get_channels_max (hw_params, - &channels_max); - *nchns = channels_max ; - - if (*nchns > 1024) { - - /* the hapless user is an unwitting victim of - the "default" ALSA PCM device, which can - support up to 16 million channels. since - they can't be bothered to set up a proper - default device, limit the number of - channels for them to a sane default. - */ - - jack_error ( -"You appear to be using the ALSA software \"plug\" layer, probably\n" -"a result of using the \"default\" ALSA device. This is less\n" -"efficient than it could be. Consider using a hardware device\n" -"instead rather than using the plug layer. Usually the name of the\n" -"hardware device that corresponds to the first sound card is hw:0\n" - ); - *nchns = 2; - } - } - - if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, - *nchns)) < 0) { - jack_error ("ALSA: cannot set channel count to %u for %s", - *nchns, stream_name); - return -1; - } - - if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, - driver->frames_per_cycle, - 0)) - < 0) { - jack_error ("ALSA: cannot set period size to %" PRIu32 - " frames for %s", driver->frames_per_cycle, - stream_name); - return -1; - } - - *nperiodsp = driver->user_nperiods; - snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL); - if (*nperiodsp < driver->user_nperiods) - *nperiodsp = driver->user_nperiods; - if (snd_pcm_hw_params_set_periods_near (handle, hw_params, - nperiodsp, NULL) < 0) { - jack_error ("ALSA: cannot set number of periods to %u for %s", - *nperiodsp, stream_name); - return -1; - } - - if (*nperiodsp < driver->user_nperiods) { - jack_error ("ALSA: got smaller periods %u than %u for %s", - *nperiodsp, (unsigned int) driver->user_nperiods, - stream_name); - return -1; - } - jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); -#if 0 - if (!jack_power_of_two(driver->frames_per_cycle)) { - jack_error("JACK: frames must be a power of two " - "(64, 512, 1024, ...)\n"); - return -1; - } -#endif - - if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params, - *nperiodsp * - driver->frames_per_cycle)) - < 0) { - jack_error ("ALSA: cannot set buffer length to %" PRIu32 - " for %s", - *nperiodsp * driver->frames_per_cycle, - stream_name); - return -1; - } - - if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { - jack_error ("ALSA: cannot set hardware parameters for %s", - stream_name); - return -1; - } - - snd_pcm_sw_params_current (handle, sw_params); - - if ((err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, - 0U)) < 0) { - jack_error ("ALSA: cannot set start mode for %s", stream_name); - return -1; - } - - stop_th = *nperiodsp * driver->frames_per_cycle; - if (driver->soft_mode) { - stop_th = (snd_pcm_uframes_t)-1; - } - - if ((err = snd_pcm_sw_params_set_stop_threshold ( - handle, sw_params, stop_th)) < 0) { - jack_error ("ALSA: cannot set stop mode for %s", - stream_name); - return -1; - } - - if ((err = snd_pcm_sw_params_set_silence_threshold ( - handle, sw_params, 0)) < 0) { - jack_error ("ALSA: cannot set silence threshold for %s", - stream_name); - return -1; - } - -#if 0 - jack_info ("set silence size to %lu * %lu = %lu", - driver->frames_per_cycle, *nperiodsp, - driver->frames_per_cycle * *nperiodsp); - - if ((err = snd_pcm_sw_params_set_silence_size ( - handle, sw_params, - driver->frames_per_cycle * *nperiodsp)) < 0) { - jack_error ("ALSA: cannot set silence size for %s", - stream_name); - return -1; - } -#endif - - if (handle == driver->playback_handle) - err = snd_pcm_sw_params_set_avail_min ( - handle, sw_params, - driver->frames_per_cycle - * (*nperiodsp - driver->user_nperiods + 1)); - else - err = snd_pcm_sw_params_set_avail_min ( - handle, sw_params, driver->frames_per_cycle); - - if (err < 0) { - jack_error ("ALSA: cannot set avail min for %s", stream_name); - return -1; - } - - if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { - jack_error ("ALSA: cannot set software parameters for %s\n", - stream_name); - return -1; - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_set_parameters (alsa_driver_t *driver, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate) -{ - int dir; - snd_pcm_uframes_t p_period_size = 0; - snd_pcm_uframes_t c_period_size = 0; - channel_t chn; - unsigned int pr = 0; - unsigned int cr = 0; - int err; - - driver->frame_rate = rate; - driver->frames_per_cycle = frames_per_cycle; - driver->user_nperiods = user_nperiods; - - jack_info ("configuring for %" PRIu32 "Hz, period = %" - PRIu32 " frames (%.1f ms), buffer = %" PRIu32 " periods", - rate, frames_per_cycle, (((float)frames_per_cycle / (float) rate) * 1000.0f), user_nperiods); - - if (driver->capture_handle) { - if (alsa_driver_configure_stream ( - driver, - driver->alsa_name_capture, - "capture", - driver->capture_handle, - driver->capture_hw_params, - driver->capture_sw_params, - &driver->capture_nperiods, - (long unsigned int*)&driver->capture_nchannels, - driver->capture_sample_bytes)) { - jack_error ("ALSA: cannot configure capture channel"); - return -1; - } - } - - if (driver->playback_handle) { - if (alsa_driver_configure_stream ( - driver, - driver->alsa_name_playback, - "playback", - driver->playback_handle, - driver->playback_hw_params, - driver->playback_sw_params, - &driver->playback_nperiods, - (long unsigned int*)&driver->playback_nchannels, - driver->playback_sample_bytes)) { - jack_error ("ALSA: cannot configure playback channel"); - return -1; - } - } - - /* check the rate, since thats rather important */ - - if (driver->playback_handle) { - snd_pcm_hw_params_get_rate (driver->playback_hw_params, - &pr, &dir); - } - - if (driver->capture_handle) { - snd_pcm_hw_params_get_rate (driver->capture_hw_params, - &cr, &dir); - } - - if (driver->capture_handle && driver->playback_handle) { - if (cr != pr) { - jack_error ("playback and capture sample rates do " - "not match (%d vs. %d)", pr, cr); - } - - /* only change if *both* capture and playback rates - * don't match requested certain hardware actually - * still works properly in full-duplex with slightly - * different rate values between adc and dac - */ - if (cr != driver->frame_rate && pr != driver->frame_rate) { - jack_error ("sample rate in use (%d Hz) does not " - "match requested rate (%d Hz)", - cr, driver->frame_rate); - driver->frame_rate = cr; - } - - } else if (driver->capture_handle && cr != driver->frame_rate) { - jack_error ("capture sample rate in use (%d Hz) does not " - "match requested rate (%d Hz)", - cr, driver->frame_rate); - driver->frame_rate = cr; - } else if (driver->playback_handle && pr != driver->frame_rate) { - jack_error ("playback sample rate in use (%d Hz) does not " - "match requested rate (%d Hz)", - pr, driver->frame_rate); - driver->frame_rate = pr; - } - - - /* check the fragment size, since thats non-negotiable */ - - if (driver->playback_handle) { - snd_pcm_access_t access; - - err = snd_pcm_hw_params_get_period_size ( - driver->playback_hw_params, &p_period_size, &dir); - err = snd_pcm_hw_params_get_format ( - driver->playback_hw_params, - &(driver->playback_sample_format)); - err = snd_pcm_hw_params_get_access (driver->playback_hw_params, - &access); - driver->playback_interleaved = - (access == SND_PCM_ACCESS_MMAP_INTERLEAVED) - || (access == SND_PCM_ACCESS_MMAP_COMPLEX); - - if (p_period_size != driver->frames_per_cycle) { - jack_error ("alsa_pcm: requested an interrupt every %" - PRIu32 - " frames but got %u frames for playback", - driver->frames_per_cycle, p_period_size); - return -1; - } - } - - if (driver->capture_handle) { - snd_pcm_access_t access; - - err = snd_pcm_hw_params_get_period_size ( - driver->capture_hw_params, &c_period_size, &dir); - err = snd_pcm_hw_params_get_format ( - driver->capture_hw_params, - &(driver->capture_sample_format)); - err = snd_pcm_hw_params_get_access (driver->capture_hw_params, - &access); - driver->capture_interleaved = - (access == SND_PCM_ACCESS_MMAP_INTERLEAVED) - || (access == SND_PCM_ACCESS_MMAP_COMPLEX); - - - if (c_period_size != driver->frames_per_cycle) { - jack_error ("alsa_pcm: requested an interrupt every %" - PRIu32 - " frames but got %uc frames for capture", - driver->frames_per_cycle, p_period_size); - return -1; - } - } - - driver->playback_sample_bytes = - snd_pcm_format_physical_width (driver->playback_sample_format) - / 8; - driver->capture_sample_bytes = - snd_pcm_format_physical_width (driver->capture_sample_format) - / 8; - - if (driver->playback_handle) { - switch (driver->playback_sample_format) { - case SND_PCM_FORMAT_FLOAT_LE: - case SND_PCM_FORMAT_S32_LE: - case SND_PCM_FORMAT_S24_3LE: - case SND_PCM_FORMAT_S24_3BE: - case SND_PCM_FORMAT_S16_LE: - case SND_PCM_FORMAT_S32_BE: - case SND_PCM_FORMAT_S16_BE: - break; - - default: - jack_error ("programming error: unhandled format " - "type for playback"); - return -1; - } - } - - if (driver->capture_handle) { - switch (driver->capture_sample_format) { - case SND_PCM_FORMAT_FLOAT_LE: - case SND_PCM_FORMAT_S32_LE: - case SND_PCM_FORMAT_S24_3LE: - case SND_PCM_FORMAT_S24_3BE: - case SND_PCM_FORMAT_S16_LE: - case SND_PCM_FORMAT_S32_BE: - case SND_PCM_FORMAT_S16_BE: - break; - - default: - jack_error ("programming error: unhandled format " - "type for capture"); - return -1; - } - } - - if (driver->playback_interleaved) { - const snd_pcm_channel_area_t *my_areas; - snd_pcm_uframes_t offset, frames; - if (snd_pcm_mmap_begin(driver->playback_handle, - &my_areas, &offset, &frames) < 0) { - jack_error ("ALSA: %s: mmap areas info error", - driver->alsa_name_playback); - return -1; - } - driver->interleave_unit = - snd_pcm_format_physical_width ( - driver->playback_sample_format) / 8; - } else { - driver->interleave_unit = 0; /* NOT USED */ - } - - if (driver->capture_interleaved) { - const snd_pcm_channel_area_t *my_areas; - snd_pcm_uframes_t offset, frames; - if (snd_pcm_mmap_begin(driver->capture_handle, - &my_areas, &offset, &frames) < 0) { - jack_error ("ALSA: %s: mmap areas info error", - driver->alsa_name_capture); - return -1; - } - } - - if (driver->playback_nchannels > driver->capture_nchannels) { - driver->max_nchannels = driver->playback_nchannels; - driver->user_nchannels = driver->capture_nchannels; - } else { - driver->max_nchannels = driver->capture_nchannels; - driver->user_nchannels = driver->playback_nchannels; - } - - if (alsa_driver_setup_io_function_pointers (driver) != 0) - return -1; - - /* Allocate and initialize structures that rely on the - channels counts. - - Set up the bit pattern that is used to record which - channels require action on every cycle. any bits that are - not set after the engine's process() call indicate channels - that potentially need to be silenced. - */ - - bitset_create (&driver->channels_done, driver->max_nchannels); - bitset_create (&driver->channels_not_done, driver->max_nchannels); - - if (driver->playback_handle) { - driver->playback_addr = (char **) - malloc (sizeof (char *) * driver->playback_nchannels); - memset (driver->playback_addr, 0, - sizeof (char *) * driver->playback_nchannels); - driver->playback_interleave_skip = (unsigned long *) - malloc (sizeof (unsigned long *) * driver->playback_nchannels); - memset (driver->playback_interleave_skip, 0, - sizeof (unsigned long *) * driver->playback_nchannels); - driver->silent = (unsigned long *) - malloc (sizeof (unsigned long) - * driver->playback_nchannels); - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - driver->silent[chn] = 0; - } - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - bitset_add (driver->channels_done, chn); - } - - driver->dither_state = (dither_state_t *) - calloc ( driver->playback_nchannels, - sizeof (dither_state_t)); - } - - if (driver->capture_handle) { - driver->capture_addr = (char **) - malloc (sizeof (char *) * driver->capture_nchannels); - memset (driver->capture_addr, 0, - sizeof (char *) * driver->capture_nchannels); - driver->capture_interleave_skip = (unsigned long *) - malloc (sizeof (unsigned long *) * driver->capture_nchannels); - memset (driver->capture_interleave_skip, 0, - sizeof (unsigned long *) * driver->capture_nchannels); - } - - driver->clock_sync_data = (ClockSyncStatus *) - malloc (sizeof (ClockSyncStatus) * driver->max_nchannels); - - driver->period_usecs = - (jack_time_t) floor ((((float) driver->frames_per_cycle) / - driver->frame_rate) * 1000000.0f); - driver->poll_timeout = (int) floor (1.5f * driver->period_usecs); - - // steph - /* - if (driver->engine) { - driver->engine->set_buffer_size (driver->engine, - driver->frames_per_cycle); - } - */ - return 0; -} - -int -JackAlsaDriver::alsa_driver_reset_parameters (alsa_driver_t *driver, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate) -{ - /* XXX unregister old ports ? */ - alsa_driver_release_channel_dependent_memory (driver); - return alsa_driver_set_parameters (driver, - frames_per_cycle, - user_nperiods, rate); -} - -int -JackAlsaDriver::alsa_driver_get_channel_addresses (alsa_driver_t *driver, - snd_pcm_uframes_t *capture_avail, - snd_pcm_uframes_t *playback_avail, - snd_pcm_uframes_t *capture_offset, - snd_pcm_uframes_t *playback_offset) -{ - unsigned long err; - channel_t chn; - - if (capture_avail) { - if ((err = snd_pcm_mmap_begin ( - driver->capture_handle, &driver->capture_areas, - (snd_pcm_uframes_t *) capture_offset, - (snd_pcm_uframes_t *) capture_avail)) < 0) { - jack_error ("ALSA: %s: mmap areas info error", - driver->alsa_name_capture); - return -1; - } - - for (chn = 0; chn < driver->capture_nchannels; chn++) { - const snd_pcm_channel_area_t *a = - &driver->capture_areas[chn]; - driver->capture_addr[chn] = (char *) a->addr - + ((a->first + a->step * *capture_offset) / 8); - driver->capture_interleave_skip[chn] = (unsigned long ) (a->step / 8); - } - } - - if (playback_avail) { - if ((err = snd_pcm_mmap_begin ( - driver->playback_handle, &driver->playback_areas, - (snd_pcm_uframes_t *) playback_offset, - (snd_pcm_uframes_t *) playback_avail)) < 0) { - jack_error ("ALSA: %s: mmap areas info error ", - driver->alsa_name_playback); - return -1; - } - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - const snd_pcm_channel_area_t *a = - &driver->playback_areas[chn]; - driver->playback_addr[chn] = (char *) a->addr - + ((a->first + a->step * *playback_offset) / 8); - driver->playback_interleave_skip[chn] = (unsigned long ) (a->step / 8); - } - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_start (alsa_driver_t *driver) -{ - int err; - snd_pcm_uframes_t poffset, pavail; - channel_t chn; - - driver->poll_last = 0; - driver->poll_next = 0; - - if (driver->playback_handle) { - if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) { - jack_error ("ALSA: prepare error for playback on " - "\"%s\" (%s)", driver->alsa_name_playback, - snd_strerror(err)); - return -1; - } - } - - if ((driver->capture_handle && driver->capture_and_playback_not_synced) - || !driver->playback_handle) { - if ((err = snd_pcm_prepare (driver->capture_handle)) < 0) { - jack_error ("ALSA: prepare error for capture on \"%s\"" - " (%s)", driver->alsa_name_capture, - snd_strerror(err)); - return -1; - } - } - - if (driver->hw_monitoring) { - if (driver->input_monitor_mask || driver->all_monitor_in) { - if (driver->all_monitor_in) { - driver->hw->set_input_monitor_mask (driver->hw, ~0U); - } else { - driver->hw->set_input_monitor_mask ( - driver->hw, driver->input_monitor_mask); - } - } else { - driver->hw->set_input_monitor_mask (driver->hw, - driver->input_monitor_mask); - } - } - - if (driver->playback_handle) { - driver->playback_nfds = - snd_pcm_poll_descriptors_count (driver->playback_handle); - } else { - driver->playback_nfds = 0; - } - - if (driver->capture_handle) { - driver->capture_nfds = - snd_pcm_poll_descriptors_count (driver->capture_handle); - } else { - driver->capture_nfds = 0; - } - - if (driver->pfd) { - free (driver->pfd); - } - - driver->pfd = (struct pollfd *) - malloc (sizeof (struct pollfd) * - (driver->playback_nfds + driver->capture_nfds + 2)); - - if (driver->midi && !driver->xrun_recovery) - (driver->midi->start)(driver->midi); - - if (driver->playback_handle) { - /* fill playback buffer with zeroes, and mark - all fragments as having data. - */ - - pavail = snd_pcm_avail_update (driver->playback_handle); - - if (pavail != - driver->frames_per_cycle * driver->playback_nperiods) { - jack_error ("ALSA: full buffer not available at start"); - return -1; - } - - if (alsa_driver_get_channel_addresses (driver, - 0, &pavail, 0, &poffset)) { - return -1; - } - - /* XXX this is cheating. ALSA offers no guarantee that - we can access the entire buffer at any one time. It - works on most hardware tested so far, however, buts - its a liability in the long run. I think that - alsa-lib may have a better function for doing this - here, where the goal is to silence the entire - buffer. - */ - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - alsa_driver_silence_on_channel ( - driver, chn, - driver->user_nperiods - * driver->frames_per_cycle); - } - - snd_pcm_mmap_commit (driver->playback_handle, poffset, - driver->user_nperiods - * driver->frames_per_cycle); - - if ((err = snd_pcm_start (driver->playback_handle)) < 0) { - jack_error ("ALSA: could not start playback (%s)", - snd_strerror (err)); - return -1; - } - } - - if ((driver->capture_handle && driver->capture_and_playback_not_synced) - || !driver->playback_handle) { - if ((err = snd_pcm_start (driver->capture_handle)) < 0) { - jack_error ("ALSA: could not start capture (%s)", - snd_strerror (err)); - return -1; - } - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_stop (alsa_driver_t *driver) -{ - int err; - //JSList* node; - //int chn; - - /* silence all capture port buffers, because we might - be entering offline mode. - */ - - // steph - /* - for (chn = 0, node = driver->capture_ports; node; - node = jack_slist_next (node), chn++) { - - jack_port_t* port; - char* buf; - jack_nframes_t nframes = driver->engine->control->buffer_size; - - port = (jack_port_t *) node->data; - buf = jack_port_get_buffer (port, nframes); - memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes); - } - */ - - for (int i = 0; i < fPlaybackChannels; i++) { - jack_default_audio_sample_t* buf = - (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], fEngineControl->fBufferSize); - memset (buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize); - } - - if (driver->playback_handle) { - if ((err = snd_pcm_drop (driver->playback_handle)) < 0) { - jack_error ("ALSA: channel flush for playback " - "failed (%s)", snd_strerror (err)); - return -1; - } - } - - if (!driver->playback_handle - || driver->capture_and_playback_not_synced) { - if (driver->capture_handle) { - if ((err = snd_pcm_drop (driver->capture_handle)) < 0) { - jack_error ("ALSA: channel flush for " - "capture failed (%s)", - snd_strerror (err)); - return -1; - } - } - } - - if (driver->hw_monitoring) { - driver->hw->set_input_monitor_mask (driver->hw, 0); - } - - if (driver->midi && !driver->xrun_recovery) - (driver->midi->stop)(driver->midi); - - return 0; -} - -int -JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) -{ - int res; - - driver->xrun_recovery = 1; - if ((res = Stop()) == 0) - res = Start(); - driver->xrun_recovery = 0; - - if (res && driver->midi) - (driver->midi->stop)(driver->midi); - return res; -} - -int -JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs) -{ - snd_pcm_status_t *status; - int res; - - snd_pcm_status_alloca(&status); - - if (driver->capture_handle) { - if ((res = snd_pcm_status(driver->capture_handle, status)) - < 0) { - jack_error("status error: %s", snd_strerror(res)); - } - } else { - if ((res = snd_pcm_status(driver->playback_handle, status)) - < 0) { - jack_error("status error: %s", snd_strerror(res)); - } - } - - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED) { - jack_error("**** alsa_pcm: pcm in suspended state, resuming it" ); - if (driver->capture_handle) { - if ((res = snd_pcm_prepare(driver->capture_handle)) < 0) { - jack_error("error preparing after suspend: %s", snd_strerror(res)); - } - } else { - if ((res = snd_pcm_prepare(driver->playback_handle)) < 0) { - jack_error("error preparing after suspend: %s", snd_strerror(res)); - } - } - } - - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN - && driver->process_count > XRUN_REPORT_DELAY) { - struct timeval now, diff, tstamp; - driver->xrun_count++; - snd_pcm_status_get_tstamp(status,&now); - snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); - *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; - jack_error("**** alsa_pcm: xrun of at least %.3f msecs", *delayed_usecs / 1000.0); - } - - if (alsa_driver_restart (driver)) { - return -1; - } - return 0; -} - -void -JackAlsaDriver::alsa_driver_silence_untouched_channels (alsa_driver_t *driver, - jack_nframes_t nframes) -{ - channel_t chn; - jack_nframes_t buffer_frames = - driver->frames_per_cycle * driver->playback_nperiods; - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - if (bitset_contains (driver->channels_not_done, chn)) { - if (driver->silent[chn] < buffer_frames) { - alsa_driver_silence_on_channel_no_mark ( - driver, chn, nframes); - driver->silent[chn] += nframes; - } - } - } -} - -static int under_gdb = FALSE; - -jack_nframes_t -JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float - *delayed_usecs) -{ - snd_pcm_sframes_t avail = 0; - snd_pcm_sframes_t capture_avail = 0; - snd_pcm_sframes_t playback_avail = 0; - int xrun_detected = FALSE; - int need_capture; - int need_playback; - unsigned int i; - jack_time_t poll_enter; - jack_time_t poll_ret = 0; - - *status = -1; - *delayed_usecs = 0; - - need_capture = driver->capture_handle ? 1 : 0; - - if (extra_fd >= 0) { - need_playback = 0; - } else { - need_playback = driver->playback_handle ? 1 : 0; - } - - again: - - while (need_playback || need_capture) { - - int poll_result; - unsigned int ci = 0; - unsigned int nfds; - unsigned short revents; - - nfds = 0; - - if (need_playback) { - snd_pcm_poll_descriptors (driver->playback_handle, - &driver->pfd[0], - driver->playback_nfds); - nfds += driver->playback_nfds; - } - - if (need_capture) { - snd_pcm_poll_descriptors (driver->capture_handle, - &driver->pfd[nfds], - driver->capture_nfds); - ci = nfds; - nfds += driver->capture_nfds; - } - - /* ALSA doesn't set POLLERR in some versions of 0.9.X */ - - for (i = 0; i < nfds; i++) { - driver->pfd[i].events |= POLLERR; - } - - if (extra_fd >= 0) { - driver->pfd[nfds].fd = extra_fd; - driver->pfd[nfds].events = - POLLIN|POLLERR|POLLHUP|POLLNVAL; - nfds++; - } - - poll_enter = jack_get_microseconds (); - - if (poll_enter > driver->poll_next) { - /* - * This processing cycle was delayed past the - * next due interrupt! Do not account this as - * a wakeup delay: - */ - driver->poll_next = 0; - driver->poll_late++; - } - - poll_result = poll (driver->pfd, nfds, driver->poll_timeout); - if (poll_result < 0) { - - if (errno == EINTR) { - jack_info ("poll interrupt"); - // this happens mostly when run - // under gdb, or when exiting due to a signal - if (under_gdb) { - goto again; - } - *status = -2; - return 0; - } - - jack_error ("ALSA: poll call failed (%s)", - strerror (errno)); - *status = -3; - return 0; - - } - - poll_ret = jack_get_microseconds (); - - // steph - fBeginDateUst = poll_ret; - - if (extra_fd < 0) { - if (driver->poll_next && poll_ret > driver->poll_next) { - *delayed_usecs = poll_ret - driver->poll_next; - } - driver->poll_last = poll_ret; - driver->poll_next = poll_ret + driver->period_usecs; - // steph - /* - driver->engine->transport_cycle_start (driver->engine, - poll_ret); - */ - } - -#ifdef DEBUG_WAKEUP - jack_info ("%" PRIu64 ": checked %d fds, %" PRIu64 - " usecs since poll entered", poll_ret, nfds, - poll_ret - poll_enter); -#endif - - /* check to see if it was the extra FD that caused us - * to return from poll */ - - if (extra_fd >= 0) { - - if (driver->pfd[nfds-1].revents == 0) { - /* we timed out on the extra fd */ - - *status = -4; - return -1; - } - - /* if POLLIN was the only bit set, we're OK */ - - *status = 0; - if (driver->pfd[nfds-1].revents != POLLIN) { - jack_error("driver->pfd[nfds-1].revents == POLLIN"); - } - return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; - } - - if (need_playback) { - if (snd_pcm_poll_descriptors_revents - (driver->playback_handle, &driver->pfd[0], - driver->playback_nfds, &revents) < 0) { - jack_error ("ALSA: playback revents failed"); - *status = -6; - return 0; - } - - if (revents & POLLERR) { - xrun_detected = TRUE; - } - - if (revents & POLLOUT) { - need_playback = 0; -#ifdef DEBUG_WAKEUP - jack_info ("%" PRIu64 - " playback stream ready", - poll_ret); -#endif - } - } - - if (need_capture) { - if (snd_pcm_poll_descriptors_revents - (driver->capture_handle, &driver->pfd[ci], - driver->capture_nfds, &revents) < 0) { - jack_error ("ALSA: capture revents failed"); - *status = -6; - return 0; - } - - if (revents & POLLERR) { - xrun_detected = TRUE; - } - - if (revents & POLLIN) { - need_capture = 0; -#ifdef DEBUG_WAKEUP - jack_info ("%" PRIu64 - " capture stream ready", - poll_ret); -#endif - } - } - - if (poll_result == 0) { - jack_error ("ALSA: poll time out, polled for %" PRIu64 - " usecs", - poll_ret - poll_enter); - *status = -5; - return 0; - } - - } - - if (driver->capture_handle) { - if ((capture_avail = snd_pcm_avail_update ( - driver->capture_handle)) < 0) { - if (capture_avail == -EPIPE) { - xrun_detected = TRUE; - } else { - jack_error ("unknown ALSA avail_update return" - " value (%u)", capture_avail); - } - } - } else { - /* odd, but see min() computation below */ - capture_avail = INT_MAX; - } - - if (driver->playback_handle) { - if ((playback_avail = snd_pcm_avail_update ( - driver->playback_handle)) < 0) { - if (playback_avail == -EPIPE) { - xrun_detected = TRUE; - } else { - jack_error ("unknown ALSA avail_update return" - " value (%u)", playback_avail); - } - } - } else { - /* odd, but see min() computation below */ - playback_avail = INT_MAX; - } - - if (xrun_detected) { - *status = alsa_driver_xrun_recovery (driver, delayed_usecs); - return 0; - } - - *status = 0; - driver->last_wait_ust = poll_ret; - - avail = capture_avail < playback_avail ? capture_avail : playback_avail; - -#ifdef DEBUG_WAKEUP - jack_info ("wakeup complete, avail = %lu, pavail = %lu " - "cavail = %lu", - avail, playback_avail, capture_avail); -#endif - - /* mark all channels not done for now. read/write will change this */ - - bitset_copy (driver->channels_not_done, driver->channels_done); - - /* constrain the available count to the nearest (round down) number of - periods. - */ - - return avail - (avail % driver->frames_per_cycle); -} - +namespace Jack +{ int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size) { @@ -1514,574 +65,11 @@ int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size) return res; } -int -JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) -{ - snd_pcm_sframes_t contiguous; - snd_pcm_sframes_t nread; - snd_pcm_sframes_t offset; - jack_nframes_t orig_nframes; - jack_default_audio_sample_t* buf; - //channel_t chn; - //JSList *node; - //jack_port_t* port; - int err; - - // steph - /* - if (!driver->capture_handle || driver->engine->freewheeling) { - return 0; - } - */ - - if (nframes > driver->frames_per_cycle) { - return -1; - } - - if (driver->midi) - (driver->midi->read)(driver->midi, nframes); - - if (!driver->capture_handle) { - return 0; - } - - nread = 0; - contiguous = 0; - orig_nframes = nframes; - - while (nframes) { - - contiguous = nframes; - - if (alsa_driver_get_channel_addresses ( - driver, - (snd_pcm_uframes_t *) &contiguous, - (snd_pcm_uframes_t *) 0, - (snd_pcm_uframes_t *)&offset, 0) < 0) { - return -1; - } - - // steph - for (int chn = 0; chn < fCaptureChannels; chn++) { - if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) > 0) { - buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], orig_nframes); - alsa_driver_read_from_channel (driver, chn, buf + nread, contiguous); - } - } - - /* // steph - for (chn = 0, node = driver->capture_ports; node; - node = jack_slist_next (node), chn++) { - - port = (jack_port_t *) node->data; - - if (!jack_port_connected (port)) { - // no-copy optimization - continue; - } - buf = jack_port_get_buffer (port, orig_nframes); - alsa_driver_read_from_channel (driver, chn, - buf + nread, contiguous); - } - */ - - if ((err = snd_pcm_mmap_commit (driver->capture_handle, - offset, contiguous)) < 0) { - - jack_error ("ALSA: could not complete read of %" - PRIu32 " frames: error = %d\n", contiguous, err); - return -1; - } - - nframes -= contiguous; - nread += contiguous; - } - - return 0; -} - -int -JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) -{ - //channel_t chn; - //JSList *node; - //JSList *mon_node; - jack_default_audio_sample_t* buf; - jack_default_audio_sample_t* monbuf; - jack_nframes_t orig_nframes; - snd_pcm_sframes_t nwritten; - snd_pcm_sframes_t contiguous; - snd_pcm_sframes_t offset; - JackPort* port; - //jack_port_t *port; - int err; - - driver->process_count++; - - // steph - /* - if (!driver->playback_handle || driver->engine->freewheeling) { - return 0; - } - */ - if (!driver->playback_handle) { - return 0; - } - - if (nframes > driver->frames_per_cycle) { - return -1; - } - - if (driver->midi) - (driver->midi->write)(driver->midi, nframes); - - nwritten = 0; - contiguous = 0; - orig_nframes = nframes; - - /* check current input monitor request status */ - - driver->input_monitor_mask = 0; - - // steph - /* - for (chn = 0, node = driver->capture_ports; node; - node = jack_slist_next (node), chn++) { - if (((jack_port_t *) node->data)->shared->monitor_requests) { - driver->input_monitor_mask |= (1<GetPort(fCapturePortList[chn]); - if (port->MonitoringInput()) { - driver->input_monitor_mask |= (1 << chn); - } - } - - if (driver->hw_monitoring) { - if ((driver->hw->input_monitor_mask - != driver->input_monitor_mask) - && !driver->all_monitor_in) { - driver->hw->set_input_monitor_mask ( - driver->hw, driver->input_monitor_mask); - } - } - - while (nframes) { - - contiguous = nframes; - - if (alsa_driver_get_channel_addresses ( - driver, - (snd_pcm_uframes_t *) 0, - (snd_pcm_uframes_t *) &contiguous, - 0, (snd_pcm_uframes_t *)&offset) < 0) { - return -1; - } - - // steph - for (int chn = 0; chn < fPlaybackChannels; chn++) { - // Ouput ports - if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) { - buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes); - alsa_driver_write_to_channel (driver, chn, buf + nwritten, contiguous); - // Monitor ports - if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) { - monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes); - memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); - } - } - } - - /* - for (chn = 0, node = driver->playback_ports, mon_node=driver->monitor_ports; - node; - node = jack_slist_next (node), chn++) { - - port = (jack_port_t *) node->data; - - if (!jack_port_connected (port)) { - continue; - } - buf = jack_port_get_buffer (port, orig_nframes); - alsa_driver_write_to_channel (driver, chn, - buf + nwritten, contiguous); - - if (mon_node) { - port = (jack_port_t *) mon_node->data; - if (!jack_port_connected (port)) { - continue; - } - monbuf = jack_port_get_buffer (port, orig_nframes); - memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); - mon_node = jack_slist_next (mon_node); - } - } - */ - - if (!bitset_empty (driver->channels_not_done)) { - alsa_driver_silence_untouched_channels (driver, - contiguous); - } - - if ((err = snd_pcm_mmap_commit (driver->playback_handle, - offset, contiguous)) < 0) { - jack_error ("ALSA: could not complete playback of %" - PRIu32 " frames: error = %d", contiguous, err); - if (err != -EPIPE && err != -ESTRPIPE) - return -1; - } - - nframes -= contiguous; - nwritten += contiguous; - } - return 0; -} - -void -JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) -{ - JSList *node; - - if (driver->midi) - (driver->midi->destroy)(driver->midi); - - for (node = driver->clock_sync_listeners; node; - node = jack_slist_next (node)) { - free (node->data); - } - jack_slist_free (driver->clock_sync_listeners); - - if (driver->ctl_handle) { - snd_ctl_close (driver->ctl_handle); - driver->ctl_handle = 0; - } - - if (driver->capture_handle) { - snd_pcm_close (driver->capture_handle); - driver->capture_handle = 0; - } - - if (driver->playback_handle) { - snd_pcm_close (driver->playback_handle); - driver->capture_handle = 0; - } - - if (driver->capture_hw_params) { - snd_pcm_hw_params_free (driver->capture_hw_params); - driver->capture_hw_params = 0; - } - - if (driver->playback_hw_params) { - snd_pcm_hw_params_free (driver->playback_hw_params); - driver->playback_hw_params = 0; - } - - if (driver->capture_sw_params) { - snd_pcm_sw_params_free (driver->capture_sw_params); - driver->capture_sw_params = 0; - } - - if (driver->playback_sw_params) { - snd_pcm_sw_params_free (driver->playback_sw_params); - driver->playback_sw_params = 0; - } - - if (driver->pfd) { - free (driver->pfd); - } - - if (driver->hw) { - driver->hw->release (driver->hw); - driver->hw = 0; - } - free(driver->alsa_name_playback); - free(driver->alsa_name_capture); - free(driver->alsa_driver); - - alsa_driver_release_channel_dependent_memory (driver); - // steph - //jack_driver_nt_finish ((jack_driver_nt_t *) driver); - free (driver); -} - -jack_driver_t * -JackAlsaDriver::alsa_driver_new (const char *name, char *playback_alsa_device, - char *capture_alsa_device, - jack_client_t *client, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate, - int hw_monitoring, - int hw_metering, - int capturing, - int playing, - DitherAlgorithm dither, - int soft_mode, - int monitor, - int user_capture_nchnls, - int user_playback_nchnls, - int shorts_first, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency, - alsa_midi_t *midi) -{ - int err; - - alsa_driver_t *driver; - - jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 - "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", - playing ? playback_alsa_device : "-", - capturing ? capture_alsa_device : "-", - frames_per_cycle, user_nperiods, rate, - user_capture_nchnls,user_playback_nchnls, - hw_monitoring ? "hwmon": "nomon", - hw_metering ? "hwmeter":"swmeter", - soft_mode ? "soft-mode":"-", - shorts_first ? "16bit":"32bit"); - - driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); - - jack_driver_nt_init ((jack_driver_nt_t *) driver); - - driver->midi = midi; - driver->xrun_recovery = 0; - - //driver->nt_attach = (JackDriverNTAttachFunction) alsa_driver_attach; - //driver->nt_detach = (JackDriverNTDetachFunction) alsa_driver_detach; - //driver->read = (JackDriverReadFunction) alsa_driver_read; - //driver->write = (JackDriverReadFunction) alsa_driver_write; - //driver->null_cycle = (JackDriverNullCycleFunction) alsa_driver_null_cycle; - //driver->nt_bufsize = (JackDriverNTBufSizeFunction) alsa_driver_bufsize; - //driver->nt_start = (JackDriverNTStartFunction) alsa_driver_start; - //driver->nt_stop = (JackDriverNTStopFunction) alsa_driver_stop; - //driver->nt_run_cycle = (JackDriverNTRunCycleFunction) alsa_driver_run_cycle; - - driver->playback_handle = NULL; - driver->capture_handle = NULL; - driver->ctl_handle = 0; - driver->hw = 0; - driver->capture_and_playback_not_synced = FALSE; - driver->max_nchannels = 0; - driver->user_nchannels = 0; - driver->playback_nchannels = user_playback_nchnls; - driver->capture_nchannels = user_capture_nchnls; - driver->playback_sample_bytes = (shorts_first ? 2 : 4); - driver->capture_sample_bytes = (shorts_first ? 2 : 4); - driver->capture_frame_latency = capture_latency; - driver->playback_frame_latency = playback_latency; - - driver->playback_addr = 0; - driver->capture_addr = 0; - driver->playback_interleave_skip = NULL; - driver->capture_interleave_skip = NULL; - - driver->silent = 0; - driver->all_monitor_in = FALSE; - driver->with_monitor_ports = monitor; - - driver->clock_mode = ClockMaster; /* XXX is it? */ - driver->input_monitor_mask = 0; /* XXX is it? */ - - driver->capture_ports = 0; - driver->playback_ports = 0; - driver->monitor_ports = 0; - - driver->pfd = 0; - driver->playback_nfds = 0; - driver->capture_nfds = 0; - - driver->dither = dither; - driver->soft_mode = soft_mode; - - pthread_mutex_init (&driver->clock_sync_lock, 0); - driver->clock_sync_listeners = 0; - - driver->poll_late = 0; - driver->xrun_count = 0; - driver->process_count = 0; - - driver->alsa_name_playback = strdup (playback_alsa_device); - driver->alsa_name_capture = strdup (capture_alsa_device); - - if (alsa_driver_check_card_type (driver)) { - alsa_driver_delete (driver); - return NULL; - } - - alsa_driver_hw_specific (driver, hw_monitoring, hw_metering); - - if (playing) { - if (snd_pcm_open (&driver->playback_handle, - playback_alsa_device, - SND_PCM_STREAM_PLAYBACK, - SND_PCM_NONBLOCK) < 0) { - switch (errno) { - case EBUSY: - jack_error ("the playback device \"%s\" is " - "already in use. Please stop the" - " application using it and " - "run JACK again", - playback_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; - - case EPERM: - jack_error ("you do not have permission to open " - "the audio device \"%s\" for playback", - playback_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; - } - - driver->playback_handle = NULL; - } - - if (driver->playback_handle) { - snd_pcm_nonblock (driver->playback_handle, 0); - } - } - - if (capturing) { - if (snd_pcm_open (&driver->capture_handle, - capture_alsa_device, - SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK) < 0) { - switch (errno) { - case EBUSY: - jack_error ("the capture device \"%s\" is " - "already in use. Please stop the" - " application using it and " - "run JACK again", - capture_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; - - case EPERM: - jack_error ("you do not have permission to open " - "the audio device \"%s\" for capture", - capture_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; - } - - driver->capture_handle = NULL; - } - - if (driver->capture_handle) { - snd_pcm_nonblock (driver->capture_handle, 0); - } - } - - if (driver->playback_handle == NULL) { - if (playing) { - - /* they asked for playback, but we can't do it */ - - jack_error ("ALSA: Cannot open PCM device %s for " - "playback. Falling back to capture-only" - " mode", name); - - if (driver->capture_handle == NULL) { - /* can't do anything */ - alsa_driver_delete (driver); - return NULL; - } - - playing = FALSE; - } - } - - if (driver->capture_handle == NULL) { - if (capturing) { - - /* they asked for capture, but we can't do it */ - - jack_error ("ALSA: Cannot open PCM device %s for " - "capture. Falling back to playback-only" - " mode", name); - - if (driver->playback_handle == NULL) { - /* can't do anything */ - alsa_driver_delete (driver); - return NULL; - } - - capturing = FALSE; - } - } - - driver->playback_hw_params = 0; - driver->capture_hw_params = 0; - driver->playback_sw_params = 0; - driver->capture_sw_params = 0; - - if (driver->playback_handle) { - if ((err = snd_pcm_hw_params_malloc ( - &driver->playback_hw_params)) < 0) { - jack_error ("ALSA: could not allocate playback hw" - " params structure"); - alsa_driver_delete (driver); - return NULL; - } - - if ((err = snd_pcm_sw_params_malloc ( - &driver->playback_sw_params)) < 0) { - jack_error ("ALSA: could not allocate playback sw" - " params structure"); - alsa_driver_delete (driver); - return NULL; - } - } - - if (driver->capture_handle) { - if ((err = snd_pcm_hw_params_malloc ( - &driver->capture_hw_params)) < 0) { - jack_error ("ALSA: could not allocate capture hw" - " params structure"); - alsa_driver_delete (driver); - return NULL; - } - - if ((err = snd_pcm_sw_params_malloc ( - &driver->capture_sw_params)) < 0) { - jack_error ("ALSA: could not allocate capture sw" - " params structure"); - alsa_driver_delete (driver); - return NULL; - } - } - - if (alsa_driver_set_parameters (driver, frames_per_cycle, - user_nperiods, rate)) { - alsa_driver_delete (driver); - return NULL; - } - - driver->capture_and_playback_not_synced = FALSE; - - if (driver->capture_handle && driver->playback_handle) { - if (snd_pcm_link (driver->capture_handle, - driver->playback_handle) != 0) { - driver->capture_and_playback_not_synced = TRUE; - } - } - - driver->client = client; - return (jack_driver_t *) driver; -} - int JackAlsaDriver::Attach() { JackPort* port; int port_index; - unsigned long port_flags; + unsigned long port_flags = (unsigned long)CaptureDriverFlags; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; jack_latency_range_t range; @@ -2089,8 +77,6 @@ int JackAlsaDriver::Attach() assert(fCaptureChannels < DRIVER_PORT_NUM); assert(fPlaybackChannels < DRIVER_PORT_NUM); - port_flags = (unsigned long)CaptureDriverFlags; - alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; if (alsa_driver->has_hw_monitoring) @@ -2100,10 +86,10 @@ int JackAlsaDriver::Attach() JackAudioDriver::SetBufferSize(alsa_driver->frames_per_cycle); JackAudioDriver::SetSampleRate(alsa_driver->frame_rate); - jack_log("JackAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); + jack_log("JackAlsaDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); for (int i = 0; i < fCaptureChannels; i++) { - snprintf(alias, sizeof(alias) - 1, "%s:capture_%u", fAliasName, i + 1); + snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("driver: cannot register port for %s", name); @@ -2114,13 +100,13 @@ int JackAlsaDriver::Attach() range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; port->SetLatencyRange(JackCaptureLatency, &range); fCapturePortList[i] = port_index; - jack_log("JackAudioDriver::Attach fCapturePortList[i] %ld ", port_index); + jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_index); } port_flags = (unsigned long)PlaybackDriverFlags; for (int i = 0; i < fPlaybackChannels; i++) { - snprintf(alias, sizeof(alias) - 1, "%s:playback_%u", fAliasName, i + 1); + snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("driver: cannot register port for %s", name); @@ -2134,11 +120,11 @@ int JackAlsaDriver::Attach() port->SetLatencyRange(JackPlaybackLatency, &range); fPlaybackPortList[i] = port_index; - jack_log("JackAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index); + jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index); // Monitor ports if (fWithMonitorPorts) { - jack_log("Create monitor port "); + jack_log("Create monitor port"); snprintf(name, sizeof(name) - 1, "%s:monitor_%d", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error ("ALSA: cannot register monitor port for %s", name); @@ -2169,6 +155,35 @@ int JackAlsaDriver::Detach() return JackAudioDriver::Detach(); } +static char* get_control_device_name(const char * device_name) +{ + char * ctl_name; + regex_t expression; + + regcomp(&expression, "(plug)?hw:[0-9](,[0-9])?", REG_ICASE | REG_EXTENDED); + + if (!regexec(&expression, device_name, 0, NULL, 0)) { + /* the user wants a hw or plughw device, the ctl name + * should be hw:x where x is the card number */ + + char tmp[5]; + strncpy(tmp, strstr(device_name, "hw"), 4); + tmp[4] = '\0'; + jack_info("control device %s",tmp); + ctl_name = strdup(tmp); + } else { + ctl_name = strdup(device_name); + } + + regfree(&expression); + + if (ctl_name == NULL) { + jack_error("strdup(\"%s\") failed.", ctl_name); + } + + return ctl_name; +} + static int card_to_num(const char* device) { int err; @@ -2291,7 +306,9 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, int JackAlsaDriver::Close() { - JackAudioDriver::Close(); + // Generic audio driver close + int res = JackAudioDriver::Close(); + alsa_driver_delete((alsa_driver_t*)fDriver); if (JackServerGlobals::on_device_release != NULL) @@ -2310,18 +327,28 @@ int JackAlsaDriver::Close() } } - return 0; + return res; } int JackAlsaDriver::Start() { - JackAudioDriver::Start(); - return alsa_driver_start((alsa_driver_t *)fDriver); + int res = JackAudioDriver::Start(); + if (res >= 0) { + res = alsa_driver_start((alsa_driver_t *)fDriver); + if (res < 0) { + JackAudioDriver::Stop(); + } + } + return res; } int JackAlsaDriver::Stop() { - return alsa_driver_stop((alsa_driver_t *)fDriver); + int res = alsa_driver_stop((alsa_driver_t *)fDriver); + if (JackAudioDriver::Stop() < 0) { + res = -1; + } + return res; } int JackAlsaDriver::Read() @@ -2348,7 +375,7 @@ retry: } if (nframes != fEngineControl->fBufferSize) - jack_log("JackAlsaDriver::Read warning nframes = %ld", nframes); + jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes); // Has to be done before read JackDriver::CycleIncTime(); @@ -2361,40 +388,54 @@ int JackAlsaDriver::Write() return alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); } -void -JackAlsaDriver::jack_driver_init (jack_driver_t *driver) +void JackAlsaDriver::ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) { - memset (driver, 0, sizeof (*driver)); - - driver->attach = 0; - driver->detach = 0; - driver->write = 0; - driver->read = 0; - driver->null_cycle = 0; - driver->bufsize = 0; - driver->start = 0; - driver->stop = 0; + for (int chn = 0; chn < fCaptureChannels; chn++) { + if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) > 0) { + jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], orig_nframes); + alsa_driver_read_from_channel((alsa_driver_t *)fDriver, chn, buf + nread, contiguous); + } + } } -void -JackAlsaDriver::jack_driver_nt_init (jack_driver_nt_t * driver) +void JackAlsaDriver::MonitorInputAux() +{ + for (int chn = 0; chn < fCaptureChannels; chn++) { + JackPort* port = fGraphManager->GetPort(fCapturePortList[chn]); + if (port->MonitoringInput()) { + ((alsa_driver_t *)fDriver)->input_monitor_mask |= (1 << chn); + } + } +} + +void JackAlsaDriver::ClearOutputAux() +{ + for (int chn = 0; chn < fPlaybackChannels; chn++) { + jack_default_audio_sample_t* buf = + (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], fEngineControl->fBufferSize); + memset(buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize); + } +} + +void JackAlsaDriver::SetTimetAux(jack_time_t time) { - memset (driver, 0, sizeof (*driver)); - - jack_driver_init ((jack_driver_t *) driver); - - driver->attach = 0; - driver->detach = 0; - driver->bufsize = 0; - driver->stop = 0; - driver->start = 0; - - driver->nt_bufsize = 0; - driver->nt_start = 0; - driver->nt_stop = 0; - driver->nt_attach = 0; - driver->nt_detach = 0; - driver->nt_run_cycle = 0; + fBeginDateUst = time; +} + +void JackAlsaDriver::WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) +{ + for (int chn = 0; chn < fPlaybackChannels; chn++) { + // Output ports + if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) { + jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes); + alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), chn, buf + nwritten, contiguous); + // Monitor ports + if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) { + jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes); + memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); + } + } + } } int JackAlsaDriver::is_realtime() const @@ -2843,6 +884,8 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () return desc; } +static Jack::JackAlsaDriver* g_alsa_driver; + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { jack_nframes_t srate = 48000; @@ -2969,10 +1012,10 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke playback = TRUE; } - Jack::JackAlsaDriver* alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table); - Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(alsa_driver); + g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table); + Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver); // Special open for ALSA driver... - if (alsa_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor, + if (g_alsa_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor, user_capture_nchnls, user_playback_nchnls, shorts_first, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, midi_driver) == 0) { return threaded_driver; @@ -2982,6 +1025,37 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke } } +// Code to be used in alsa_driver.c + +void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) +{ + g_alsa_driver->ReadInputAux(orig_nframes, contiguous, nread); +} +void MonitorInput() +{ + g_alsa_driver->MonitorInputAux(); +} +void ClearOutput() +{ + g_alsa_driver->ClearOutputAux(); +} +void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) +{ + g_alsa_driver->WriteOutputAux(orig_nframes, contiguous, nwritten); +} +void SetTime(jack_time_t time) +{ + g_alsa_driver->SetTimetAux(time); +} + +int Restart() +{ + int res; + if ((res = g_alsa_driver->Stop()) == 0) + res = g_alsa_driver->Start(); + return res; +} + #ifdef __cplusplus } #endif diff --git a/linux/alsa/JackAlsaDriver.h b/linux/alsa/JackAlsaDriver.h index 8bab0e69..6d42b91a 100644 --- a/linux/alsa/JackAlsaDriver.h +++ b/linux/alsa/JackAlsaDriver.h @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackAudioDriver.h" #include "JackThreadedDriver.h" #include "JackTime.h" - #include "alsa_driver.h" namespace Jack @@ -42,87 +41,11 @@ class JackAlsaDriver : public JackAudioDriver jack_driver_t* fDriver; int fReservedCaptureDevice; int fReservedPlaybackDevice; - - void alsa_driver_release_channel_dependent_memory(alsa_driver_t *driver); - int alsa_driver_check_capabilities(alsa_driver_t *driver); - int alsa_driver_check_card_type(alsa_driver_t *driver); - int alsa_driver_hammerfall_hardware(alsa_driver_t *driver); - int alsa_driver_hdsp_hardware(alsa_driver_t *driver); - int alsa_driver_ice1712_hardware(alsa_driver_t *driver); - int alsa_driver_usx2y_hardware(alsa_driver_t *driver); - int alsa_driver_generic_hardware(alsa_driver_t *driver); - int alsa_driver_hw_specific(alsa_driver_t *driver, int hw_monitoring, - int hw_metering); - int alsa_driver_setup_io_function_pointers (alsa_driver_t *driver); - int alsa_driver_configure_stream(alsa_driver_t *driver, char *device_name, - const char *stream_name, - snd_pcm_t *handle, - snd_pcm_hw_params_t *hw_params, - snd_pcm_sw_params_t *sw_params, - unsigned int *nperiodsp, - unsigned long *nchns, - unsigned long sample_width); - - int alsa_driver_set_parameters(alsa_driver_t *driver, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate); - - int alsa_driver_reset_parameters(alsa_driver_t *driver, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate); - - int alsa_driver_get_channel_addresses(alsa_driver_t *driver, - snd_pcm_uframes_t *capture_avail, - snd_pcm_uframes_t *playback_avail, - snd_pcm_uframes_t *capture_offset, - snd_pcm_uframes_t *playback_offset); - - jack_driver_t * alsa_driver_new(const char *name, char *playback_alsa_device, - char *capture_alsa_device, - jack_client_t *client, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate, - int hw_monitoring, - int hw_metering, - int capturing, - int playing, - DitherAlgorithm dither, - int soft_mode, - int monitor, - int user_capture_nchnls, - int user_playback_nchnls, - int shorts_first, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency, - alsa_midi_t *midi); - - void alsa_driver_delete(alsa_driver_t *driver); - int alsa_driver_start(alsa_driver_t *driver); - int alsa_driver_stop(alsa_driver_t *driver); - int alsa_driver_read(alsa_driver_t *driver, jack_nframes_t nframes); - int alsa_driver_write(alsa_driver_t *driver, jack_nframes_t nframes); - - jack_nframes_t alsa_driver_wait(alsa_driver_t *driver, int extra_fd, int *status, float - *delayed_usecs); - - void alsa_driver_silence_untouched_channels(alsa_driver_t *driver, - jack_nframes_t nframes); - - int alsa_driver_restart(alsa_driver_t *driver); - int alsa_driver_xrun_recovery(alsa_driver_t *driver, float *delayed_usecs); - void jack_driver_init(jack_driver_t *driver); - void jack_driver_nt_init(jack_driver_nt_t * driver); public: JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) - : JackAudioDriver(name, alias, engine, table) - ,fDriver(NULL) - ,fReservedCaptureDevice(-1) - ,fReservedPlaybackDevice(-1) + : JackAudioDriver(name, alias, engine, table),fDriver(NULL),fReservedCaptureDevice(-1),fReservedPlaybackDevice(-1) {} virtual ~JackAlsaDriver() {} @@ -164,7 +87,13 @@ class JackAlsaDriver : public JackAudioDriver int SetBufferSize(jack_nframes_t buffer_size); - // jack api emulation for the midi driver + void ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); + void MonitorInputAux(); + void ClearOutputAux(); + void WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); + void SetTimetAux(jack_time_t time); + + // JACK API emulation for the midi driver int is_realtime() const; int create_thread(pthread_t *thread, int prio, int rt, void *(*start_func)(void*), void *arg); diff --git a/linux/alsa/alsa_driver.c b/linux/alsa/alsa_driver.c new file mode 100644 index 00000000..536cfb6c --- /dev/null +++ b/linux/alsa/alsa_driver.c @@ -0,0 +1,2172 @@ +/* -*- mode: c; c-file-style: "linux"; -*- */ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#define __STDC_FORMAT_MACROS // For inttypes.h to work in C++ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alsa_driver.h" +#include "hammerfall.h" +#include "hdsp.h" +#include "ice1712.h" +#include "usx2y.h" +#include "generic.h" +#include "memops.h" +#include "JackError.h" + +#include "alsa_midi_impl.h" + +extern void store_work_time (int); +extern void store_wait_time (int); +extern void show_wait_times (); +extern void show_work_times (); + +#undef DEBUG_WAKEUP + +/* Delay (in process calls) before jackd will report an xrun */ +#define XRUN_REPORT_DELAY 0 + +void +jack_driver_init (jack_driver_t *driver) +{ + memset (driver, 0, sizeof (*driver)); + + driver->attach = 0; + driver->detach = 0; + driver->write = 0; + driver->read = 0; + driver->null_cycle = 0; + driver->bufsize = 0; + driver->start = 0; + driver->stop = 0; +} + +void +jack_driver_nt_init (jack_driver_nt_t * driver) +{ + memset (driver, 0, sizeof (*driver)); + + jack_driver_init ((jack_driver_t *) driver); + + driver->attach = 0; + driver->detach = 0; + driver->bufsize = 0; + driver->stop = 0; + driver->start = 0; + + driver->nt_bufsize = 0; + driver->nt_start = 0; + driver->nt_stop = 0; + driver->nt_attach = 0; + driver->nt_detach = 0; + driver->nt_run_cycle = 0; +} + +static void +alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) +{ + bitset_destroy (&driver->channels_done); + bitset_destroy (&driver->channels_not_done); + + if (driver->playback_addr) { + free (driver->playback_addr); + driver->playback_addr = 0; + } + + if (driver->capture_addr) { + free (driver->capture_addr); + driver->capture_addr = 0; + } + + if (driver->playback_interleave_skip) { + free (driver->playback_interleave_skip); + driver->playback_interleave_skip = NULL; + } + + if (driver->capture_interleave_skip) { + free (driver->capture_interleave_skip); + driver->capture_interleave_skip = NULL; + } + + if (driver->silent) { + free (driver->silent); + driver->silent = 0; + } + + if (driver->dither_state) { + free (driver->dither_state); + driver->dither_state = 0; + } +} + +static int +alsa_driver_check_capabilities (alsa_driver_t *driver) +{ + return 0; +} + +static int +alsa_driver_check_card_type (alsa_driver_t *driver) +{ + int err; + snd_ctl_card_info_t *card_info; + char * ctl_name; + regex_t expression; + + snd_ctl_card_info_alloca (&card_info); + + regcomp(&expression,"(plug)?hw:[0-9](,[0-9])?",REG_ICASE|REG_EXTENDED); + + if (!regexec(&expression,driver->alsa_name_playback,0,NULL,0)) { + /* the user wants a hw or plughw device, the ctl name + * should be hw:x where x is the card number */ + + char tmp[5]; + strncpy(tmp,strstr(driver->alsa_name_playback,"hw"),4); + tmp[4]='\0'; + jack_info("control device %s",tmp); + ctl_name = strdup(tmp); + } else { + ctl_name = strdup(driver->alsa_name_playback); + } + + // XXX: I don't know the "right" way to do this. Which to use + // driver->alsa_name_playback or driver->alsa_name_capture. + if ((err = snd_ctl_open (&driver->ctl_handle, ctl_name, 0)) < 0) { + jack_error ("control open \"%s\" (%s)", ctl_name, + snd_strerror(err)); + } else if ((err = snd_ctl_card_info(driver->ctl_handle, card_info)) < 0) { + jack_error ("control hardware info \"%s\" (%s)", + driver->alsa_name_playback, snd_strerror (err)); + snd_ctl_close (driver->ctl_handle); + } + + driver->alsa_driver = strdup(snd_ctl_card_info_get_driver (card_info)); + + regfree(&expression); + free(ctl_name); + + return alsa_driver_check_capabilities (driver); +} + +static int +alsa_driver_hammerfall_hardware (alsa_driver_t *driver) +{ + driver->hw = jack_alsa_hammerfall_hw_new (driver); + return 0; +} + +static int +alsa_driver_hdsp_hardware (alsa_driver_t *driver) +{ + driver->hw = jack_alsa_hdsp_hw_new (driver); + return 0; +} + +static int +alsa_driver_ice1712_hardware (alsa_driver_t *driver) +{ + driver->hw = jack_alsa_ice1712_hw_new (driver); + return 0; +} + +// JACK2 +/* +static int +alsa_driver_usx2y_hardware (alsa_driver_t *driver) +{ + driver->hw = jack_alsa_usx2y_hw_new (driver); + return 0; +} +*/ + +static int +alsa_driver_generic_hardware (alsa_driver_t *driver) +{ + driver->hw = jack_alsa_generic_hw_new (driver); + return 0; +} + +static int +alsa_driver_hw_specific (alsa_driver_t *driver, int hw_monitoring, + int hw_metering) +{ + int err; + + if (!strcmp(driver->alsa_driver, "RME9652")) { + if ((err = alsa_driver_hammerfall_hardware (driver)) != 0) { + return err; + } + } else if (!strcmp(driver->alsa_driver, "H-DSP")) { + if ((err = alsa_driver_hdsp_hardware (driver)) !=0) { + return err; + } + } else if (!strcmp(driver->alsa_driver, "ICE1712")) { + if ((err = alsa_driver_ice1712_hardware (driver)) !=0) { + return err; + } + } + // JACK2 + /* + else if (!strcmp(driver->alsa_driver, "USB US-X2Y")) { + if ((err = alsa_driver_usx2y_hardware (driver)) !=0) { + return err; + } + } + */ + else { + if ((err = alsa_driver_generic_hardware (driver)) != 0) { + return err; + } + } + + if (driver->hw->capabilities & Cap_HardwareMonitoring) { + driver->has_hw_monitoring = TRUE; + /* XXX need to ensure that this is really FALSE or + * TRUE or whatever*/ + driver->hw_monitoring = hw_monitoring; + } else { + driver->has_hw_monitoring = FALSE; + driver->hw_monitoring = FALSE; + } + + if (driver->hw->capabilities & Cap_ClockLockReporting) { + driver->has_clock_sync_reporting = TRUE; + } else { + driver->has_clock_sync_reporting = FALSE; + } + + if (driver->hw->capabilities & Cap_HardwareMetering) { + driver->has_hw_metering = TRUE; + driver->hw_metering = hw_metering; + } else { + driver->has_hw_metering = FALSE; + driver->hw_metering = FALSE; + } + + return 0; +} + +static void +alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) +{ + if (driver->playback_handle) { + if (SND_PCM_FORMAT_FLOAT_LE == driver->playback_sample_format) { + driver->write_via_copy = sample_move_dS_floatLE; + } else { + switch (driver->playback_sample_bytes) { + case 2: + switch (driver->dither) { + case Rectangular: + jack_info("Rectangular dithering at 16 bits"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_rect_d16_sSs: + sample_move_dither_rect_d16_sS; + break; + + case Triangular: + jack_info("Triangular dithering at 16 bits"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_tri_d16_sSs: + sample_move_dither_tri_d16_sS; + break; + + case Shaped: + jack_info("Noise-shaped dithering at 16 bits"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_shaped_d16_sSs: + sample_move_dither_shaped_d16_sS; + break; + + default: + driver->write_via_copy = driver->quirk_bswap? + sample_move_d16_sSs : + sample_move_d16_sS; + break; + } + break; + + case 3: /* NO DITHER */ + driver->write_via_copy = driver->quirk_bswap? + sample_move_d24_sSs: + sample_move_d24_sS; + + break; + + case 4: /* NO DITHER */ + driver->write_via_copy = driver->quirk_bswap? + sample_move_d32u24_sSs: + sample_move_d32u24_sS; + break; + + default: + jack_error ("impossible sample width (%d) discovered!", + driver->playback_sample_bytes); + exit (1); + } + } + } + + if (driver->capture_handle) { + if (SND_PCM_FORMAT_FLOAT_LE == driver->capture_sample_format) { + driver->read_via_copy = sample_move_floatLE_sSs; + } else { + switch (driver->capture_sample_bytes) { + case 2: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s16s: + sample_move_dS_s16; + break; + case 3: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s24s: + sample_move_dS_s24; + break; + case 4: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s32u24s: + sample_move_dS_s32u24; + break; + } + } + } +} + +static int +alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name, + const char *stream_name, + snd_pcm_t *handle, + snd_pcm_hw_params_t *hw_params, + snd_pcm_sw_params_t *sw_params, + unsigned int *nperiodsp, + channel_t *nchns, + unsigned long sample_width) +{ + int err, format; + unsigned int frame_rate; + snd_pcm_uframes_t stop_th; + static struct { + char Name[32]; + snd_pcm_format_t format; + int swapped; + } formats[] = { + {"32bit float little-endian", SND_PCM_FORMAT_FLOAT_LE}, + {"32bit integer little-endian", SND_PCM_FORMAT_S32_LE, IS_LE}, + {"32bit integer big-endian", SND_PCM_FORMAT_S32_BE, IS_BE}, + {"24bit little-endian", SND_PCM_FORMAT_S24_3LE, IS_LE}, + {"24bit big-endian", SND_PCM_FORMAT_S24_3BE, IS_BE}, + {"16bit little-endian", SND_PCM_FORMAT_S16_LE, IS_LE}, + {"16bit big-endian", SND_PCM_FORMAT_S16_BE, IS_BE}, + }; +#define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) +#define FIRST_16BIT_FORMAT 5 + + if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { + jack_error ("ALSA: no playback configurations available (%s)", + snd_strerror (err)); + return -1; + } + + if ((err = snd_pcm_hw_params_set_periods_integer (handle, hw_params)) + < 0) { + jack_error ("ALSA: cannot restrict period size to integral" + " value."); + return -1; + } + + if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0) { + if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + if ((err = snd_pcm_hw_params_set_access ( + handle, hw_params, + SND_PCM_ACCESS_MMAP_COMPLEX)) < 0) { + jack_error ("ALSA: mmap-based access is not possible" + " for the %s " + "stream of this audio interface", + stream_name); + return -1; + } + } + } + + format = (sample_width == 4) ? 0 : NUMFORMATS - 1; + + while (1) { + if ((err = snd_pcm_hw_params_set_format ( + handle, hw_params, formats[format].format)) < 0) { + + if ((sample_width == 4 + ? format++ >= NUMFORMATS - 1 + : format-- <= 0)) { + jack_error ("Sorry. The audio interface \"%s\"" + " doesn't support any of the" + " hardware sample formats that" + " JACK's alsa-driver can use.", + device_name); + return -1; + } + } else { + if (formats[format].swapped) { + driver->quirk_bswap = 1; + } else { + driver->quirk_bswap = 0; + } + jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); + break; + } + } + + frame_rate = driver->frame_rate ; + err = snd_pcm_hw_params_set_rate_near (handle, hw_params, + &frame_rate, NULL) ; + driver->frame_rate = frame_rate ; + if (err < 0) { + jack_error ("ALSA: cannot set sample/frame rate to %" + PRIu32 " for %s", driver->frame_rate, + stream_name); + return -1; + } + if (!*nchns) { + /*if not user-specified, try to find the maximum + * number of channels */ + unsigned int channels_max ; + err = snd_pcm_hw_params_get_channels_max (hw_params, + &channels_max); + *nchns = channels_max ; + + if (*nchns > 1024) { + + /* the hapless user is an unwitting victim of + the "default" ALSA PCM device, which can + support up to 16 million channels. since + they can't be bothered to set up a proper + default device, limit the number of + channels for them to a sane default. + */ + + jack_error ( +"You appear to be using the ALSA software \"plug\" layer, probably\n" +"a result of using the \"default\" ALSA device. This is less\n" +"efficient than it could be. Consider using a hardware device\n" +"instead rather than using the plug layer. Usually the name of the\n" +"hardware device that corresponds to the first sound card is hw:0\n" + ); + *nchns = 2; + } + } + + if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, + *nchns)) < 0) { + jack_error ("ALSA: cannot set channel count to %u for %s", + *nchns, stream_name); + return -1; + } + + if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, + driver->frames_per_cycle, + 0)) + < 0) { + jack_error ("ALSA: cannot set period size to %" PRIu32 + " frames for %s", driver->frames_per_cycle, + stream_name); + return -1; + } + + *nperiodsp = driver->user_nperiods; + snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL); + if (*nperiodsp < driver->user_nperiods) + *nperiodsp = driver->user_nperiods; + if (snd_pcm_hw_params_set_periods_near (handle, hw_params, + nperiodsp, NULL) < 0) { + jack_error ("ALSA: cannot set number of periods to %u for %s", + *nperiodsp, stream_name); + return -1; + } + + if (*nperiodsp < driver->user_nperiods) { + jack_error ("ALSA: got smaller periods %u than %u for %s", + *nperiodsp, (unsigned int) driver->user_nperiods, + stream_name); + return -1; + } + jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name); +#if 0 + if (!jack_power_of_two(driver->frames_per_cycle)) { + jack_error("JACK: frames must be a power of two " + "(64, 512, 1024, ...)\n"); + return -1; + } +#endif + + if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params, + *nperiodsp * + driver->frames_per_cycle)) + < 0) { + jack_error ("ALSA: cannot set buffer length to %" PRIu32 + " for %s", + *nperiodsp * driver->frames_per_cycle, + stream_name); + return -1; + } + + if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { + jack_error ("ALSA: cannot set hardware parameters for %s", + stream_name); + return -1; + } + + snd_pcm_sw_params_current (handle, sw_params); + + if ((err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, + 0U)) < 0) { + jack_error ("ALSA: cannot set start mode for %s", stream_name); + return -1; + } + + stop_th = *nperiodsp * driver->frames_per_cycle; + if (driver->soft_mode) { + stop_th = (snd_pcm_uframes_t)-1; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold ( + handle, sw_params, stop_th)) < 0) { + jack_error ("ALSA: cannot set stop mode for %s", + stream_name); + return -1; + } + + if ((err = snd_pcm_sw_params_set_silence_threshold ( + handle, sw_params, 0)) < 0) { + jack_error ("ALSA: cannot set silence threshold for %s", + stream_name); + return -1; + } + +#if 0 + jack_info ("set silence size to %lu * %lu = %lu", + driver->frames_per_cycle, *nperiodsp, + driver->frames_per_cycle * *nperiodsp); + + if ((err = snd_pcm_sw_params_set_silence_size ( + handle, sw_params, + driver->frames_per_cycle * *nperiodsp)) < 0) { + jack_error ("ALSA: cannot set silence size for %s", + stream_name); + return -1; + } +#endif + + if (handle == driver->playback_handle) + err = snd_pcm_sw_params_set_avail_min ( + handle, sw_params, + driver->frames_per_cycle + * (*nperiodsp - driver->user_nperiods + 1)); + else + err = snd_pcm_sw_params_set_avail_min ( + handle, sw_params, driver->frames_per_cycle); + + if (err < 0) { + jack_error ("ALSA: cannot set avail min for %s", stream_name); + return -1; + } + + if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { + jack_error ("ALSA: cannot set software parameters for %s\n", + stream_name); + return -1; + } + + return 0; +} + +static int +alsa_driver_set_parameters (alsa_driver_t *driver, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate) +{ + int dir; + snd_pcm_uframes_t p_period_size = 0; + snd_pcm_uframes_t c_period_size = 0; + channel_t chn; + unsigned int pr = 0; + unsigned int cr = 0; + int err; + + driver->frame_rate = rate; + driver->frames_per_cycle = frames_per_cycle; + driver->user_nperiods = user_nperiods; + + jack_info ("configuring for %" PRIu32 "Hz, period = %" + PRIu32 " frames (%.1f ms), buffer = %" PRIu32 " periods", + rate, frames_per_cycle, (((float)frames_per_cycle / (float) rate) * 1000.0f), user_nperiods); + + if (driver->capture_handle) { + if (alsa_driver_configure_stream ( + driver, + driver->alsa_name_capture, + "capture", + driver->capture_handle, + driver->capture_hw_params, + driver->capture_sw_params, + &driver->capture_nperiods, + &driver->capture_nchannels, + driver->capture_sample_bytes)) { + jack_error ("ALSA: cannot configure capture channel"); + return -1; + } + } + + if (driver->playback_handle) { + if (alsa_driver_configure_stream ( + driver, + driver->alsa_name_playback, + "playback", + driver->playback_handle, + driver->playback_hw_params, + driver->playback_sw_params, + &driver->playback_nperiods, + &driver->playback_nchannels, + driver->playback_sample_bytes)) { + jack_error ("ALSA: cannot configure playback channel"); + return -1; + } + } + + /* check the rate, since thats rather important */ + + if (driver->playback_handle) { + snd_pcm_hw_params_get_rate (driver->playback_hw_params, + &pr, &dir); + } + + if (driver->capture_handle) { + snd_pcm_hw_params_get_rate (driver->capture_hw_params, + &cr, &dir); + } + + if (driver->capture_handle && driver->playback_handle) { + if (cr != pr) { + jack_error ("playback and capture sample rates do " + "not match (%d vs. %d)", pr, cr); + } + + /* only change if *both* capture and playback rates + * don't match requested certain hardware actually + * still works properly in full-duplex with slightly + * different rate values between adc and dac + */ + if (cr != driver->frame_rate && pr != driver->frame_rate) { + jack_error ("sample rate in use (%d Hz) does not " + "match requested rate (%d Hz)", + cr, driver->frame_rate); + driver->frame_rate = cr; + } + + } + else if (driver->capture_handle && cr != driver->frame_rate) { + jack_error ("capture sample rate in use (%d Hz) does not " + "match requested rate (%d Hz)", + cr, driver->frame_rate); + driver->frame_rate = cr; + } + else if (driver->playback_handle && pr != driver->frame_rate) { + jack_error ("playback sample rate in use (%d Hz) does not " + "match requested rate (%d Hz)", + pr, driver->frame_rate); + driver->frame_rate = pr; + } + + + /* check the fragment size, since thats non-negotiable */ + + if (driver->playback_handle) { + snd_pcm_access_t access; + + err = snd_pcm_hw_params_get_period_size ( + driver->playback_hw_params, &p_period_size, &dir); + err = snd_pcm_hw_params_get_format ( + driver->playback_hw_params, + &(driver->playback_sample_format)); + err = snd_pcm_hw_params_get_access (driver->playback_hw_params, + &access); + driver->playback_interleaved = + (access == SND_PCM_ACCESS_MMAP_INTERLEAVED) + || (access == SND_PCM_ACCESS_MMAP_COMPLEX); + + if (p_period_size != driver->frames_per_cycle) { + jack_error ("alsa_pcm: requested an interrupt every %" + PRIu32 + " frames but got %u frames for playback", + driver->frames_per_cycle, p_period_size); + return -1; + } + } + + if (driver->capture_handle) { + snd_pcm_access_t access; + + err = snd_pcm_hw_params_get_period_size ( + driver->capture_hw_params, &c_period_size, &dir); + err = snd_pcm_hw_params_get_format ( + driver->capture_hw_params, + &(driver->capture_sample_format)); + err = snd_pcm_hw_params_get_access (driver->capture_hw_params, + &access); + driver->capture_interleaved = + (access == SND_PCM_ACCESS_MMAP_INTERLEAVED) + || (access == SND_PCM_ACCESS_MMAP_COMPLEX); + + if (c_period_size != driver->frames_per_cycle) { + jack_error ("alsa_pcm: requested an interrupt every %" + PRIu32 + " frames but got %uc frames for capture", + driver->frames_per_cycle, p_period_size); + return -1; + } + } + + driver->playback_sample_bytes = + snd_pcm_format_physical_width (driver->playback_sample_format) + / 8; + driver->capture_sample_bytes = + snd_pcm_format_physical_width (driver->capture_sample_format) + / 8; + + if (driver->playback_handle) { + switch (driver->playback_sample_format) { + case SND_PCM_FORMAT_FLOAT_LE: + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S24_3LE: + case SND_PCM_FORMAT_S24_3BE: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S16_BE: + break; + + default: + jack_error ("programming error: unhandled format " + "type for playback"); + exit (1); + } + } + + if (driver->capture_handle) { + switch (driver->capture_sample_format) { + case SND_PCM_FORMAT_FLOAT_LE: + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S24_3LE: + case SND_PCM_FORMAT_S24_3BE: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S16_BE: + break; + + default: + jack_error ("programming error: unhandled format " + "type for capture"); + exit (1); + } + } + + if (driver->playback_interleaved) { + const snd_pcm_channel_area_t *my_areas; + snd_pcm_uframes_t offset, frames; + if (snd_pcm_mmap_begin(driver->playback_handle, + &my_areas, &offset, &frames) < 0) { + jack_error ("ALSA: %s: mmap areas info error", + driver->alsa_name_playback); + return -1; + } + driver->interleave_unit = + snd_pcm_format_physical_width ( + driver->playback_sample_format) / 8; + } else { + driver->interleave_unit = 0; /* NOT USED */ + } + + if (driver->capture_interleaved) { + const snd_pcm_channel_area_t *my_areas; + snd_pcm_uframes_t offset, frames; + if (snd_pcm_mmap_begin(driver->capture_handle, + &my_areas, &offset, &frames) < 0) { + jack_error ("ALSA: %s: mmap areas info error", + driver->alsa_name_capture); + return -1; + } + } + + if (driver->playback_nchannels > driver->capture_nchannels) { + driver->max_nchannels = driver->playback_nchannels; + driver->user_nchannels = driver->capture_nchannels; + } else { + driver->max_nchannels = driver->capture_nchannels; + driver->user_nchannels = driver->playback_nchannels; + } + + alsa_driver_setup_io_function_pointers (driver); + + /* Allocate and initialize structures that rely on the + channels counts. + + Set up the bit pattern that is used to record which + channels require action on every cycle. any bits that are + not set after the engine's process() call indicate channels + that potentially need to be silenced. + */ + + bitset_create (&driver->channels_done, driver->max_nchannels); + bitset_create (&driver->channels_not_done, driver->max_nchannels); + + if (driver->playback_handle) { + driver->playback_addr = (char **) + malloc (sizeof (char *) * driver->playback_nchannels); + memset (driver->playback_addr, 0, + sizeof (char *) * driver->playback_nchannels); + driver->playback_interleave_skip = (unsigned long *) + malloc (sizeof (unsigned long *) * driver->playback_nchannels); + memset (driver->playback_interleave_skip, 0, + sizeof (unsigned long *) * driver->playback_nchannels); + driver->silent = (unsigned long *) + malloc (sizeof (unsigned long) + * driver->playback_nchannels); + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + driver->silent[chn] = 0; + } + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + bitset_add (driver->channels_done, chn); + } + + driver->dither_state = (dither_state_t *) + calloc ( driver->playback_nchannels, + sizeof (dither_state_t)); + } + + if (driver->capture_handle) { + driver->capture_addr = (char **) + malloc (sizeof (char *) * driver->capture_nchannels); + memset (driver->capture_addr, 0, + sizeof (char *) * driver->capture_nchannels); + driver->capture_interleave_skip = (unsigned long *) + malloc (sizeof (unsigned long *) * driver->capture_nchannels); + memset (driver->capture_interleave_skip, 0, + sizeof (unsigned long *) * driver->capture_nchannels); + } + + driver->clock_sync_data = (ClockSyncStatus *) + malloc (sizeof (ClockSyncStatus) * driver->max_nchannels); + + driver->period_usecs = + (jack_time_t) floor ((((float) driver->frames_per_cycle) / + driver->frame_rate) * 1000000.0f); + driver->poll_timeout = (int) floor (1.5f * driver->period_usecs); + +// JACK2 +/* + if (driver->engine) { + if (driver->engine->set_buffer_size (driver->engine, + driver->frames_per_cycle)) { + jack_error ("ALSA: Cannot set engine buffer size to %d (check MIDI)", driver->frames_per_cycle); + return -1; + } + } +*/ + + return 0; +} + +int +alsa_driver_reset_parameters (alsa_driver_t *driver, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate) +{ + /* XXX unregister old ports ? */ + alsa_driver_release_channel_dependent_memory (driver); + return alsa_driver_set_parameters (driver, + frames_per_cycle, + user_nperiods, rate); +} + +static int +alsa_driver_get_channel_addresses (alsa_driver_t *driver, + snd_pcm_uframes_t *capture_avail, + snd_pcm_uframes_t *playback_avail, + snd_pcm_uframes_t *capture_offset, + snd_pcm_uframes_t *playback_offset) +{ + unsigned long err; + channel_t chn; + + if (capture_avail) { + if ((err = snd_pcm_mmap_begin ( + driver->capture_handle, &driver->capture_areas, + (snd_pcm_uframes_t *) capture_offset, + (snd_pcm_uframes_t *) capture_avail)) < 0) { + jack_error ("ALSA: %s: mmap areas info error", + driver->alsa_name_capture); + return -1; + } + + for (chn = 0; chn < driver->capture_nchannels; chn++) { + const snd_pcm_channel_area_t *a = + &driver->capture_areas[chn]; + driver->capture_addr[chn] = (char *) a->addr + + ((a->first + a->step * *capture_offset) / 8); + driver->capture_interleave_skip[chn] = (unsigned long ) (a->step / 8); + } + } + + if (playback_avail) { + if ((err = snd_pcm_mmap_begin ( + driver->playback_handle, &driver->playback_areas, + (snd_pcm_uframes_t *) playback_offset, + (snd_pcm_uframes_t *) playback_avail)) < 0) { + jack_error ("ALSA: %s: mmap areas info error ", + driver->alsa_name_playback); + return -1; + } + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + const snd_pcm_channel_area_t *a = + &driver->playback_areas[chn]; + driver->playback_addr[chn] = (char *) a->addr + + ((a->first + a->step * *playback_offset) / 8); + driver->playback_interleave_skip[chn] = (unsigned long ) (a->step / 8); + } + } + + return 0; +} + +int +alsa_driver_start (alsa_driver_t *driver) +{ + int err; + snd_pcm_uframes_t poffset, pavail; + channel_t chn; + + driver->poll_last = 0; + driver->poll_next = 0; + + if (driver->playback_handle) { + if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) { + jack_error ("ALSA: prepare error for playback on " + "\"%s\" (%s)", driver->alsa_name_playback, + snd_strerror(err)); + return -1; + } + } + + if ((driver->capture_handle && driver->capture_and_playback_not_synced) + || !driver->playback_handle) { + if ((err = snd_pcm_prepare (driver->capture_handle)) < 0) { + jack_error ("ALSA: prepare error for capture on \"%s\"" + " (%s)", driver->alsa_name_capture, + snd_strerror(err)); + return -1; + } + } + + if (driver->hw_monitoring) { + if (driver->input_monitor_mask || driver->all_monitor_in) { + if (driver->all_monitor_in) { + driver->hw->set_input_monitor_mask (driver->hw, ~0U); + } else { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); + } + } else { + driver->hw->set_input_monitor_mask (driver->hw, + driver->input_monitor_mask); + } + } + + if (driver->playback_handle) { + driver->playback_nfds = + snd_pcm_poll_descriptors_count (driver->playback_handle); + } else { + driver->playback_nfds = 0; + } + + if (driver->capture_handle) { + driver->capture_nfds = + snd_pcm_poll_descriptors_count (driver->capture_handle); + } else { + driver->capture_nfds = 0; + } + + if (driver->pfd) { + free (driver->pfd); + } + + driver->pfd = (struct pollfd *) + malloc (sizeof (struct pollfd) * + (driver->playback_nfds + driver->capture_nfds + 2)); + + if (driver->midi && !driver->xrun_recovery) + (driver->midi->start)(driver->midi); + + if (driver->playback_handle) { + /* fill playback buffer with zeroes, and mark + all fragments as having data. + */ + + pavail = snd_pcm_avail_update (driver->playback_handle); + + if (pavail != + driver->frames_per_cycle * driver->playback_nperiods) { + jack_error ("ALSA: full buffer not available at start"); + return -1; + } + + if (alsa_driver_get_channel_addresses (driver, + 0, &pavail, 0, &poffset)) { + return -1; + } + + /* XXX this is cheating. ALSA offers no guarantee that + we can access the entire buffer at any one time. It + works on most hardware tested so far, however, buts + its a liability in the long run. I think that + alsa-lib may have a better function for doing this + here, where the goal is to silence the entire + buffer. + */ + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + alsa_driver_silence_on_channel ( + driver, chn, + driver->user_nperiods + * driver->frames_per_cycle); + } + + snd_pcm_mmap_commit (driver->playback_handle, poffset, + driver->user_nperiods + * driver->frames_per_cycle); + + if ((err = snd_pcm_start (driver->playback_handle)) < 0) { + jack_error ("ALSA: could not start playback (%s)", + snd_strerror (err)); + return -1; + } + } + + if ((driver->capture_handle && driver->capture_and_playback_not_synced) + || !driver->playback_handle) { + if ((err = snd_pcm_start (driver->capture_handle)) < 0) { + jack_error ("ALSA: could not start capture (%s)", + snd_strerror (err)); + return -1; + } + } + + return 0; +} + +int +alsa_driver_stop (alsa_driver_t *driver) +{ + int err; +// JSList* node; +// int chn; + + /* silence all capture port buffers, because we might + be entering offline mode. + */ + +// JACK2 +/* + for (chn = 0, node = driver->capture_ports; node; + node = jack_slist_next (node), chn++) { + + jack_port_t* port; + char* buf; + jack_nframes_t nframes = driver->engine->control->buffer_size; + + port = (jack_port_t *) node->data; + buf = jack_port_get_buffer (port, nframes); + memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes); + } +*/ + +// JACK2 + ClearOutput(); + + if (driver->playback_handle) { + if ((err = snd_pcm_drop (driver->playback_handle)) < 0) { + jack_error ("ALSA: channel flush for playback " + "failed (%s)", snd_strerror (err)); + return -1; + } + } + + if (!driver->playback_handle + || driver->capture_and_playback_not_synced) { + if (driver->capture_handle) { + if ((err = snd_pcm_drop (driver->capture_handle)) < 0) { + jack_error ("ALSA: channel flush for " + "capture failed (%s)", + snd_strerror (err)); + return -1; + } + } + } + + if (driver->hw_monitoring) { + driver->hw->set_input_monitor_mask (driver->hw, 0); + } + + if (driver->midi && !driver->xrun_recovery) + (driver->midi->stop)(driver->midi); + + return 0; +} + +static int +alsa_driver_restart (alsa_driver_t *driver) +{ + int res; + + driver->xrun_recovery = 1; + // JACK2 + /* + if ((res = driver->nt_stop((struct _jack_driver_nt *) driver))==0) + res = driver->nt_start((struct _jack_driver_nt *) driver); + */ + res = Restart(); + driver->xrun_recovery = 0; + + if (res && driver->midi) + (driver->midi->stop)(driver->midi); + + return res; +} + +static int +alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs) +{ + snd_pcm_status_t *status; + int res; + + snd_pcm_status_alloca(&status); + + if (driver->capture_handle) { + if ((res = snd_pcm_status(driver->capture_handle, status)) + < 0) { + jack_error("status error: %s", snd_strerror(res)); + } + } else { + if ((res = snd_pcm_status(driver->playback_handle, status)) + < 0) { + jack_error("status error: %s", snd_strerror(res)); + } + } + + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED) + { + jack_log("**** alsa_pcm: pcm in suspended state, resuming it" ); + if (driver->capture_handle) { + if ((res = snd_pcm_prepare(driver->capture_handle)) + < 0) { + jack_error("error preparing after suspend: %s", snd_strerror(res)); + } + } else { + if ((res = snd_pcm_prepare(driver->playback_handle)) + < 0) { + jack_error("error preparing after suspend: %s", snd_strerror(res)); + } + } + } + + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN + && driver->process_count > XRUN_REPORT_DELAY) { + struct timeval now, diff, tstamp; + driver->xrun_count++; + snd_pcm_status_get_tstamp(status,&now); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; + jack_log("**** alsa_pcm: xrun of at least %.3f msecs",*delayed_usecs / 1000.0); + } + + if (alsa_driver_restart (driver)) { + return -1; + } + return 0; +} + +void +alsa_driver_silence_untouched_channels (alsa_driver_t *driver, + jack_nframes_t nframes) +{ + channel_t chn; + jack_nframes_t buffer_frames = + driver->frames_per_cycle * driver->playback_nperiods; + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + if (bitset_contains (driver->channels_not_done, chn)) { + if (driver->silent[chn] < buffer_frames) { + alsa_driver_silence_on_channel_no_mark ( + driver, chn, nframes); + driver->silent[chn] += nframes; + } + } + } +} + +void +alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, + ClockSyncStatus status) +{ + driver->clock_sync_data[chn] = status; + alsa_driver_clock_sync_notify (driver, chn, status); +} + +static int under_gdb = FALSE; + +jack_nframes_t +alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float + *delayed_usecs) +{ + snd_pcm_sframes_t avail = 0; + snd_pcm_sframes_t capture_avail = 0; + snd_pcm_sframes_t playback_avail = 0; + int xrun_detected = FALSE; + int need_capture; + int need_playback; + unsigned int i; + jack_time_t poll_enter; + jack_time_t poll_ret = 0; + + *status = -1; + *delayed_usecs = 0; + + need_capture = driver->capture_handle ? 1 : 0; + + if (extra_fd >= 0) { + need_playback = 0; + } else { + need_playback = driver->playback_handle ? 1 : 0; + } + + again: + + while (need_playback || need_capture) { + + int poll_result; + unsigned int ci = 0; + unsigned int nfds; + unsigned short revents; + + nfds = 0; + + if (need_playback) { + snd_pcm_poll_descriptors (driver->playback_handle, + &driver->pfd[0], + driver->playback_nfds); + nfds += driver->playback_nfds; + } + + if (need_capture) { + snd_pcm_poll_descriptors (driver->capture_handle, + &driver->pfd[nfds], + driver->capture_nfds); + ci = nfds; + nfds += driver->capture_nfds; + } + + /* ALSA doesn't set POLLERR in some versions of 0.9.X */ + + for (i = 0; i < nfds; i++) { + driver->pfd[i].events |= POLLERR; + } + + if (extra_fd >= 0) { + driver->pfd[nfds].fd = extra_fd; + driver->pfd[nfds].events = + POLLIN|POLLERR|POLLHUP|POLLNVAL; + nfds++; + } + + poll_enter = jack_get_microseconds (); + + if (poll_enter > driver->poll_next) { + /* + * This processing cycle was delayed past the + * next due interrupt! Do not account this as + * a wakeup delay: + */ + driver->poll_next = 0; + driver->poll_late++; + } + + poll_result = poll (driver->pfd, nfds, driver->poll_timeout); + if (poll_result < 0) { + + if (errno == EINTR) { + jack_info ("poll interrupt"); + // this happens mostly when run + // under gdb, or when exiting due to a signal + if (under_gdb) { + goto again; + } + *status = -2; + return 0; + } + + jack_error ("ALSA: poll call failed (%s)", + strerror (errno)); + *status = -3; + return 0; + + } + + poll_ret = jack_get_microseconds (); + + // JACK2 + SetTime(poll_ret); + + if (extra_fd < 0) { + if (driver->poll_next && poll_ret > driver->poll_next) { + *delayed_usecs = poll_ret - driver->poll_next; + } + driver->poll_last = poll_ret; + driver->poll_next = poll_ret + driver->period_usecs; +// JACK2 +/* + driver->engine->transport_cycle_start (driver->engine, + poll_ret); +*/ + } + +#ifdef DEBUG_WAKEUP + fprintf (stderr, "%" PRIu64 ": checked %d fds, started at %" PRIu64 " %" PRIu64 " usecs since poll entered\n", + poll_ret, nfds, poll_enter, poll_ret - poll_enter); +#endif + + /* check to see if it was the extra FD that caused us + * to return from poll */ + + if (extra_fd >= 0) { + + if (driver->pfd[nfds-1].revents == 0) { + /* we timed out on the extra fd */ + + *status = -4; + return -1; + } + + /* if POLLIN was the only bit set, we're OK */ + + *status = 0; + return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; + } + + if (need_playback) { + if (snd_pcm_poll_descriptors_revents + (driver->playback_handle, &driver->pfd[0], + driver->playback_nfds, &revents) < 0) { + jack_error ("ALSA: playback revents failed"); + *status = -6; + return 0; + } + + if (revents & POLLERR) { + xrun_detected = TRUE; + } + + if (revents & POLLOUT) { + need_playback = 0; +#ifdef DEBUG_WAKEUP + fprintf (stderr, "%" PRIu64 + " playback stream ready\n", + poll_ret); +#endif + } + } + + if (need_capture) { + if (snd_pcm_poll_descriptors_revents + (driver->capture_handle, &driver->pfd[ci], + driver->capture_nfds, &revents) < 0) { + jack_error ("ALSA: capture revents failed"); + *status = -6; + return 0; + } + + if (revents & POLLERR) { + xrun_detected = TRUE; + } + + if (revents & POLLIN) { + need_capture = 0; +#ifdef DEBUG_WAKEUP + fprintf (stderr, "%" PRIu64 + " capture stream ready\n", + poll_ret); +#endif + } + } + + if (poll_result == 0) { + jack_error ("ALSA: poll time out, polled for %" PRIu64 + " usecs", + poll_ret - poll_enter); + *status = -5; + return 0; + } + + } + + if (driver->capture_handle) { + if ((capture_avail = snd_pcm_avail_update ( + driver->capture_handle)) < 0) { + if (capture_avail == -EPIPE) { + xrun_detected = TRUE; + } else { + jack_error ("unknown ALSA avail_update return" + " value (%u)", capture_avail); + } + } + } else { + /* odd, but see min() computation below */ + capture_avail = INT_MAX; + } + + if (driver->playback_handle) { + if ((playback_avail = snd_pcm_avail_update ( + driver->playback_handle)) < 0) { + if (playback_avail == -EPIPE) { + xrun_detected = TRUE; + } else { + jack_error ("unknown ALSA avail_update return" + " value (%u)", playback_avail); + } + } + } else { + /* odd, but see min() computation below */ + playback_avail = INT_MAX; + } + + if (xrun_detected) { + *status = alsa_driver_xrun_recovery (driver, delayed_usecs); + return 0; + } + + *status = 0; + driver->last_wait_ust = poll_ret; + + avail = capture_avail < playback_avail ? capture_avail : playback_avail; + +#ifdef DEBUG_WAKEUP + fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu " + "cavail = %lu\n", + avail, playback_avail, capture_avail); +#endif + + /* mark all channels not done for now. read/write will change this */ + + bitset_copy (driver->channels_not_done, driver->channels_done); + + /* constrain the available count to the nearest (round down) number of + periods. + */ + + return avail - (avail % driver->frames_per_cycle); +} + + +int +alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) +{ + snd_pcm_sframes_t contiguous; + snd_pcm_sframes_t nread; + snd_pcm_uframes_t offset; + jack_nframes_t orig_nframes; +// jack_default_audio_sample_t* buf; +// channel_t chn; +// JSList *node; +// jack_port_t* port; + int err; + + if (nframes > driver->frames_per_cycle) { + return -1; + } + +// JACK2 +/* + if (driver->engine->freewheeling) { + return 0; + } +*/ + if (driver->midi) + (driver->midi->read)(driver->midi, nframes); + + if (!driver->capture_handle) { + return 0; + } + + nread = 0; + contiguous = 0; + orig_nframes = nframes; + + while (nframes) { + + contiguous = nframes; + + if (alsa_driver_get_channel_addresses ( + driver, + (snd_pcm_uframes_t *) &contiguous, + (snd_pcm_uframes_t *) 0, + &offset, 0) < 0) { + return -1; + } +// JACK2 +/* + for (chn = 0, node = driver->capture_ports; node; + node = jack_slist_next (node), chn++) { + + port = (jack_port_t *) node->data; + + if (!jack_port_connected (port)) { + // no-copy optimization + continue; + } + buf = jack_port_get_buffer (port, orig_nframes); + alsa_driver_read_from_channel (driver, chn, + buf + nread, contiguous); + } +*/ + ReadInput(orig_nframes, contiguous, nread); + + if ((err = snd_pcm_mmap_commit (driver->capture_handle, + offset, contiguous)) < 0) { + jack_error ("ALSA: could not complete read of %" + PRIu32 " frames: error = %d", contiguous, err); + return -1; + } + + nframes -= contiguous; + nread += contiguous; + } + + return 0; +} + +int +alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) +{ +// channel_t chn; +// JSList *node; +// JSList *mon_node; +// jack_default_audio_sample_t* buf; +// jack_default_audio_sample_t* monbuf; + jack_nframes_t orig_nframes; + snd_pcm_sframes_t nwritten; + snd_pcm_sframes_t contiguous; + snd_pcm_uframes_t offset; +// jack_port_t *port; + int err; + + driver->process_count++; + +// JACK2 +/* + if (!driver->playback_handle || driver->engine->freewheeling) { + return 0; + } +*/ + if (!driver->playback_handle) { + return 0; + } + + if (nframes > driver->frames_per_cycle) { + return -1; + } + + if (driver->midi) + (driver->midi->write)(driver->midi, nframes); + + nwritten = 0; + contiguous = 0; + orig_nframes = nframes; + + /* check current input monitor request status */ + + driver->input_monitor_mask = 0; + +// JACK2 +/* + for (chn = 0, node = driver->capture_ports; node; + node = jack_slist_next (node), chn++) { + if (((jack_port_t *) node->data)->shared->monitor_requests) { + driver->input_monitor_mask |= (1<hw_monitoring) { + if ((driver->hw->input_monitor_mask + != driver->input_monitor_mask) + && !driver->all_monitor_in) { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); + } + } + + while (nframes) { + + contiguous = nframes; + + if (alsa_driver_get_channel_addresses ( + driver, + (snd_pcm_uframes_t *) 0, + (snd_pcm_uframes_t *) &contiguous, + 0, &offset) < 0) { + return -1; + } + +// JACK2 +/* + for (chn = 0, node = driver->playback_ports, mon_node=driver->monitor_ports; + node; + node = jack_slist_next (node), chn++) { + + port = (jack_port_t *) node->data; + + if (!jack_port_connected (port)) { + continue; + } + buf = jack_port_get_buffer (port, orig_nframes); + alsa_driver_write_to_channel (driver, chn, + buf + nwritten, contiguous); + + if (mon_node) { + port = (jack_port_t *) mon_node->data; + if (!jack_port_connected (port)) { + continue; + } + monbuf = jack_port_get_buffer (port, orig_nframes); + memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); + mon_node = jack_slist_next (mon_node); + } + } +*/ + + // JACK2 + WriteOutput(orig_nframes, contiguous, nwritten); + + if (!bitset_empty (driver->channels_not_done)) { + alsa_driver_silence_untouched_channels (driver, + contiguous); + } + + if ((err = snd_pcm_mmap_commit (driver->playback_handle, + offset, contiguous)) < 0) { + jack_error ("ALSA: could not complete playback of %" + PRIu32 " frames: error = %d", contiguous, err); + if (err != -EPIPE && err != -ESTRPIPE) + return -1; + } + + nframes -= contiguous; + nwritten += contiguous; + } + + return 0; +} + +#if 0 +static int /* UNUSED */ +alsa_driver_change_sample_clock (alsa_driver_t *driver, SampleClockMode mode) +{ + return driver->hw->change_sample_clock (driver->hw, mode); +} + +static void /* UNUSED */ +alsa_driver_request_all_monitor_input (alsa_driver_t *driver, int yn) + +{ + if (driver->hw_monitoring) { + if (yn) { + driver->hw->set_input_monitor_mask (driver->hw, ~0U); + } else { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); + } + } + + driver->all_monitor_in = yn; +} + +static void /* UNUSED */ +alsa_driver_set_hw_monitoring (alsa_driver_t *driver, int yn) +{ + if (yn) { + driver->hw_monitoring = TRUE; + + if (driver->all_monitor_in) { + driver->hw->set_input_monitor_mask (driver->hw, ~0U); + } else { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); + } + } else { + driver->hw_monitoring = FALSE; + driver->hw->set_input_monitor_mask (driver->hw, 0); + } +} + +static ClockSyncStatus /* UNUSED */ +alsa_driver_clock_sync_status (channel_t chn) +{ + return Lock; +} +#endif + +void +alsa_driver_delete (alsa_driver_t *driver) +{ + JSList *node; + + if (driver->midi) + (driver->midi->destroy)(driver->midi); + + for (node = driver->clock_sync_listeners; node; + node = jack_slist_next (node)) { + free (node->data); + } + jack_slist_free (driver->clock_sync_listeners); + + if (driver->ctl_handle) { + snd_ctl_close (driver->ctl_handle); + driver->ctl_handle = 0; + } + + if (driver->capture_handle) { + snd_pcm_close (driver->capture_handle); + driver->capture_handle = 0; + } + + if (driver->playback_handle) { + snd_pcm_close (driver->playback_handle); + driver->capture_handle = 0; + } + + if (driver->capture_hw_params) { + snd_pcm_hw_params_free (driver->capture_hw_params); + driver->capture_hw_params = 0; + } + + if (driver->playback_hw_params) { + snd_pcm_hw_params_free (driver->playback_hw_params); + driver->playback_hw_params = 0; + } + + if (driver->capture_sw_params) { + snd_pcm_sw_params_free (driver->capture_sw_params); + driver->capture_sw_params = 0; + } + + if (driver->playback_sw_params) { + snd_pcm_sw_params_free (driver->playback_sw_params); + driver->playback_sw_params = 0; + } + + if (driver->pfd) { + free (driver->pfd); + } + + if (driver->hw) { + driver->hw->release (driver->hw); + driver->hw = 0; + } + free(driver->alsa_name_playback); + free(driver->alsa_name_capture); + free(driver->alsa_driver); + + alsa_driver_release_channel_dependent_memory (driver); + //JACK2 + //jack_driver_nt_finish ((jack_driver_nt_t *) driver); + free (driver); +} + +jack_driver_t * +alsa_driver_new (char *name, char *playback_alsa_device, + char *capture_alsa_device, + jack_client_t *client, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate, + int hw_monitoring, + int hw_metering, + int capturing, + int playing, + DitherAlgorithm dither, + int soft_mode, + int monitor, + int user_capture_nchnls, + int user_playback_nchnls, + int shorts_first, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency, + alsa_midi_t *midi_driver + ) +{ + int err; + + alsa_driver_t *driver; + + jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 + "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", + playing ? playback_alsa_device : "-", + capturing ? capture_alsa_device : "-", + frames_per_cycle, user_nperiods, rate, + user_capture_nchnls,user_playback_nchnls, + hw_monitoring ? "hwmon": "nomon", + hw_metering ? "hwmeter":"swmeter", + soft_mode ? "soft-mode":"-", + shorts_first ? "16bit":"32bit"); + + driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); + + jack_driver_nt_init ((jack_driver_nt_t *) driver); + + // JACK2 + /* + driver->nt_attach = (JackDriverNTAttachFunction) alsa_driver_attach; + driver->nt_detach = (JackDriverNTDetachFunction) alsa_driver_detach; + driver->read = (JackDriverReadFunction) alsa_driver_read; + driver->write = (JackDriverReadFunction) alsa_driver_write; + driver->null_cycle = (JackDriverNullCycleFunction) alsa_driver_null_cycle; + driver->nt_bufsize = (JackDriverNTBufSizeFunction) alsa_driver_bufsize; + driver->nt_start = (JackDriverNTStartFunction) alsa_driver_start; + driver->nt_stop = (JackDriverNTStopFunction) alsa_driver_stop; + driver->nt_run_cycle = (JackDriverNTRunCycleFunction) alsa_driver_run_cycle; + */ + + driver->playback_handle = NULL; + driver->capture_handle = NULL; + driver->ctl_handle = 0; + driver->hw = 0; + driver->capture_and_playback_not_synced = FALSE; + driver->max_nchannels = 0; + driver->user_nchannels = 0; + driver->playback_nchannels = user_playback_nchnls; + driver->capture_nchannels = user_capture_nchnls; + driver->playback_sample_bytes = (shorts_first ? 2:4); + driver->capture_sample_bytes = (shorts_first ? 2:4); + driver->capture_frame_latency = capture_latency; + driver->playback_frame_latency = playback_latency; + + driver->playback_addr = 0; + driver->capture_addr = 0; + driver->playback_interleave_skip = NULL; + driver->capture_interleave_skip = NULL; + + + driver->silent = 0; + driver->all_monitor_in = FALSE; + driver->with_monitor_ports = monitor; + + driver->clock_mode = ClockMaster; /* XXX is it? */ + driver->input_monitor_mask = 0; /* XXX is it? */ + + driver->capture_ports = 0; + driver->playback_ports = 0; + driver->monitor_ports = 0; + + driver->pfd = 0; + driver->playback_nfds = 0; + driver->capture_nfds = 0; + + driver->dither = dither; + driver->soft_mode = soft_mode; + + driver->quirk_bswap = 0; + + pthread_mutex_init (&driver->clock_sync_lock, 0); + driver->clock_sync_listeners = 0; + + driver->poll_late = 0; + driver->xrun_count = 0; + driver->process_count = 0; + + driver->alsa_name_playback = strdup (playback_alsa_device); + driver->alsa_name_capture = strdup (capture_alsa_device); + + driver->midi = midi_driver; + driver->xrun_recovery = 0; + + if (alsa_driver_check_card_type (driver)) { + alsa_driver_delete (driver); + return NULL; + } + + alsa_driver_hw_specific (driver, hw_monitoring, hw_metering); + + if (playing) { + if (snd_pcm_open (&driver->playback_handle, + playback_alsa_device, + SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK) < 0) { + switch (errno) { + case EBUSY: + jack_error ("the playback device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + playback_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; + + case EPERM: + jack_error ("you do not have permission to open " + "the audio device \"%s\" for playback", + playback_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; + } + + driver->playback_handle = NULL; + } + + if (driver->playback_handle) { + snd_pcm_nonblock (driver->playback_handle, 0); + } + } + + if (capturing) { + if (snd_pcm_open (&driver->capture_handle, + capture_alsa_device, + SND_PCM_STREAM_CAPTURE, + SND_PCM_NONBLOCK) < 0) { + switch (errno) { + case EBUSY: + jack_error ("the capture device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + capture_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; + + case EPERM: + jack_error ("you do not have permission to open " + "the audio device \"%s\" for capture", + capture_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; + } + + driver->capture_handle = NULL; + } + + if (driver->capture_handle) { + snd_pcm_nonblock (driver->capture_handle, 0); + } + } + + if (driver->playback_handle == NULL) { + if (playing) { + + /* they asked for playback, but we can't do it */ + + jack_error ("ALSA: Cannot open PCM device %s for " + "playback. Falling back to capture-only" + " mode", name); + + if (driver->capture_handle == NULL) { + /* can't do anything */ + alsa_driver_delete (driver); + return NULL; + } + + playing = FALSE; + } + } + + if (driver->capture_handle == NULL) { + if (capturing) { + + /* they asked for capture, but we can't do it */ + + jack_error ("ALSA: Cannot open PCM device %s for " + "capture. Falling back to playback-only" + " mode", name); + + if (driver->playback_handle == NULL) { + /* can't do anything */ + alsa_driver_delete (driver); + return NULL; + } + + capturing = FALSE; + } + } + + driver->playback_hw_params = 0; + driver->capture_hw_params = 0; + driver->playback_sw_params = 0; + driver->capture_sw_params = 0; + + if (driver->playback_handle) { + if ((err = snd_pcm_hw_params_malloc ( + &driver->playback_hw_params)) < 0) { + jack_error ("ALSA: could not allocate playback hw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + + if ((err = snd_pcm_sw_params_malloc ( + &driver->playback_sw_params)) < 0) { + jack_error ("ALSA: could not allocate playback sw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + } + + if (driver->capture_handle) { + if ((err = snd_pcm_hw_params_malloc ( + &driver->capture_hw_params)) < 0) { + jack_error ("ALSA: could not allocate capture hw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + + if ((err = snd_pcm_sw_params_malloc ( + &driver->capture_sw_params)) < 0) { + jack_error ("ALSA: could not allocate capture sw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + } + + if (alsa_driver_set_parameters (driver, frames_per_cycle, + user_nperiods, rate)) { + alsa_driver_delete (driver); + return NULL; + } + + driver->capture_and_playback_not_synced = FALSE; + + if (driver->capture_handle && driver->playback_handle) { + if (snd_pcm_link (driver->playback_handle, + driver->capture_handle) != 0) { + driver->capture_and_playback_not_synced = TRUE; + } + } + + driver->client = client; + + return (jack_driver_t *) driver; +} + +int +alsa_driver_listen_for_clock_sync_status (alsa_driver_t *driver, + ClockSyncListenerFunction func, + void *arg) +{ + ClockSyncListener *csl; + + csl = (ClockSyncListener *) malloc (sizeof (ClockSyncListener)); + csl->function = func; + csl->arg = arg; + csl->id = driver->next_clock_sync_listener_id++; + + pthread_mutex_lock (&driver->clock_sync_lock); + driver->clock_sync_listeners = + jack_slist_prepend (driver->clock_sync_listeners, csl); + pthread_mutex_unlock (&driver->clock_sync_lock); + return csl->id; +} + +int +alsa_driver_stop_listening_to_clock_sync_status (alsa_driver_t *driver, + unsigned int which) + +{ + JSList *node; + int ret = -1; + pthread_mutex_lock (&driver->clock_sync_lock); + for (node = driver->clock_sync_listeners; node; + node = jack_slist_next (node)) { + if (((ClockSyncListener *) node->data)->id == which) { + driver->clock_sync_listeners = + jack_slist_remove_link ( + driver->clock_sync_listeners, node); + free (node->data); + jack_slist_free_1 (node); + ret = 0; + break; + } + } + pthread_mutex_unlock (&driver->clock_sync_lock); + return ret; +} + +void +alsa_driver_clock_sync_notify (alsa_driver_t *driver, channel_t chn, + ClockSyncStatus status) +{ + JSList *node; + + pthread_mutex_lock (&driver->clock_sync_lock); + for (node = driver->clock_sync_listeners; node; + node = jack_slist_next (node)) { + ClockSyncListener *csl = (ClockSyncListener *) node->data; + csl->function (chn, status, csl->arg); + } + pthread_mutex_unlock (&driver->clock_sync_lock); + +} + +/* DRIVER "PLUGIN" INTERFACE */ + +const char driver_client_name[] = "alsa_pcm"; + +void +driver_finish (jack_driver_t *driver) +{ + alsa_driver_delete ((alsa_driver_t *) driver); +} diff --git a/linux/alsa/alsa_driver.h b/linux/alsa/alsa_driver.h index 13a78073..efe93de5 100644 --- a/linux/alsa/alsa_driver.h +++ b/linux/alsa/alsa_driver.h @@ -32,12 +32,20 @@ #define IS_BE 0 #endif +#define TRUE 1 +#define FALSE 0 + #include "types.h" #include "hardware.h" #include "driver.h" #include "memops.h" #include "alsa_midi.h" +#ifdef __cplusplus +extern "C" +{ +#endif + typedef void (*ReadCopyFunction) (jack_default_audio_sample_t *dst, char *src, unsigned long src_bytes, unsigned long src_skip_bytes); @@ -45,13 +53,8 @@ typedef void (*WriteCopyFunction) (char *dst, jack_default_audio_sample_t *src, unsigned long src_bytes, unsigned long dst_skip_bytes, dither_state_t *state); -typedef void (*CopyCopyFunction) (char *dst, char *src, - unsigned long src_bytes, - unsigned long dst_skip_bytes, - unsigned long src_skip_byte); -typedef struct _alsa_driver -{ +typedef struct _alsa_driver { JACK_DRIVER_NT_DECL @@ -124,7 +127,6 @@ typedef struct _alsa_driver ReadCopyFunction read_via_copy; WriteCopyFunction write_via_copy; - CopyCopyFunction channel_copy; int dither; dither_state_t *dither_state; @@ -144,100 +146,143 @@ typedef struct _alsa_driver alsa_midi_t *midi; int xrun_recovery; -} -alsa_driver_t; +} alsa_driver_t; static inline void -alsa_driver_mark_channel_done (alsa_driver_t *driver, channel_t chn) -{ - bitset_remove (driver->channels_not_done, chn); - driver->silent[chn] = 0; +alsa_driver_mark_channel_done (alsa_driver_t *driver, channel_t chn) { + bitset_remove (driver->channels_not_done, chn); + driver->silent[chn] = 0; } static inline void alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, - jack_nframes_t nframes) -{ - if (driver->playback_interleaved) { - memset_interleave - (driver->playback_addr[chn], - 0, nframes * driver->playback_sample_bytes, - driver->interleave_unit, - driver->playback_interleave_skip[chn]); - } else { - memset (driver->playback_addr[chn], 0, - nframes * driver->playback_sample_bytes); - } - alsa_driver_mark_channel_done (driver, chn); + jack_nframes_t nframes) { + if (driver->playback_interleaved) { + memset_interleave + (driver->playback_addr[chn], + 0, nframes * driver->playback_sample_bytes, + driver->interleave_unit, + driver->playback_interleave_skip[chn]); + } else { + memset (driver->playback_addr[chn], 0, + nframes * driver->playback_sample_bytes); + } + alsa_driver_mark_channel_done (driver,chn); } static inline void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, - jack_nframes_t nframes) -{ - if (driver->playback_interleaved) { - memset_interleave - (driver->playback_addr[chn], - 0, nframes * driver->playback_sample_bytes, - driver->interleave_unit, - driver->playback_interleave_skip[chn]); - } else { - memset (driver->playback_addr[chn], 0, - nframes * driver->playback_sample_bytes); - } + jack_nframes_t nframes) { + if (driver->playback_interleaved) { + memset_interleave + (driver->playback_addr[chn], + 0, nframes * driver->playback_sample_bytes, + driver->interleave_unit, + driver->playback_interleave_skip[chn]); + } else { + memset (driver->playback_addr[chn], 0, + nframes * driver->playback_sample_bytes); + } } static inline void alsa_driver_read_from_channel (alsa_driver_t *driver, - channel_t channel, - jack_default_audio_sample_t *buf, - jack_nframes_t nsamples) + channel_t channel, + jack_default_audio_sample_t *buf, + jack_nframes_t nsamples) { - driver->read_via_copy (buf, - driver->capture_addr[channel], - nsamples, - driver->capture_interleave_skip[channel]); + driver->read_via_copy (buf, + driver->capture_addr[channel], + nsamples, + driver->capture_interleave_skip[channel]); } static inline void alsa_driver_write_to_channel (alsa_driver_t *driver, - channel_t channel, - jack_default_audio_sample_t *buf, - jack_nframes_t nsamples) + channel_t channel, + jack_default_audio_sample_t *buf, + jack_nframes_t nsamples) { - driver->write_via_copy (driver->playback_addr[channel], - buf, - nsamples, - driver->playback_interleave_skip[channel], - driver->dither_state + channel); - alsa_driver_mark_channel_done (driver, channel); -} - -static inline void -alsa_driver_copy_channel (alsa_driver_t *driver, - channel_t input_channel, - channel_t output_channel, - jack_nframes_t nsamples) -{ - - driver->channel_copy (driver->playback_addr[output_channel], - driver->capture_addr[input_channel], - nsamples * driver->playback_sample_bytes, - driver->playback_interleave_skip[output_channel], - driver->capture_interleave_skip[input_channel]); - alsa_driver_mark_channel_done (driver, output_channel); + driver->write_via_copy (driver->playback_addr[channel], + buf, + nsamples, + driver->playback_interleave_skip[channel], + driver->dither_state+channel); + alsa_driver_mark_channel_done (driver, channel); } void alsa_driver_silence_untouched_channels (alsa_driver_t *driver, - jack_nframes_t nframes); + jack_nframes_t nframes); void alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, - ClockSyncStatus status); + ClockSyncStatus status); int alsa_driver_listen_for_clock_sync_status (alsa_driver_t *, - ClockSyncListenerFunction, - void *arg); + ClockSyncListenerFunction, + void *arg); int alsa_driver_stop_listen_for_clock_sync_status (alsa_driver_t *, - unsigned int); + unsigned int); void alsa_driver_clock_sync_notify (alsa_driver_t *, channel_t chn, - ClockSyncStatus); + ClockSyncStatus); + +int +alsa_driver_reset_parameters (alsa_driver_t *driver, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate); + +jack_driver_t * +alsa_driver_new (char *name, char *playback_alsa_device, + char *capture_alsa_device, + jack_client_t *client, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate, + int hw_monitoring, + int hw_metering, + int capturing, + int playing, + DitherAlgorithm dither, + int soft_mode, + int monitor, + int user_capture_nchnls, + int user_playback_nchnls, + int shorts_first, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency, + alsa_midi_t *midi_driver + ); +void +alsa_driver_delete (alsa_driver_t *driver); + +int +alsa_driver_start (alsa_driver_t *driver); + +int +alsa_driver_stop (alsa_driver_t *driver); + +jack_nframes_t +alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float + *delayed_usecs); + +int +alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes); + +int +alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes); + +jack_time_t jack_get_microseconds(void); + +// Code implemented in JackAlsaDriver.cpp + +void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); +void MonitorInput(); +void ClearOutput(); +void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); +void SetTime(jack_time_t time); +int Restart(); + +#ifdef __cplusplus +} +#endif + #endif /* __jack_alsa_driver_h__ */ diff --git a/linux/firewire/JackFFADODriver.cpp b/linux/firewire/JackFFADODriver.cpp index 486c3794..2f855f37 100644 --- a/linux/firewire/JackFFADODriver.cpp +++ b/linux/firewire/JackFFADODriver.cpp @@ -526,7 +526,7 @@ int JackFFADODriver::Attach() port = fGraphManager->GetPort(port_index); // Add one buffer more latency if "async" mode is used... - range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency + range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency; port->SetLatencyRange(JackPlaybackLatency, &range); // playback port aliases (jackd1 style port names) snprintf(buf, sizeof(buf) - 1, "%s:playback_%i", fClientControl.fName, (int) chn + 1); @@ -644,20 +644,32 @@ int JackFFADODriver::Open(ffado_jack_settings_t *params) int JackFFADODriver::Close() { - JackAudioDriver::Close(); + // Generic audio driver close + int res = JackAudioDriver::Close(); + ffado_driver_delete((ffado_driver_t*)fDriver); - return 0; + return res; } int JackFFADODriver::Start() { - JackAudioDriver::Start(); - return ffado_driver_start((ffado_driver_t *)fDriver); + int res = JackAudioDriver::Start(); + if (res >= 0) { + res = ffado_driver_start((ffado_driver_t *)fDriver); + if (res < 0) { + JackAudioDriver::Stop(); + } + } + return res; } int JackFFADODriver::Stop() { - return ffado_driver_stop((ffado_driver_t *)fDriver); + int res = ffado_driver_stop((ffado_driver_t *)fDriver); + if (JackAudioDriver::Stop() < 0) { + res = -1; + } + return res; } int JackFFADODriver::Read() diff --git a/linux/freebob/JackFreebobDriver.cpp b/linux/freebob/JackFreebobDriver.cpp index 552e9927..03a26893 100644 --- a/linux/freebob/JackFreebobDriver.cpp +++ b/linux/freebob/JackFreebobDriver.cpp @@ -832,20 +832,32 @@ int JackFreebobDriver::Open(freebob_jack_settings_t *params) int JackFreebobDriver::Close() { - JackAudioDriver::Close(); + // Generic audio driver close + int res = JackAudioDriver::Close(); + freebob_driver_delete((freebob_driver_t*)fDriver); - return 0; + return res; } int JackFreebobDriver::Start() { - JackAudioDriver::Start(); - return freebob_driver_start((freebob_driver_t *)fDriver); + int res = JackAudioDriver::Start(); + if (res >= 0) { + res = freebob_driver_start((freebob_driver_t *)fDriver); + if (res < 0) { + JackAudioDriver::Stop(); + } + } + return res; } int JackFreebobDriver::Stop() { - return freebob_driver_stop((freebob_driver_t *)fDriver); + int res = freebob_driver_stop((freebob_driver_t *)fDriver); + if (JackAudioDriver::Stop() < 0) { + res = -1; + } + return res; } int JackFreebobDriver::Read() diff --git a/linux/wscript b/linux/wscript index 869985d4..5675c3dc 100644 --- a/linux/wscript +++ b/linux/wscript @@ -44,13 +44,15 @@ def build(bld): create_jack_driver_obj(bld, 'dummy', '../common/JackDummyDriver.cpp') - alsa_driver_src = ['alsa/JackAlsaDriver.cpp', + alsa_driver_src = [ + 'alsa/JackAlsaDriver.cpp', 'alsa/alsa_rawmidi.c', 'alsa/alsa_seqmidi.c', 'alsa/alsa_midi_jackmp.cpp', '../common/memops.c', 'alsa/generic_hw.c', 'alsa/hdsp.c', + 'alsa/alsa_driver.c', 'alsa/hammerfall.c', 'alsa/ice1712.c' ] diff --git a/macosx/Jackdmp.xcodeproj/project.pbxproj b/macosx/Jackdmp.xcodeproj/project.pbxproj index 1c3370aa..dbcdbe05 100644 --- a/macosx/Jackdmp.xcodeproj/project.pbxproj +++ b/macosx/Jackdmp.xcodeproj/project.pbxproj @@ -1598,6 +1598,7 @@ 4B98AE010931D30C0091932A /* JackDebugClient.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackDebugClient.h; path = ../common/JackDebugClient.h; sourceTree = SOURCE_ROOT; }; 4B9A25B30DBF8330006E9FBC /* JackError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackError.cpp; path = ../common/JackError.cpp; sourceTree = SOURCE_ROOT; }; 4B9A26000DBF8584006E9FBC /* jslist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jslist.h; path = ../common/jack/jslist.h; sourceTree = SOURCE_ROOT; }; + 4BA2574C132FB49B009F2D3F /* alsa_driver.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = alsa_driver.c; path = ../linux/alsa/alsa_driver.c; sourceTree = SOURCE_ROOT; }; 4BA339AC10B2E36800190E3B /* Jackservermp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Jackservermp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4BA577BC08BF8BE200F82DE1 /* testSynchroClient.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = testSynchroClient.cpp; path = ../tests/testSynchroClient.cpp; sourceTree = SOURCE_ROOT; }; 4BA577FB08BF8E4600F82DE1 /* testSynchroServer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = testSynchroServer.cpp; path = ../tests/testSynchroServer.cpp; sourceTree = SOURCE_ROOT; }; @@ -2683,6 +2684,7 @@ 4B05A09D0DF72C6000840F4C /* Additional */ = { isa = PBXGroup; children = ( + 4BA2574C132FB49B009F2D3F /* alsa_driver.c */, 4B05A08A0DF72BF600840F4C /* Windows */, 4B05A0420DF72B8500840F4C /* Linux */, ); diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index d7e5edea..c1e9dc5e 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -276,17 +276,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, JackCoreAudioAdapter* adapter = static_cast(inRefCon); AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); - float* inputBuffer[adapter->fCaptureChannels]; - float* outputBuffer[adapter->fPlaybackChannels]; + jack_default_audio_sample_t* inputBuffer[adapter->fCaptureChannels]; + jack_default_audio_sample_t* outputBuffer[adapter->fPlaybackChannels]; for (int i = 0; i < adapter->fCaptureChannels; i++) { - inputBuffer[i] = (float*)adapter->fInputData->mBuffers[i].mData; + inputBuffer[i] = (jack_default_audio_sample_t*)adapter->fInputData->mBuffers[i].mData; } for (int i = 0; i < adapter->fPlaybackChannels; i++) { - outputBuffer[i] = (float*)ioData->mBuffers[i].mData; + outputBuffer[i] = (jack_default_audio_sample_t*)ioData->mBuffers[i].mData; } - adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, inNumberFrames); + adapter->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, inNumberFrames); return noErr; } @@ -769,8 +769,8 @@ int JackCoreAudioAdapter::SetupBuffers(int inchannels) fInputData->mNumberBuffers = inchannels; for (int i = 0; i < fCaptureChannels; i++) { fInputData->mBuffers[i].mNumberChannels = 1; - fInputData->mBuffers[i].mDataByteSize = fAdaptedBufferSize * sizeof(float); - fInputData->mBuffers[i].mData = malloc(fAdaptedBufferSize * sizeof(float)); + fInputData->mBuffers[i].mDataByteSize = fAdaptedBufferSize * sizeof(jack_default_audio_sample_t); + fInputData->mBuffers[i].mData = malloc(fAdaptedBufferSize * sizeof(jack_default_audio_sample_t)); } return 0; } @@ -942,9 +942,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, srcFormat.mSampleRate = samplerate; srcFormat.mFormatID = kAudioFormatLinearPCM; srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; - srcFormat.mBytesPerPacket = sizeof(float); + srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); srcFormat.mFramesPerPacket = 1; - srcFormat.mBytesPerFrame = sizeof(float); + srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); srcFormat.mChannelsPerFrame = inchannels; srcFormat.mBitsPerChannel = 32; PrintStreamDesc(&srcFormat); @@ -973,9 +973,9 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing, dstFormat.mSampleRate = samplerate; dstFormat.mFormatID = kAudioFormatLinearPCM; dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; - dstFormat.mBytesPerPacket = sizeof(float); + dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); dstFormat.mFramesPerPacket = 1; - dstFormat.mBytesPerFrame = sizeof(float); + dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); dstFormat.mChannelsPerFrame = outchannels; dstFormat.mBitsPerChannel = 32; PrintStreamDesc(&dstFormat); diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index 03e22adf..83806646 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -55,7 +55,7 @@ static void PrintStreamDesc(AudioStreamBasicDescription *inDesc) jack_log(" Bytes per Frame:%ld", inDesc->mBytesPerFrame); jack_log(" Channels per Frame:%ld", inDesc->mChannelsPerFrame); jack_log(" Bits per Channel:%ld", inDesc->mBitsPerChannel); - jack_log("- - - - - - - - - - - - - - - - - - - -\n"); + jack_log("- - - - - - - - - - - - - - - - - - - -"); } static void printError(OSStatus err) @@ -224,20 +224,19 @@ int JackCoreAudioDriver::Write() { for (int i = 0; i < fPlaybackChannels; i++) { if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { - float* buffer = GetOutputBuffer(i); - int size = sizeof(float) * fEngineControl->fBufferSize; - memcpy((float*)fDriverOutputData->mBuffers[i].mData, buffer, size); + jack_default_audio_sample_t* buffer = GetOutputBuffer(i); + int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize; + memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size); // Monitor ports if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) memcpy(GetMonitorBuffer(i), buffer, size); } else { - memset((float*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(float) * fEngineControl->fBufferSize); + memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); } } return 0; } - OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, @@ -1294,9 +1293,9 @@ int JackCoreAudioDriver::OpenAUHAL(bool capturing, srcFormat.mSampleRate = samplerate; srcFormat.mFormatID = kAudioFormatLinearPCM; srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; - srcFormat.mBytesPerPacket = sizeof(float); + srcFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); srcFormat.mFramesPerPacket = 1; - srcFormat.mBytesPerFrame = sizeof(float); + srcFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); srcFormat.mChannelsPerFrame = inchannels; srcFormat.mBitsPerChannel = 32; PrintStreamDesc(&srcFormat); @@ -1324,9 +1323,9 @@ int JackCoreAudioDriver::OpenAUHAL(bool capturing, dstFormat.mSampleRate = samplerate; dstFormat.mFormatID = kAudioFormatLinearPCM; dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; - dstFormat.mBytesPerPacket = sizeof(float); + dstFormat.mBytesPerPacket = sizeof(jack_default_audio_sample_t); dstFormat.mFramesPerPacket = 1; - dstFormat.mBytesPerFrame = sizeof(float); + dstFormat.mBytesPerFrame = sizeof(jack_default_audio_sample_t); dstFormat.mChannelsPerFrame = outchannels; dstFormat.mBitsPerChannel = 32; PrintStreamDesc(&dstFormat); @@ -1376,7 +1375,7 @@ int JackCoreAudioDriver::SetupBuffers(int inchannels) fJackInputData->mNumberBuffers = inchannels; for (int i = 0; i < inchannels; i++) { fJackInputData->mBuffers[i].mNumberChannels = 1; - fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float); + fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t); } return 0; } @@ -1551,12 +1550,15 @@ int JackCoreAudioDriver::Close() { jack_log("JackCoreAudioDriver::Close"); Stop(); - JackAudioDriver::Close(); + + // Generic audio driver close + int res = JackAudioDriver::Close(); + RemoveListeners(); DisposeBuffers(); CloseAUHAL(); DestroyAggregateDevice(); - return 0; + return res; } int JackCoreAudioDriver::Attach() @@ -1577,11 +1579,11 @@ int JackCoreAudioDriver::Attach() err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable); if (err != noErr) - jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error "); + jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error"); if (err == noErr && size > 0) { err = AudioDeviceGetProperty(fDeviceID, i + 1, true, kAudioDevicePropertyChannelName, &size, channel_name); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error"); snprintf(alias, sizeof(alias) - 1, "%s:%s:out_%s%u", fAliasName, fCaptureDriverName, channel_name, i + 1); } else { snprintf(alias, sizeof(alias) - 1, "%s:%s:out%u", fAliasName, fCaptureDriverName, i + 1); @@ -1599,10 +1601,10 @@ int JackCoreAudioDriver::Attach() UInt32 value2 = 0; err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); port = fGraphManager->GetPort(port_index); port->SetAlias(alias); @@ -1615,11 +1617,11 @@ int JackCoreAudioDriver::Attach() err = AudioDeviceGetPropertyInfo(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable); if (err != noErr) - jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error "); + jack_log("AudioDeviceGetPropertyInfo kAudioDevicePropertyChannelName error"); if (err == noErr && size > 0) { err = AudioDeviceGetProperty(fDeviceID, i + 1, false, kAudioDevicePropertyChannelName, &size, channel_name); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertyChannelName error"); snprintf(alias, sizeof(alias) - 1, "%s:%s:in_%s%u", fAliasName, fPlaybackDriverName, channel_name, i + 1); } else { snprintf(alias, sizeof(alias) - 1, "%s:%s:in%u", fAliasName, fPlaybackDriverName, i + 1); @@ -1637,10 +1639,10 @@ int JackCoreAudioDriver::Attach() UInt32 value2 = 0; err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2); if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error "); + jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); port = fGraphManager->GetPort(port_index); port->SetAlias(alias); @@ -1651,14 +1653,13 @@ int JackCoreAudioDriver::Attach() // Monitor ports if (fWithMonitorPorts) { - jack_log("Create monitor port "); + jack_log("Create monitor port"); snprintf(name, sizeof(name) - 1, "%s:monitor_%u", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("Cannot register monitor port for %s", name); return -1; } else { port = fGraphManager->GetPort(port_index); - port->SetAlias(alias); range.min = range.max = fEngineControl->fBufferSize; port->SetLatencyRange(JackCaptureLatency, &range); fMonitorPortList[i] = port_index; @@ -1677,33 +1678,38 @@ int JackCoreAudioDriver::Attach() int JackCoreAudioDriver::Start() { jack_log("JackCoreAudioDriver::Start"); - JackAudioDriver::Start(); + if (JackAudioDriver::Start() >= 0) { + OSStatus err = AudioOutputUnitStart(fAUHAL); + if (err == noErr) { - OSStatus err = AudioOutputUnitStart(fAUHAL); - if (err != noErr) - return -1; + // Waiting for Measure callback to be called (= driver has started) + fState = false; + int count = 0; + while (!fState && count++ < WAIT_COUNTER) { + usleep(100000); + jack_log("JackCoreAudioDriver::Start wait count = %d", count); + } - // Waiting for Measure callback to be called (= driver has started) - fState = false; - int count = 0; - while (!fState && count++ < WAIT_COUNTER) { - usleep(100000); - jack_log("JackCoreAudioDriver::Start wait count = %d", count); - } + if (count < WAIT_COUNTER) { + jack_info("CoreAudio driver is running..."); + return 0; + } - if (count < WAIT_COUNTER) { - jack_info("CoreAudio driver is running..."); - return 0; - } else { - jack_error("CoreAudio driver cannot start..."); - return -1; + jack_error("CoreAudio driver cannot start..."); + } + JackAudioDriver::Stop(); } + return -1; } int JackCoreAudioDriver::Stop() { jack_log("JackCoreAudioDriver::Stop"); - return (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1; + int res = (AudioOutputUnitStop(fAUHAL) == noErr) ? 0 : -1; + if (JackAudioDriver::Stop() < 0) { + res = -1; + } + return res; } int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) @@ -1723,7 +1729,7 @@ int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) // Input buffers do no change : prepare them only once for (int i = 0; i < fCaptureChannels; i++) { fJackInputData->mBuffers[i].mNumberChannels = 1; - fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(float); + fJackInputData->mBuffers[i].mDataByteSize = fEngineControl->fBufferSize * sizeof(jack_default_audio_sample_t); fJackInputData->mBuffers[i].mData = GetInputBuffer(i); } diff --git a/macosx/coremidi/JackCoreMidiDriver.cpp b/macosx/coremidi/JackCoreMidiDriver.cpp index 55ffeae6..1cb7176b 100644 --- a/macosx/coremidi/JackCoreMidiDriver.cpp +++ b/macosx/coremidi/JackCoreMidiDriver.cpp @@ -45,15 +45,15 @@ void JackCoreMidiDriver::ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuf jack_error("ReadProc : ring buffer is full, skip events..."); return; } - + jack_ringbuffer_write(ringbuffer, (char*)&pktlist->numPackets, sizeof(UInt32)); - + for (unsigned int i = 0; i < pktlist->numPackets; ++i) { - + MIDIPacket *packet = (MIDIPacket *)pktlist->packet; - + // TODO : use timestamp - + // Check available size first.. size = jack_ringbuffer_write_space(ringbuffer); if (size < (sizeof(UInt16) + packet->length)) { @@ -64,7 +64,7 @@ void JackCoreMidiDriver::ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuf jack_ringbuffer_write(ringbuffer, (char*)&packet->length, sizeof(UInt16)); // Write event actual data jack_ringbuffer_write(ringbuffer, (char*)packet->data, packet->length); - + packet = MIDIPacketNext(packet); } } @@ -83,7 +83,7 @@ void JackCoreMidiDriver::ReadVirtualProc(const MIDIPacketList *pktlist, void *re void JackCoreMidiDriver::NotifyProc(const MIDINotification *message, void *refCon) { - jack_info("NotifyProc %d", message->messageID); + jack_log("NotifyProc %d", message->messageID); } JackCoreMidiDriver::JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) @@ -106,15 +106,15 @@ int JackCoreMidiDriver::Open(bool capturing, OSStatus err; CFStringRef coutputStr; std::string str; - + // Get real input/output number fRealCaptureChannels = MIDIGetNumberOfSources(); fRealPlaybackChannels = MIDIGetNumberOfDestinations(); - + // Generic JackMidiDriver Open if (JackMidiDriver::Open(capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) return -1; - + coutputStr = CFStringCreateWithCString(0, "JackMidi", CFStringGetSystemEncoding()); err = MIDIClientCreate(coutputStr, NotifyProc, this, &fMidiClient); CFRelease(coutputStr); @@ -122,7 +122,7 @@ int JackCoreMidiDriver::Open(bool capturing, jack_error("Cannot create CoreMidi client"); goto error; } - + err = MIDIInputPortCreate(fMidiClient, CFSTR("Input port"), ReadProc, this, &fInputPort); if (!fInputPort) { jack_error("Cannot open CoreMidi in port\n"); @@ -134,10 +134,10 @@ int JackCoreMidiDriver::Open(bool capturing, jack_error("Cannot open CoreMidi out port\n"); goto error; } - + fMidiDestination = new MIDIEndpointRef[inchannels + fRealCaptureChannels]; assert(fMidiDestination); - + // Virtual input for (int i = 0; i < inchannels; i++) { std::stringstream num; @@ -151,13 +151,13 @@ int JackCoreMidiDriver::Open(bool capturing, goto error; } } - + // Real input for (int i = 0; i < fRealCaptureChannels; i++) { fMidiDestination[i + inchannels] = MIDIGetSource(i); MIDIPortConnectSource(fInputPort, fMidiDestination[i + inchannels], fRingBuffer[i + inchannels]); } - + fMidiSource = new MIDIEndpointRef[outchannels + fRealPlaybackChannels]; assert(fMidiSource); @@ -172,47 +172,50 @@ int JackCoreMidiDriver::Open(bool capturing, if (!fMidiSource[i]) { jack_error("Cannot create CoreMidi source"); goto error; - } + } } - + // Real output for (int i = 0; i < fRealPlaybackChannels; i++) { fMidiSource[i + outchannels] = MIDIGetDestination(i); } - + return 0; - + error: Close(); return -1; } - + int JackCoreMidiDriver::Close() { + // Generic midi driver close + int res = JackMidiDriver::Close(); + if (fInputPort) MIDIPortDispose(fInputPort); - - if (fOutputPort) + + if (fOutputPort) MIDIPortDispose(fOutputPort); - + // Only dispose "virtual" endpoints for (int i = 0; i < fCaptureChannels - fRealCaptureChannels; i++) { - if (fMidiDestination) + if (fMidiDestination) MIDIEndpointDispose(fMidiDestination[i]); } delete[] fMidiDestination; - + // Only dispose "virtual" endpoints for (int i = 0; i < fPlaybackChannels - fRealPlaybackChannels; i++) { - if (fMidiSource[i]) + if (fMidiSource[i]) MIDIEndpointDispose(fMidiSource[i]); } delete[] fMidiSource; - - if (fMidiClient) + + if (fMidiClient) MIDIClientDispose(fMidiClient); - - return 0; + + return res; } int JackCoreMidiDriver::Attach() @@ -229,7 +232,7 @@ int JackCoreMidiDriver::Attach() jack_log("JackCoreMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); for (i = 0; i < fCaptureChannels; i++) { - + err = MIDIObjectGetStringProperty(fMidiDestination[i], kMIDIPropertyName, &pname); if (err == noErr) { CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0); @@ -238,7 +241,7 @@ int JackCoreMidiDriver::Attach() } else { snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); } - + snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("driver: cannot register port for %s", name); @@ -251,7 +254,7 @@ int JackCoreMidiDriver::Attach() } for (i = 0; i < fPlaybackChannels; i++) { - + err = MIDIObjectGetStringProperty(fMidiSource[i], kMIDIPropertyName, &pname); if (err == noErr) { CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0); @@ -260,7 +263,7 @@ int JackCoreMidiDriver::Attach() } else { snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); } - + snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1); if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error("driver: cannot register port for %s", name); @@ -277,23 +280,23 @@ int JackCoreMidiDriver::Attach() int JackCoreMidiDriver::Read() { for (int chan = 0; chan < fCaptureChannels; chan++) { - + if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) { - + // Get JACK port JackMidiBuffer* midi_buffer = GetInputBuffer(chan); - + if (jack_ringbuffer_read_space(fRingBuffer[chan]) == 0) { // Reset buffer midi_buffer->Reset(midi_buffer->nframes); } else { - + while (jack_ringbuffer_read_space(fRingBuffer[chan]) > 0) { - + // Read event number int ev_count = 0; jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int)); - + for (int j = 0; j < ev_count; j++) { // Read event length UInt16 event_len; @@ -304,7 +307,7 @@ int JackCoreMidiDriver::Read() } } } - + } else { // Consume ring buffer jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan])); @@ -316,35 +319,35 @@ int JackCoreMidiDriver::Read() int JackCoreMidiDriver::Write() { MIDIPacketList* pktlist = (MIDIPacketList*)fMIDIBuffer; - + for (int chan = 0; chan < fPlaybackChannels; chan++) { - + if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) { - + MIDIPacket* packet = MIDIPacketListInit(pktlist); JackMidiBuffer* midi_buffer = GetOutputBuffer(chan); - + // TODO : use timestamp - + for (unsigned int j = 0; j < midi_buffer->event_count; j++) { JackMidiEvent* ev = &midi_buffer->events[j]; packet = MIDIPacketListAdd(pktlist, sizeof(fMIDIBuffer), packet, MIDIGetCurrentHostTime(), ev->size, ev->GetData(midi_buffer)); } - + if (packet) { if (chan < fPlaybackChannels - fRealPlaybackChannels) { OSStatus err = MIDIReceived(fMidiSource[chan], pktlist); - if (err != noErr) + if (err != noErr) jack_error("MIDIReceived error"); } else { OSStatus err = MIDISend(fOutputPort, fMidiSource[chan], pktlist); - if (err != noErr) + if (err != noErr) jack_error("MIDISend error"); } } } } - + return 0; } @@ -355,7 +358,7 @@ extern "C" { #endif - SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() + SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() { jack_driver_desc_t * desc; unsigned int i; @@ -366,7 +369,7 @@ extern "C" desc->nparams = 2; desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); - + i = 0; strcpy(desc->params[i].name, "inchannels"); desc->params[i].character = 'i'; @@ -386,7 +389,7 @@ extern "C" return desc; } - SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { const JSList * node; const jack_driver_param_t * param; @@ -407,7 +410,7 @@ extern "C" break; } } - + Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table); if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) { return driver; diff --git a/macosx/coremidi/JackCoreMidiDriver.h b/macosx/coremidi/JackCoreMidiDriver.h index 190e9cd2..a99b35a0 100644 --- a/macosx/coremidi/JackCoreMidiDriver.h +++ b/macosx/coremidi/JackCoreMidiDriver.h @@ -41,17 +41,17 @@ class JackCoreMidiDriver : public JackMidiDriver MIDIPortRef fOutputPort; MIDIEndpointRef* fMidiDestination; MIDIEndpointRef* fMidiSource; - - char fMIDIBuffer[BUFFER_SIZE_MAX * sizeof(float)]; - + + char fMIDIBuffer[BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t)]; + int fRealCaptureChannels; int fRealPlaybackChannels; - + static void ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuffer_t* ringbuffer); static void ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon); static void ReadVirtualProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon); static void NotifyProc(const MIDINotification *message, void *refCon); - + public: JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); @@ -67,7 +67,7 @@ class JackCoreMidiDriver : public JackMidiDriver jack_nframes_t capture_latency, jack_nframes_t playback_latency); int Close(); - + int Attach(); int Read(); diff --git a/posix/JackSocketServerChannel.cpp b/posix/JackSocketServerChannel.cpp index ac857de2..3008e307 100644 --- a/posix/JackSocketServerChannel.cpp +++ b/posix/JackSocketServerChannel.cpp @@ -392,7 +392,7 @@ bool JackSocketServerChannel::HandleRequest(int fd) JackInternalClientLoadRequest req; JackInternalClientLoadResult res; if (req.Read(socket) == 0) - res.fResult = fServer->InternalClientLoad(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus); + res.fResult = fServer->InternalClientLoad1(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus); if (res.Write(socket) < 0) jack_error("JackRequest::InternalClientLoad write error name = %s", req.fName); break; diff --git a/posix/JackSystemDeps_os.h b/posix/JackSystemDeps_os.h index 41ee9528..516b805b 100644 --- a/posix/JackSystemDeps_os.h +++ b/posix/JackSystemDeps_os.h @@ -25,7 +25,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include +#ifndef UINT32_MAX #define UINT32_MAX 4294967295U +#endif #define DRIVER_HANDLE void* #define LoadDriverModule(name) dlopen((name), RTLD_NOW | RTLD_GLOBAL) diff --git a/windows/JackRouter/JackRouter.cpp b/windows/JackRouter/JackRouter.cpp index 47727af7..e5086f8d 100644 --- a/windows/JackRouter/JackRouter.cpp +++ b/windows/JackRouter/JackRouter.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2006 Grame +Copyright (C) 2006 Grame This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,13 +58,13 @@ static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32; using namespace std; -// class id. +// class id. // {838FE50A-C1AB-4b77-B9B6-0A40788B53F3} CLSID IID_ASIO_DRIVER = { 0x838fe50a, 0xc1ab, 0x4b77, { 0xb9, 0xb6, 0xa, 0x40, 0x78, 0x8b, 0x53, 0xf3 } }; CFactoryTemplate g_Templates[1] = { - {L"ASIOJACK", &IID_ASIO_DRIVER, JackRouter::CreateInstance} + {L"ASIOJACK", &IID_ASIO_DRIVER, JackRouter::CreateInstance} }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); @@ -183,7 +183,7 @@ JackRouter::JackRouter() : AsioDriver() char dllName[512]; string confPath; DWORD res = GetModuleFileName(handle, dllName, 512); - + // Compute .ini file path string fullPath = dllName; int lastPos = fullPath.find_last_of(PATH_SEP); @@ -223,7 +223,7 @@ static bool GetEXEName(DWORD dwProcessID, char* name) { DWORD aProcesses [1024], cbNeeded, cProcesses; unsigned int i; - + // Enumerate all processes if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) return false; @@ -240,33 +240,33 @@ static bool GetEXEName(DWORD dwProcessID, char* name) // Get a handle to the process HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); - + // Get the process name if (NULL != hProcess) { HMODULE hMod; DWORD cbNeeded; - - if(EnumProcessModules(hProcess, &hMod, + + if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { //Get the name of the exe file - GetModuleBaseName(hProcess, hMod, szEXEName, + GetModuleBaseName(hProcess, hMod, szEXEName, sizeof(szEXEName)/sizeof(TCHAR)); int len = strlen((char*)szEXEName) - 4; // remove ".exe" - strncpy(name, (char*)szEXEName, len); + strncpy(name, (char*)szEXEName, len); name[len] = '\0'; return true; } } - } + } } return false; } //------------------------------------------------------------------------------------------ -static inline float ClipFloat(float sample) +static inline jack_default_audio_sample_t ClipFloat(jack_default_audio_sample_t sample) { - return (sample < -1.0f) ? -1.0f : (sample > 1.0f) ? 1.0f : sample; + return (sample < jack_default_audio_sample_t(-1.0)) ? jack_default_audio_sample_t(-1.0) : (sample > jack_default_audio_sample_t(1.0)) ? jack_default_audio_sample_t(1.0) : sample; } //------------------------------------------------------------------------------------------ @@ -288,42 +288,42 @@ int JackRouter::process(jack_nframes_t nframes, void* arg) { JackRouter* driver = (JackRouter*)arg; int i,j; - int pos = (driver->fToggle) ? 0 : driver->fBufferSize ; - - for (i = 0; i < driver->fActiveInputs; i++) { - -#ifdef LONG_SAMPLE - float* buffer = (float*)jack_port_get_buffer(driver->fInputPorts[i], nframes); + int pos = (driver->fToggle) ? 0 : driver->fBufferSize ; + + for (i = 0; i < driver->fActiveInputs; i++) { + +#ifdef LONG_SAMPLE + jack_default_audio_sample_t* buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(driver->fInputPorts[i], nframes); long* in = driver->fInputBuffers[i] + pos; for (j = 0; j < nframes; j++) { - in[j] = buffer[j] * float(0x7fffffff); + in[j] = buffer[j] * jack_default_audio_sample_t(0x7fffffff); } #else memcpy(driver->fInputBuffers[i] + pos, jack_port_get_buffer(driver->fInputPorts[i], nframes), - nframes * sizeof(float)); + nframes * sizeof(jack_default_audio_sample_t)); #endif - } + } driver->bufferSwitch(); for (i = 0; i < driver->fActiveOutputs; i++) { #ifdef LONG_SAMPLE - float* buffer = (float*)jack_port_get_buffer(driver->fOutputPorts[i], nframes); + jack_default_audio_sample_t* buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(driver->fOutputPorts[i], nframes); long* out = driver->fOutputBuffers[i] + pos; - float gain = 1.f/float(0x7fffffff); + jack_default_audio_sample_t gain = jack_default_audio_sample_t(1)/jack_default_audio_sample_t(0x7fffffff); for (j = 0; j < nframes; j++) { buffer[j] = out[j] * gain; } #else memcpy(jack_port_get_buffer(driver->fOutputPorts[i], nframes), driver->fOutputBuffers[i] + pos, - nframes * sizeof(float)); + nframes * sizeof(jack_default_audio_sample_t)); #endif } - + return 0; } @@ -356,7 +356,7 @@ ASIOBool JackRouter::init(void* sysRef) HANDLE win = (HANDLE)sysRef; int my_pid = _getpid(); - + if (!GetEXEName(my_pid, name)) { // If getting the .exe name fails, takes a generic one. _snprintf(name, sizeof(name) - 1, "JackRouter_%d", my_pid); } @@ -365,19 +365,19 @@ ASIOBool JackRouter::init(void* sysRef) printf("Error: jack client still present...\n"); return true; } - + fClient = jack_client_open(name, JackNullOption, NULL); if (fClient == NULL) { strcpy (fErrorMessage, "Open error: is jack server running?"); printf("Open error: is jack server running?\n"); return false; } - + fBufferSize = jack_get_buffer_size(fClient); fSampleRate = jack_get_sample_rate(fClient); jack_set_process_callback(fClient, process, this); jack_on_shutdown(fClient, shutdown, this); - + fInputLatency = fBufferSize; // typically fOutputLatency = fBufferSize * 2; fMilliSeconds = (long)((double)(fBufferSize * 1000) / fSampleRate); @@ -399,7 +399,7 @@ ASIOError JackRouter::start() fToggle = 0; fStarted = true; printf("Start ASIO Jack\n"); - + if (jack_activate(fClient) == 0) { if (fFirstActivate) { @@ -413,9 +413,9 @@ ASIOError JackRouter::start() } else { return ASE_NotPresent; - } + } } - + return ASE_NotPresent; } @@ -533,8 +533,8 @@ ASIOError JackRouter::getChannelInfo(ASIOChannelInfo *info) char buf[32]; if (info->isInput) { - for (i = 0; i < fActiveInputs; i++) { - if (fInMap[i] == info->channel) { + for (i = 0; i < fActiveInputs; i++) { + if (fInMap[i] == info->channel) { info->isActive = ASIOTrue; //_snprintf(buf, sizeof(buf) - 1, "Jack::In%d ", info->channel); //strcpy(info->name, buf); @@ -545,7 +545,7 @@ ASIOError JackRouter::getChannelInfo(ASIOChannelInfo *info) _snprintf(buf, sizeof(buf) - 1, "In%d ", info->channel); strcpy(info->name, buf); } else { - for (i = 0; i < fActiveOutputs; i++) { + for (i = 0; i < fActiveOutputs; i++) { if (fOutMap[i] == info->channel) { //NOT USED !! info->isActive = ASIOTrue; //_snprintf(buf, sizeof(buf) - 1, "Jack::Out%d ", info->channel); @@ -579,7 +579,7 @@ ASIOError JackRouter::createBuffers(ASIOBufferInfo *bufferInfos, long numChannel #ifdef LONG_SAMPLE fInputBuffers[fActiveInputs] = new long[fBufferSize * 2]; // double buffer #else - fInputBuffers[fActiveInputs] = new float[fBufferSize * 2]; // double buffer + fInputBuffers[fActiveInputs] = new jack_default_audio_sample_t[fBufferSize * 2]; // double buffer #endif if (fInputBuffers[fActiveInputs]) { info->buffers[0] = fInputBuffers[fActiveInputs]; @@ -588,9 +588,9 @@ ASIOError JackRouter::createBuffers(ASIOBufferInfo *bufferInfos, long numChannel info->buffers[0] = info->buffers[1] = 0; notEnoughMem = true; } - + _snprintf(buf, sizeof(buf) - 1, "in%d", fActiveInputs + 1); - fInputPorts[fActiveInputs] + fInputPorts[fActiveInputs] = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput,0); if (fInputPorts[fActiveInputs] == NULL) goto error; @@ -601,17 +601,17 @@ error: disposeBuffers(); return ASE_InvalidParameter; } - } else { // output + } else { // output if (info->channelNum < 0 || info->channelNum >= kNumOutputs) goto error; fOutMap[fActiveOutputs] = info->channelNum; - + #ifdef LONG_SAMPLE fOutputBuffers[fActiveOutputs] = new long[fBufferSize * 2]; // double buffer #else - fOutputBuffers[fActiveOutputs] = new float[fBufferSize * 2]; // double buffer + fOutputBuffers[fActiveOutputs] = new jack_default_audio_sample_t[fBufferSize * 2]; // double buffer #endif - + if (fOutputBuffers[fActiveOutputs]) { info->buffers[0] = fOutputBuffers[fActiveOutputs]; info->buffers[1] = fOutputBuffers[fActiveOutputs] + fBufferSize; @@ -619,9 +619,9 @@ error: info->buffers[0] = info->buffers[1] = 0; notEnoughMem = true; } - + _snprintf(buf, sizeof(buf) - 1, "out%d", fActiveOutputs + 1); - fOutputPorts[fActiveOutputs] + fOutputPorts[fActiveOutputs] = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput,0); if (fOutputPorts[fActiveOutputs] == NULL) goto error; @@ -633,7 +633,7 @@ error: return ASE_InvalidParameter; } } - } + } if (notEnoughMem) { disposeBuffers(); @@ -653,9 +653,9 @@ error: fAsioTime.timeCode.timeCodeSamples.lo = fAsioTime.timeCode.timeCodeSamples.hi = 0; fAsioTime.timeCode.flags = kTcValid | kTcRunning ; } else { - fTimeInfoMode = false; + fTimeInfoMode = false; } - + return ASE_OK; } @@ -663,14 +663,14 @@ error: ASIOError JackRouter::disposeBuffers() { long i; - + fCallbacks = 0; stop(); for (i = 0; i < fActiveInputs; i++) { delete[] fInputBuffers[i]; jack_port_unregister(fClient, fInputPorts[i]); - } + } fActiveInputs = 0; for (i = 0; i < fActiveOutputs; i++) { @@ -689,7 +689,7 @@ ASIOError JackRouter::controlPanel() } //--------------------------------------------------------------------------------------------- -ASIOError JackRouter::future(long selector, void* opt) // !!! check properties +ASIOError JackRouter::future(long selector, void* opt) // !!! check properties { ASIOTransportParameters* tp = (ASIOTransportParameters*)opt; switch (selector) @@ -804,7 +804,7 @@ void JackRouter::RestoreConnections() void JackRouter::AutoConnect() { const char** ports; - + if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput)) == NULL) { printf("Cannot find any physical capture ports\n"); } else { @@ -818,9 +818,9 @@ void JackRouter::AutoConnect() } } } - jack_free(ports); + jack_free(ports); } - + if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput)) == NULL) { printf("Cannot find any physical playback ports"); } else { @@ -834,7 +834,7 @@ void JackRouter::AutoConnect() } } } - jack_free(ports); + jack_free(ports); } } diff --git a/windows/JackWinNamedPipeServerChannel.cpp b/windows/JackWinNamedPipeServerChannel.cpp index b4d4d622..3723af5e 100644 --- a/windows/JackWinNamedPipeServerChannel.cpp +++ b/windows/JackWinNamedPipeServerChannel.cpp @@ -307,7 +307,7 @@ bool JackClientPipeThread::HandleRequest() JackInternalClientLoadRequest req; JackInternalClientLoadResult res; if (req.Read(fPipe) == 0) - res.fResult = fServer->InternalClientLoad(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus); + res.fResult = fServer->InternalClientLoad1(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus); res.Write(fPipe); break; } diff --git a/windows/JackWinProcessSync.cpp b/windows/JackWinProcessSync.cpp index 12dbcdcf..5f3fa2fd 100644 --- a/windows/JackWinProcessSync.cpp +++ b/windows/JackWinProcessSync.cpp @@ -1,20 +1,20 @@ /* Copyright (C) 2004-2008 Grame - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + */ @@ -74,7 +74,7 @@ bool JackWinProcessSync::LockedTimedWait(long usec) } /* -Code from CAGuard.cpp : does ot sees to work as expected.. +Code from APPLE CAGuard.cpp : does not seem to work as expected... void JackWinProcessSync::Wait() { diff --git a/windows/Setup/JackRouter.dll b/windows/Setup/JackRouter.dll index 829f6e10..860fcc39 100644 Binary files a/windows/Setup/JackRouter.dll and b/windows/Setup/JackRouter.dll differ diff --git a/windows/portaudio/JackPortAudioAdapter.cpp b/windows/portaudio/JackPortAudioAdapter.cpp index 0f5e161b..f8915a5d 100644 --- a/windows/portaudio/JackPortAudioAdapter.cpp +++ b/windows/portaudio/JackPortAudioAdapter.cpp @@ -35,7 +35,7 @@ namespace Jack void* userData) { JackPortAudioAdapter* adapter = static_cast(userData); - adapter->PushAndPull((float**)inputBuffer, (float**)outputBuffer, framesPerBuffer); + adapter->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, framesPerBuffer); return paContinue; } diff --git a/windows/portaudio/JackPortAudioDriver.cpp b/windows/portaudio/JackPortAudioDriver.cpp index d910bb9d..41a3deb2 100644 --- a/windows/portaudio/JackPortAudioDriver.cpp +++ b/windows/portaudio/JackPortAudioDriver.cpp @@ -38,8 +38,8 @@ namespace Jack void* userData) { JackPortAudioDriver* driver = (JackPortAudioDriver*)userData; - driver->fInputBuffer = (float**)inputBuffer; - driver->fOutputBuffer = (float**)outputBuffer; + driver->fInputBuffer = (jack_default_audio_sample_t**)inputBuffer; + driver->fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer; // Setup threadded based log function set_threaded_log_function(); driver->CycleTakeBeginTime(); @@ -49,14 +49,14 @@ namespace Jack int JackPortAudioDriver::Read() { for (int i = 0; i < fCaptureChannels; i++) - memcpy(GetInputBuffer(i), fInputBuffer[i], sizeof(float) * fEngineControl->fBufferSize); + memcpy(GetInputBuffer(i), fInputBuffer[i], sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); return 0; } int JackPortAudioDriver::Write() { for (int i = 0; i < fPlaybackChannels; i++) - memcpy(fOutputBuffer[i], GetOutputBuffer(i), sizeof(float) * fEngineControl->fBufferSize); + memcpy(fOutputBuffer[i], GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); return 0; } @@ -180,7 +180,9 @@ error: int JackPortAudioDriver::Close() { + // Generic audio driver close int res = JackAudioDriver::Close(); + jack_log("JackPortAudioDriver::Close"); Pa_CloseStream(fStream); return res; @@ -189,16 +191,25 @@ error: int JackPortAudioDriver::Start() { jack_log("JackPortAudioDriver::Start"); - JackAudioDriver::Start(); - PaError err = Pa_StartStream(fStream); - return (err == paNoError) ? 0 : -1; + if (JackAudioDriver::Start() >= 0) { + PaError err = Pa_StartStream(fStream); + if (err == paNoError) { + return 0; + } + JackAudioDriver::Stop(); + } + return -1; } int JackPortAudioDriver::Stop() { jack_log("JackPortAudioDriver::Stop"); PaError err = Pa_StopStream(fStream); - return (err == paNoError) ? 0 : -1; + int res = (err == paNoError) ? 0 : -1; + if (JackAudioDriver::Stop() < 0) { + res = -1; + } + return res; } int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size) diff --git a/windows/portaudio/JackPortAudioDriver.h b/windows/portaudio/JackPortAudioDriver.h index d18da9b8..c4945f44 100644 --- a/windows/portaudio/JackPortAudioDriver.h +++ b/windows/portaudio/JackPortAudioDriver.h @@ -37,8 +37,8 @@ class JackPortAudioDriver : public JackAudioDriver PortAudioDevices* fPaDevices; PaStream* fStream; - float** fInputBuffer; - float** fOutputBuffer; + jack_default_audio_sample_t** fInputBuffer; + jack_default_audio_sample_t** fOutputBuffer; PaDeviceIndex fInputDevice; PaDeviceIndex fOutputDevice; diff --git a/windows/winmme/JackWinMMEDriver.cpp b/windows/winmme/JackWinMMEDriver.cpp index b76a8299..d3635c64 100644 --- a/windows/winmme/JackWinMMEDriver.cpp +++ b/windows/winmme/JackWinMMEDriver.cpp @@ -264,6 +264,9 @@ int JackWinMMEDriver::Close() { jack_log("JackWinMMEDriver::Close"); + // Generic midi driver close + int res = JackMidiDriver::Close(); + // Close input if (fMidiDestination) { for (int i = 0; i < fRealCaptureChannels; i++) { @@ -280,7 +283,7 @@ int JackWinMMEDriver::Close() delete[] fMidiSource; } - return 0; + return res; } int JackWinMMEDriver::Attach() diff --git a/wscript b/wscript index 43ab73a2..dedd86eb 100644 --- a/wscript +++ b/wscript @@ -129,23 +129,33 @@ def configure(conf): conf.fatal('jackdbus was explicitly requested but cannot be built') conf.sub_config('example-clients') - if conf.check_cfg(package='celt', atleast_version='0.8.0', args='--cflags --libs'): + if conf.check_cfg(package='celt', atleast_version='0.11.0', args='--cflags --libs'): conf.define('HAVE_CELT', 1) + conf.define('HAVE_CELT_API_0_11', 1) + conf.define('HAVE_CELT_API_0_8', 0) + conf.define('HAVE_CELT_API_0_7', 0) + conf.define('HAVE_CELT_API_0_5', 0) + elif conf.check_cfg(package='celt', atleast_version='0.8.0', args='--cflags --libs'): + conf.define('HAVE_CELT', 1) + conf.define('HAVE_CELT_API_0_11', 0) conf.define('HAVE_CELT_API_0_8', 1) conf.define('HAVE_CELT_API_0_7', 0) conf.define('HAVE_CELT_API_0_5', 0) elif conf.check_cfg(package='celt', atleast_version='0.7.0', args='--cflags --libs'): conf.define('HAVE_CELT', 1) + conf.define('HAVE_CELT_API_0_11', 0) conf.define('HAVE_CELT_API_0_8', 0) conf.define('HAVE_CELT_API_0_7', 1) conf.define('HAVE_CELT_API_0_5', 0) elif conf.check_cfg(package='celt', atleast_version='0.5.0', args='--cflags --libs', required=True): conf.define('HAVE_CELT', 1) + conf.define('HAVE_CELT_API_0_11', 0) conf.define('HAVE_CELT_API_0_8', 0) conf.define('HAVE_CELT_API_0_7', 0) conf.define('HAVE_CELT_API_0_5', 1) else: conf.define('HAVE_CELT', 0) + conf.define('HAVE_CELT_API_0_11', 0) conf.define('HAVE_CELT_API_0_8', 0) conf.define('HAVE_CELT_API_0_7', 0) conf.define('HAVE_CELT_API_0_5', 0)