| @@ -0,0 +1,14 @@ | |||||
| .PHONY: all | |||||
| all: | |||||
| CC=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-gcc CXX=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ AR=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-ar LDFLAGS="-L${INSTALL_ROOT_nto}/aarch64le/lib -L${INSTALL_ROOT_nto}/aarch64le/usr/lib -L${QNX_TARGET}/aarch64le/lib -L${QNX_TARGET}/aarch64le/usr/lib" PKG_CONFIG_LIBDIR=${INSTALL_ROOT_nto}/aarch64le/usr/lib/pkgconfig ./waf configure --platform=qnx --prefix=/usr --libdir=/usr/lib64 | |||||
| ./waf build | |||||
| ./waf install --destdir=${INSTALL_ROOT_nto}/aarch64le | |||||
| .PHONY: install | |||||
| install: all | |||||
| .PHONY:clean | |||||
| clean: | |||||
| # ignore error codes otherwise it would for example fail if clean is called before configure | |||||
| -./waf clean | |||||
| @@ -277,6 +277,8 @@ extern "C" | |||||
| LIB_EXPORT void jack_uuid_unparse(jack_uuid_t, char buf[JACK_UUID_STRING_SIZE]); | LIB_EXPORT void jack_uuid_unparse(jack_uuid_t, char buf[JACK_UUID_STRING_SIZE]); | ||||
| LIB_EXPORT int jack_uuid_empty(jack_uuid_t); | LIB_EXPORT int jack_uuid_empty(jack_uuid_t); | ||||
| LIB_EXPORT int jack_client_reload_master(jack_client_t* ext_client); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -2140,3 +2142,17 @@ LIB_EXPORT int jack_uuid_empty(jack_uuid_t u) | |||||
| { | { | ||||
| return u == JACK_UUID_EMPTY_INITIALIZER; | return u == JACK_UUID_EMPTY_INITIALIZER; | ||||
| } | } | ||||
| LIB_EXPORT int jack_client_reload_master(jack_client_t* ext_client) | |||||
| { | |||||
| JackGlobals::CheckContext("jack_client_reload_master"); | |||||
| JackClient* client = (JackClient*)ext_client; | |||||
| if (client == NULL) { | |||||
| jack_error("jack_client_reload_master called with a NULL client"); | |||||
| return -1; | |||||
| } else { | |||||
| WaitGraphChange(); | |||||
| return client->ClientReloadMaster(); | |||||
| } | |||||
| } | |||||
| @@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #endif | #endif | ||||
| #include "JackAudioAdapter.h" | #include "JackAudioAdapter.h" | ||||
| #ifndef MY_TARGET_OS_IPHONE | |||||
| #if !defined(MY_TARGET_OS_IPHONE) && !defined(__QNXNTO__) | |||||
| #include "JackLibSampleRateResampler.h" | #include "JackLibSampleRateResampler.h" | ||||
| #endif | #endif | ||||
| #include "JackTime.h" | #include "JackTime.h" | ||||
| @@ -185,7 +185,7 @@ namespace Jack | |||||
| fRunning = false; | fRunning = false; | ||||
| } | } | ||||
| #ifdef MY_TARGET_OS_IPHONE | |||||
| #if defined(MY_TARGET_OS_IPHONE) || defined(__QNXNTO__) | |||||
| void JackAudioAdapterInterface::Create() | void JackAudioAdapterInterface::Create() | ||||
| {} | {} | ||||
| #else | #else | ||||
| @@ -199,7 +199,19 @@ int JackAudioDriver::Write() | |||||
| int JackAudioDriver::Process() | int JackAudioDriver::Process() | ||||
| { | { | ||||
| return (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync(); | |||||
| int err = 0; | |||||
| int retries = -1; | |||||
| while (retries++ < fMaxRetryCount) { | |||||
| err = (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync(); | |||||
| if (err == 0) { | |||||
| break; | |||||
| } | |||||
| jack_error("JackAudioDriver::Process failed, retry %d", retries); | |||||
| } | |||||
| return err; | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -211,13 +223,13 @@ int JackAudioDriver::ProcessAsync() | |||||
| { | { | ||||
| // Read input buffers for the current cycle | // Read input buffers for the current cycle | ||||
| if (Read() < 0) { | if (Read() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessAsync: read error, stopping..."); | |||||
| jack_error("JackAudioDriver::ProcessAsync: read error"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| // Write output buffers from the previous cycle | // Write output buffers from the previous cycle | ||||
| if (Write() < 0) { | if (Write() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessAsync: write error, stopping..."); | |||||
| jack_error("JackAudioDriver::ProcessAsync: write error"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -285,7 +297,7 @@ int JackAudioDriver::ProcessSync() | |||||
| { | { | ||||
| // Read input buffers for the current cycle | // Read input buffers for the current cycle | ||||
| if (Read() < 0) { | if (Read() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessSync: read error, stopping..."); | |||||
| jack_error("JackAudioDriver::ProcessSync: read error"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -294,7 +306,7 @@ int JackAudioDriver::ProcessSync() | |||||
| // Write output buffers from the current cycle | // Write output buffers from the current cycle | ||||
| if (Write() < 0) { | if (Write() < 0) { | ||||
| jack_error("JackAudioDriver::ProcessSync: write error, stopping..."); | |||||
| jack_error("JackAudioDriver::ProcessSync: write error"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -61,6 +61,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver | |||||
| void ProcessGraphSyncMaster(); | void ProcessGraphSyncMaster(); | ||||
| void ProcessGraphSyncSlave(); | void ProcessGraphSyncSlave(); | ||||
| static const int fMaxRetryCount = 5; | |||||
| public: | public: | ||||
| JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | ||||
| @@ -137,6 +137,9 @@ class JackClientChannelInterface | |||||
| virtual void ClientDeactivate(int refnum, int* result) | virtual void ClientDeactivate(int refnum, int* result) | ||||
| {} | {} | ||||
| virtual void ClientReloadMaster(int* result) | |||||
| {} | |||||
| virtual void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result) | virtual void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result) | ||||
| {} | {} | ||||
| virtual void PortUnRegister(int refnum, jack_port_id_t port_index, int* result) | virtual void PortUnRegister(int refnum, jack_port_id_t port_index, int* result) | ||||
| @@ -34,6 +34,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
| using namespace std; | using namespace std; | ||||
| #ifdef __QNXNTO__ | |||||
| void __attribute__((constructor)) init_output_for_percent_s_NULL_for_clients(); | |||||
| void init_output_for_percent_s_NULL_for_clients() | |||||
| { | |||||
| extern const char *output_for_percent_s_NULL; | |||||
| output_for_percent_s_NULL = "(null)"; | |||||
| } | |||||
| #endif | |||||
| namespace Jack | namespace Jack | ||||
| { | { | ||||
| @@ -493,6 +502,13 @@ int JackClient::Deactivate() | |||||
| if (IsRealTime()) { | if (IsRealTime()) { | ||||
| fThread.Kill(); | fThread.Kill(); | ||||
| } | } | ||||
| return result; | |||||
| } | |||||
| int JackClient::ClientReloadMaster() | |||||
| { | |||||
| int result = -1; | |||||
| fChannel->ClientReloadMaster(&result); | |||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -145,6 +145,8 @@ class SERVER_EXPORT JackClient : public JackClientInterface, public JackRunnable | |||||
| virtual int Activate(); | virtual int Activate(); | ||||
| virtual int Deactivate(); | virtual int Deactivate(); | ||||
| virtual int ClientReloadMaster(); | |||||
| // Context | // Context | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | virtual int SetBufferSize(jack_nframes_t buffer_size); | ||||
| virtual int SetFreeWheel(int onoff); | virtual int SetFreeWheel(int onoff); | ||||
| @@ -663,7 +663,10 @@ jackctl_setup_signals( | |||||
| sigfillset(&allsignals); | sigfillset(&allsignals); | ||||
| action.sa_handler = signal_handler; | action.sa_handler = signal_handler; | ||||
| action.sa_mask = allsignals; | action.sa_mask = allsignals; | ||||
| action.sa_flags = SA_RESTART|SA_RESETHAND; | |||||
| action.sa_flags = SA_RESETHAND; | |||||
| #ifndef __QNXNTO__ | |||||
| action.sa_flags |= SA_RESTART; | |||||
| #endif | |||||
| for (i = 1; i < NSIG; i++) | for (i = 1; i < NSIG; i++) | ||||
| { | { | ||||
| @@ -110,6 +110,10 @@ int JackDriver::Open(jack_nframes_t buffer_size, | |||||
| fClientControl.fRefNum = refnum; | fClientControl.fRefNum = refnum; | ||||
| fClientControl.fActive = true; | fClientControl.fActive = true; | ||||
| fEngineControl->fDriverNum++; | fEngineControl->fDriverNum++; | ||||
| if (buffer_size > BUFFER_SIZE_MAX) { | |||||
| jack_error("Buffer size %ld exceeds BUFFER_SIZE_MAX %d", buffer_size, BUFFER_SIZE_MAX); | |||||
| return -1; | |||||
| } | |||||
| if (buffer_size > 0) { | if (buffer_size > 0) { | ||||
| fEngineControl->fBufferSize = buffer_size; | fEngineControl->fBufferSize = buffer_size; | ||||
| } | } | ||||
| @@ -351,6 +355,11 @@ int JackDriver::Stop() | |||||
| return StopSlaves(); | return StopSlaves(); | ||||
| } | } | ||||
| int JackDriver::Reload() | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| int JackDriver::StartSlaves() | int JackDriver::StartSlaves() | ||||
| { | { | ||||
| int res = 0; | int res = 0; | ||||
| @@ -72,6 +72,7 @@ class SERVER_EXPORT JackDriverInterface | |||||
| virtual int Start() = 0; | virtual int Start() = 0; | ||||
| virtual int Stop() = 0; | virtual int Stop() = 0; | ||||
| virtual int Reload() = 0; | |||||
| virtual bool IsFixedBufferSize() = 0; | virtual bool IsFixedBufferSize() = 0; | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | virtual int SetBufferSize(jack_nframes_t buffer_size) = 0; | ||||
| @@ -227,6 +228,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface | |||||
| virtual int Start(); | virtual int Start(); | ||||
| virtual int Stop(); | virtual int Stop(); | ||||
| virtual int Reload(); | |||||
| // For "master" driver | // For "master" driver | ||||
| int ProcessReadSlaves(); | int ProcessReadSlaves(); | ||||
| @@ -137,6 +137,13 @@ void JackGenericClientChannel::ClientDeactivate(int refnum, int* result) | |||||
| ServerSyncCall(&req, &res, result); | ServerSyncCall(&req, &res, result); | ||||
| } | } | ||||
| void JackGenericClientChannel::ClientReloadMaster(int *result) | |||||
| { | |||||
| JackClientReloadMasterRequest req; | |||||
| JackResult res; | |||||
| ServerSyncCall(&req, &res, result); | |||||
| } | |||||
| void JackGenericClientChannel::PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result) | void JackGenericClientChannel::PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result) | ||||
| { | { | ||||
| JackPortRegisterRequest req(refnum, name, type, flags, buffer_size); | JackPortRegisterRequest req(refnum, name, type, flags, buffer_size); | ||||
| @@ -62,6 +62,8 @@ class JackGenericClientChannel : public detail::JackClientChannelInterface | |||||
| void ClientActivate(int refnum, int is_real_time, int* result); | void ClientActivate(int refnum, int is_real_time, int* result); | ||||
| void ClientDeactivate(int refnum, int* result); | void ClientDeactivate(int refnum, int* result); | ||||
| void ClientReloadMaster(int* result); | |||||
| void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result); | void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result); | ||||
| void PortUnRegister(int refnum, jack_port_id_t port_index, int* result); | void PortUnRegister(int refnum, jack_port_id_t port_index, int* result); | ||||
| @@ -90,7 +90,8 @@ struct JackRequest | |||||
| kGetUUIDByClient = 37, | kGetUUIDByClient = 37, | ||||
| kClientHasSessionCallback = 38, | kClientHasSessionCallback = 38, | ||||
| kComputeTotalLatencies = 39, | kComputeTotalLatencies = 39, | ||||
| kPropertyChangeNotify = 40 | |||||
| kPropertyChangeNotify = 40, | |||||
| kClientReloadMaster = 41, | |||||
| }; | }; | ||||
| RequestType fType; | RequestType fType; | ||||
| @@ -1736,6 +1737,31 @@ struct JackClientNotification | |||||
| }; | }; | ||||
| /*! | |||||
| \brief Restart Master Backend Request. | |||||
| */ | |||||
| struct JackClientReloadMasterRequest : public JackRequest | |||||
| { | |||||
| JackClientReloadMasterRequest(): JackRequest(JackRequest::kClientReloadMaster) | |||||
| { | |||||
| } | |||||
| int Read(detail::JackChannelTransactionInterface* trans) | |||||
| { | |||||
| CheckSize(); | |||||
| return 0; | |||||
| } | |||||
| int Write(detail::JackChannelTransactionInterface* trans) | |||||
| { | |||||
| CheckRes(JackRequest::Write(trans, Size())); | |||||
| return 0; | |||||
| } | |||||
| int Size() { return 0; } | |||||
| }; | |||||
| } // end of namespace | } // end of namespace | ||||
| #endif | #endif | ||||
| @@ -346,6 +346,16 @@ int JackRequestDecoder::HandleRequest(detail::JackChannelTransactionInterface* s | |||||
| break; | break; | ||||
| } | } | ||||
| case JackRequest::kClientReloadMaster: { | |||||
| jack_log("JackRequest::ClientReloadMaster"); | |||||
| JackClientReloadMasterRequest req; | |||||
| JackResult res; | |||||
| CheckRead(req, socket); | |||||
| res.fResult = fServer->ReloadMaster(); | |||||
| CheckWrite("JackRequest::ClientReloadMaster", socket); | |||||
| break; | |||||
| } | |||||
| default: | default: | ||||
| jack_error("Unknown request %ld", type); | jack_error("Unknown request %ld", type); | ||||
| return -1; | return -1; | ||||
| @@ -430,6 +430,11 @@ error: | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| int JackServer::ReloadMaster() | |||||
| { | |||||
| return fAudioDriver->Reload(); | |||||
| } | |||||
| //---------------------- | //---------------------- | ||||
| // Transport management | // Transport management | ||||
| //---------------------- | //---------------------- | ||||
| @@ -98,6 +98,7 @@ class SERVER_EXPORT JackServer | |||||
| JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); | JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); | ||||
| void RemoveSlave(JackDriverInfo* info); | void RemoveSlave(JackDriverInfo* info); | ||||
| int SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params); | int SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params); | ||||
| int ReloadMaster(); | |||||
| // Object access | // Object access | ||||
| JackLockedEngine* GetEngine(); | JackLockedEngine* GetEngine(); | ||||
| @@ -239,6 +239,28 @@ int JackThreadedDriver::Stop() | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| int JackThreadedDriver::Reload() | |||||
| { | |||||
| if (Stop() < 0) { | |||||
| jack_error("JackThreadedDriver::Reload stop failed"); | |||||
| return -1; | |||||
| } | |||||
| // not able to use Close() and Open() since we dont have original Open() parameters, these | |||||
| // are internal to fDriver, reload should reopen with same parameters | |||||
| if (fDriver->Reload() < 0) { | |||||
| jack_error("JackThreadedDriver::Reload reload failed"); | |||||
| return -1; | |||||
| } | |||||
| if (Start() < 0) { | |||||
| jack_error("JackThreadedDriver::Reload start failed"); | |||||
| return -1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| bool JackThreadedDriver::Execute() | bool JackThreadedDriver::Execute() | ||||
| { | { | ||||
| return (Process() == 0); | return (Process() == 0); | ||||
| @@ -70,6 +70,7 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi | |||||
| virtual int Start(); | virtual int Start(); | ||||
| virtual int Stop(); | virtual int Stop(); | ||||
| virtual int Reload(); | |||||
| virtual bool IsFixedBufferSize(); | virtual bool IsFixedBufferSize(); | ||||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | virtual int SetBufferSize(jack_nframes_t buffer_size); | ||||
| @@ -139,6 +139,22 @@ int jack_client_close (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||||
| */ | */ | ||||
| int jack_client_name_size (void) JACK_OPTIONAL_WEAK_EXPORT; | int jack_client_name_size (void) JACK_OPTIONAL_WEAK_EXPORT; | ||||
| /** | |||||
| * Reloads audio backend. | |||||
| * | |||||
| * This is useful when client wants audio backend to reload its state. | |||||
| * Currently used only for alsa audio backend. | |||||
| * | |||||
| * Alsa backend will close or open audio devices on reload depending on | |||||
| * the state of the ports asociated with audio device. If all ports | |||||
| * are disconnected audio device is closed, opened otherwise. This | |||||
| * behaviour is modifiable by alsa backend options provided to jackd | |||||
| * on startup. | |||||
| * | |||||
| * @return 0 if successful. | |||||
| */ | |||||
| int jack_client_reload_master(jack_client_t* ext_client) JACK_OPTIONAL_WEAK_EXPORT; | |||||
| /** | /** | ||||
| * @return pointer to actual client name. This is useful when @ref | * @return pointer to actual client name. This is useful when @ref | ||||
| * JackUseExactName is not specified on open and @ref | * JackUseExactName is not specified on open and @ref | ||||
| @@ -107,7 +107,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #endif /* _WIN32 && !__CYGWIN__ && !GNU_WIN32 */ | #endif /* _WIN32 && !__CYGWIN__ && !GNU_WIN32 */ | ||||
| #if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) | |||||
| #if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) || defined(__QNXNTO__) | |||||
| #if defined(__CYGWIN__) || defined(GNU_WIN32) | #if defined(__CYGWIN__) || defined(GNU_WIN32) | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| @@ -428,7 +428,9 @@ netjack_poll (int sockfd, int timeout) | |||||
| action.sa_handler = SIG_DFL; | action.sa_handler = SIG_DFL; | ||||
| action.sa_mask = sigmask; | action.sa_mask = sigmask; | ||||
| #ifndef __QNXNTO__ | |||||
| action.sa_flags = SA_RESTART; | action.sa_flags = SA_RESTART; | ||||
| #endif | |||||
| for (i = 1; i < NSIG; i++) | for (i = 1; i < NSIG; i++) | ||||
| if (sigismember (&sigmask, i)) | if (sigismember (&sigmask, i)) | ||||
| @@ -49,11 +49,16 @@ | |||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||
| #include <sys/shm.h> | |||||
| #include <sys/sem.h> | #include <sys/sem.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include "promiscuous.h" | #include "promiscuous.h" | ||||
| #ifdef __QNXNTO__ | |||||
| #include <sys/mman.h> | |||||
| #else | |||||
| #include <sys/shm.h> | |||||
| #endif | |||||
| #endif | #endif | ||||
| #include "shm.h" | #include "shm.h" | ||||
| @@ -148,8 +153,6 @@ static jack_shm_registry_t *jack_shm_registry = NULL; | |||||
| #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY | #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY | ||||
| #endif | #endif | ||||
| static int semid = -1; | |||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| #include <psapi.h> | #include <psapi.h> | ||||
| @@ -178,12 +181,61 @@ static BOOL check_process_running(DWORD process_id) | |||||
| } | } | ||||
| static int | static int | ||||
| semaphore_init () {return 0;} | |||||
| jack_shm_lock_registry () {return 0;} | |||||
| static void | |||||
| jack_shm_unlock_registry () { } | |||||
| #elif __QNXNTO__ | |||||
| #include <semaphore.h> | |||||
| static sem_t* semid = SEM_FAILED; | |||||
| static int | |||||
| semaphore_init () | |||||
| { | |||||
| const char name[] = "/jack-shm-registry-lock"; | |||||
| const int oflag = O_CREAT | O_RDWR; | |||||
| const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; | |||||
| if ((semid = sem_open(name, oflag, mode, 1)) == SEM_FAILED) { | |||||
| jack_error("Creating semaphore %s failed", name); | |||||
| return -1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int | |||||
| jack_shm_lock_registry (void) | |||||
| { | |||||
| if (semid == SEM_FAILED) { | |||||
| if (semaphore_init () < 0) | |||||
| return -1; | |||||
| } | |||||
| // TODO automatically unblock in case the process terminates | |||||
| const int ret = sem_wait(semid); | |||||
| if (ret < 0) { | |||||
| jack_error("sem_wait() failed with %s", strerror(ret)); | |||||
| return -1; | |||||
| } | |||||
| static int | |||||
| semaphore_add (int value) {return 0;} | |||||
| return 0; | |||||
| } | |||||
| static void | |||||
| jack_shm_unlock_registry (void) | |||||
| { | |||||
| const int ret = sem_post(semid); | |||||
| if (ret < 0) { | |||||
| jack_error("sem_post() failed with %s", strerror(ret)); | |||||
| } | |||||
| } | |||||
| #else | #else | ||||
| static int semid = -1; | |||||
| /* all semaphore errors are fatal -- issue message, but do not return */ | /* all semaphore errors are fatal -- issue message, but do not return */ | ||||
| static void | static void | ||||
| semaphore_error (char *msg) | semaphore_error (char *msg) | ||||
| @@ -247,8 +299,6 @@ semaphore_add (int value) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| #endif | |||||
| static int | static int | ||||
| jack_shm_lock_registry (void) | jack_shm_lock_registry (void) | ||||
| { | { | ||||
| @@ -266,6 +316,8 @@ jack_shm_unlock_registry (void) | |||||
| semaphore_add (1); | semaphore_add (1); | ||||
| } | } | ||||
| #endif | |||||
| static void | static void | ||||
| jack_shm_init_registry () | jack_shm_init_registry () | ||||
| { | { | ||||
| @@ -1308,4 +1360,3 @@ jack_attach_shm_read (jack_shm_info_t* si) | |||||
| } | } | ||||
| #endif /* !USE_POSIX_SHM */ | #endif /* !USE_POSIX_SHM */ | ||||
| @@ -28,6 +28,8 @@ def create_jack_process_obj(bld, target, sources, uselib = None, framework = Non | |||||
| env_includes = ['../macosx', '../posix', '../macosx/coreaudio'] | env_includes = ['../macosx', '../posix', '../macosx/coreaudio'] | ||||
| if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
| env_includes = ['../linux', '../posix', '../linux/alsa'] | env_includes = ['../linux', '../posix', '../linux/alsa'] | ||||
| if bld.env['IS_QNX']: | |||||
| env_includes = ['../qnx', '../posix'] | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| env_includes = ['../solaris', '../posix', '../solaris/oss'] | env_includes = ['../solaris', '../posix', '../solaris/oss'] | ||||
| if bld.env['IS_WINDOWS']: | if bld.env['IS_WINDOWS']: | ||||
| @@ -36,7 +38,7 @@ def create_jack_process_obj(bld, target, sources, uselib = None, framework = Non | |||||
| process.name = target | process.name = target | ||||
| process.target = target | process.target = target | ||||
| process.source = sources | process.source = sources | ||||
| if bld.env['IS_LINUX'] or bld.env['IS_MACOSX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_MACOSX'] or bld.env['IS_QNX']: | |||||
| process.env.append_value('CPPFLAGS', '-fvisibility=hidden') | process.env.append_value('CPPFLAGS', '-fvisibility=hidden') | ||||
| process.install_path = '${ADDON_DIR}/' | process.install_path = '${ADDON_DIR}/' | ||||
| process.use = [uselib.name] | process.use = [uselib.name] | ||||
| @@ -92,6 +94,22 @@ def build(bld): | |||||
| uselib.append('RT') | uselib.append('RT') | ||||
| uselib.append('DL') | uselib.append('DL') | ||||
| if bld.env['IS_QNX']: | |||||
| common_libsources += [ | |||||
| 'JackDebugClient.cpp', | |||||
| 'timestamps.c', | |||||
| 'promiscuous.c', | |||||
| '../posix/JackPosixThread.cpp', | |||||
| '../posix/JackPosixProcessSync.cpp', | |||||
| '../posix/JackPosixMutex.cpp', | |||||
| '../posix/JackSocket.cpp', | |||||
| '../posix/JackFifo.cpp', | |||||
| '../linux/JackLinuxTime.c', | |||||
| ] | |||||
| includes = ['../qnx', '../posix'] + includes | |||||
| uselib.append('SOCKET') | |||||
| # libdl and librt is included in libc in QNX | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| common_libsources += [ | common_libsources += [ | ||||
| 'JackDebugClient.cpp', | 'JackDebugClient.cpp', | ||||
| @@ -163,7 +181,7 @@ def build(bld): | |||||
| 'JackMetadata.cpp', | 'JackMetadata.cpp', | ||||
| ] | ] | ||||
| if bld.env['IS_LINUX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_QNX']: | |||||
| clientlib.source += [ | clientlib.source += [ | ||||
| '../posix/JackSocketClientChannel.cpp', | '../posix/JackSocketClientChannel.cpp', | ||||
| '../posix/JackPosixServerLaunch.cpp', | '../posix/JackPosixServerLaunch.cpp', | ||||
| @@ -192,7 +210,7 @@ def build(bld): | |||||
| if not bld.env['IS_WINDOWS']: | if not bld.env['IS_WINDOWS']: | ||||
| clientlib.vnum = bld.env['JACK_API_VERSION'] | clientlib.vnum = bld.env['JACK_API_VERSION'] | ||||
| if bld.env['IS_LINUX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_QNX']: | |||||
| clientlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | clientlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | ||||
| if bld.env['IS_MACOSX']: | if bld.env['IS_MACOSX']: | ||||
| @@ -270,7 +288,7 @@ def build(bld): | |||||
| 'JackMetadata.cpp', | 'JackMetadata.cpp', | ||||
| ] | ] | ||||
| if bld.env['IS_LINUX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_QNX']: | |||||
| serverlib.source += [ | serverlib.source += [ | ||||
| '../posix/JackSocketServerChannel.cpp', | '../posix/JackSocketServerChannel.cpp', | ||||
| '../posix/JackSocketNotifyChannel.cpp', | '../posix/JackSocketNotifyChannel.cpp', | ||||
| @@ -307,7 +325,7 @@ def build(bld): | |||||
| if not bld.env['IS_WINDOWS']: | if not bld.env['IS_WINDOWS']: | ||||
| serverlib.vnum = bld.env['JACK_API_VERSION'] | serverlib.vnum = bld.env['JACK_API_VERSION'] | ||||
| if bld.env['IS_LINUX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_QNX']: | |||||
| serverlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | serverlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | ||||
| if bld.env['IS_MACOSX']: | if bld.env['IS_MACOSX']: | ||||
| @@ -333,7 +351,7 @@ def build(bld): | |||||
| if skipshared: | if skipshared: | ||||
| netlib.env['SHLIB_MARKER'] = '' | netlib.env['SHLIB_MARKER'] = '' | ||||
| netlib.use += ['WS2_32', 'WINMM'] | netlib.use += ['WS2_32', 'WINMM'] | ||||
| elif not bld.env['IS_MACOSX']: | |||||
| elif not bld.env['IS_MACOSX'] and not bld.env['IS_QNX']: | |||||
| netlib.use += ['RT'] | netlib.use += ['RT'] | ||||
| netlib.install_path = '${LIBDIR}' | netlib.install_path = '${LIBDIR}' | ||||
| netlib.source = [ | netlib.source = [ | ||||
| @@ -347,7 +365,7 @@ def build(bld): | |||||
| 'JackGlobals.cpp', | 'JackGlobals.cpp', | ||||
| 'ringbuffer.c'] | 'ringbuffer.c'] | ||||
| if bld.env['IS_LINUX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_QNX']: | |||||
| netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../linux/JackLinuxTime.c'] | netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../linux/JackLinuxTime.c'] | ||||
| netlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | netlib.env.append_value('CPPFLAGS', '-fvisibility=hidden') | ||||
| @@ -0,0 +1,32 @@ | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #include <jack/jack.h> | |||||
| int main(int argc, char* argv[]) | |||||
| { | |||||
| if (argc < 2) { | |||||
| printf("usage: %s [server_name [server_name ...]]", argv[0]); | |||||
| return 1; | |||||
| } | |||||
| const int client_count = argc - 1; | |||||
| char** server_names = &argv[1]; | |||||
| jack_client_t* clients[client_count]; | |||||
| for (int i = 0; i < client_count; ++i) { | |||||
| const jack_options_t options = (jack_options_t) (JackNoStartServer | JackServerName); | |||||
| jack_status_t status; | |||||
| printf("Connecting to JACK server %s\n", server_names[i]); | |||||
| clients[i] = jack_client_open("reload", options, &status, server_names[i]); | |||||
| jack_client_reload_master(clients[i]); | |||||
| } | |||||
| for (int i = 0; i < client_count; ++i) { | |||||
| jack_client_close(clients[i]); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @@ -31,6 +31,7 @@ example_programs = { | |||||
| 'jack_midi_latency_test' : 'midi_latency_test.c', | 'jack_midi_latency_test' : 'midi_latency_test.c', | ||||
| 'jack_simdtests' : 'simdtests.cpp', | 'jack_simdtests' : 'simdtests.cpp', | ||||
| 'jack_property' : 'property.c', | 'jack_property' : 'property.c', | ||||
| 'jack_reload' : 'reload.c', | |||||
| } | } | ||||
| example_libs = { | example_libs = { | ||||
| @@ -49,6 +50,8 @@ def build(bld): | |||||
| os_incdir = ['../linux', '../posix'] | os_incdir = ['../linux', '../posix'] | ||||
| if bld.env['IS_MACOSX']: | if bld.env['IS_MACOSX']: | ||||
| os_incdir = ['../macosx', '../posix'] | os_incdir = ['../macosx', '../posix'] | ||||
| if bld.env['IS_QNX']: | |||||
| os_incdir = ['../qnx', '../posix'] | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| os_incdir = ['../solaris', '../posix'] | os_incdir = ['../solaris', '../posix'] | ||||
| if bld.env['IS_WINDOWS']: | if bld.env['IS_WINDOWS']: | ||||
| @@ -76,7 +79,7 @@ def build(bld): | |||||
| prog.use = use | prog.use = use | ||||
| if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
| prog.use += ['RT', 'M'] | prog.use += ['RT', 'M'] | ||||
| if bld.env['IS_SUN']: | |||||
| if bld.env['IS_SUN'] or bld.env['IS_QNX']: | |||||
| prog.use += ['M'] | prog.use += ['M'] | ||||
| #prog.cflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation'] | #prog.cflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation'] | ||||
| #prog.cxxflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation'] | #prog.cxxflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation'] | ||||
| @@ -90,7 +93,7 @@ def build(bld): | |||||
| prog.use = ['clientlib'] | prog.use = ['clientlib'] | ||||
| if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
| prog.use += ['RT', 'READLINE'] | prog.use += ['RT', 'READLINE'] | ||||
| if bld.env['IS_MACOSX']: | |||||
| if bld.env['IS_MACOSX'] or bld.env['IS_QNX']: | |||||
| prog.use += ['READLINE'] | prog.use += ['READLINE'] | ||||
| if bld.env['IS_WINDOWS']: | if bld.env['IS_WINDOWS']: | ||||
| prog.use += ['READLINE'] | prog.use += ['READLINE'] | ||||
| @@ -101,7 +104,7 @@ def build(bld): | |||||
| prog.includes = os_incdir + ['../common/jack', '../common'] | prog.includes = os_incdir + ['../common/jack', '../common'] | ||||
| prog.source = 'capture_client.c' | prog.source = 'capture_client.c' | ||||
| prog.use = ['clientlib'] | prog.use = ['clientlib'] | ||||
| if bld.env['IS_MACOSX']: | |||||
| if bld.env['IS_MACOSX'] or bld.env['IS_QNX']: | |||||
| prog.use += ['SNDFILE'] | prog.use += ['SNDFILE'] | ||||
| if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
| prog.use += ['RT', 'SNDFILE'] | prog.use += ['RT', 'SNDFILE'] | ||||
| @@ -111,7 +114,7 @@ def build(bld): | |||||
| prog.uselib = ['SNDFILE'] | prog.uselib = ['SNDFILE'] | ||||
| prog.target = 'jack_rec' | prog.target = 'jack_rec' | ||||
| if bld.env['IS_LINUX'] or bld.env['IS_MACOSX']: | |||||
| if bld.env['IS_LINUX'] or bld.env['IS_MACOSX'] or bld.env['IS_QNX']: | |||||
| prog = bld(features = 'c cprogram') | prog = bld(features = 'c cprogram') | ||||
| prog.includes = os_incdir + ['.', '..', '../common/jack', '../common'] | prog.includes = os_incdir + ['.', '..', '../common/jack', '../common'] | ||||
| prog.source = ['netsource.c', '../common/netjack_packet.c'] | prog.source = ['netsource.c', '../common/netjack_packet.c'] | ||||
| @@ -32,6 +32,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/time.h> | #include <sys/time.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <sstream> | |||||
| #include <fstream> | |||||
| #include <algorithm> | |||||
| #include <cctype> | |||||
| #include <vector> | |||||
| #include "JackAlsaDriver.h" | #include "JackAlsaDriver.h" | ||||
| #include "JackEngineControl.h" | #include "JackEngineControl.h" | ||||
| @@ -126,7 +131,7 @@ void JackAlsaDriver::UpdateLatencies() | |||||
| int JackAlsaDriver::Attach() | int JackAlsaDriver::Attach() | ||||
| { | { | ||||
| JackPort* port; | JackPort* port; | ||||
| jack_port_id_t port_index; | |||||
| jack_port_id_t port_id; | |||||
| unsigned long port_flags = (unsigned long)CaptureDriverFlags; | unsigned long port_flags = (unsigned long)CaptureDriverFlags; | ||||
| char name[REAL_JACK_PORT_NAME_SIZE+1]; | char name[REAL_JACK_PORT_NAME_SIZE+1]; | ||||
| char alias[REAL_JACK_PORT_NAME_SIZE+1]; | char alias[REAL_JACK_PORT_NAME_SIZE+1]; | ||||
| @@ -145,41 +150,47 @@ int JackAlsaDriver::Attach() | |||||
| jack_log("JackAlsaDriver::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), "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); | |||||
| snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) { | |||||
| for (int i = 0, port_list_index = 0; i < alsa_driver->devices_c_count; ++i) { | |||||
| alsa_device_t *device = &alsa_driver->devices[i]; | |||||
| for (int j = 0; j < device->capture_nchannels; ++j, ++port_list_index) { | |||||
| snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, port_list_index + 1); | |||||
| snprintf(alias, sizeof(alias), "%s:%s:capture_%d", fAliasName, device->capture_name, j + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_id) < 0) { | |||||
| jack_error("driver: cannot register port for %s", name); | jack_error("driver: cannot register port for %s", name); | ||||
| return -1; | |||||
| return -1; | |||||
| } | |||||
| port = fGraphManager->GetPort(port_id); | |||||
| port->SetAlias(alias); | |||||
| fCapturePortList[port_list_index] = port_id; | |||||
| jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_id); | |||||
| } | } | ||||
| port = fGraphManager->GetPort(port_index); | |||||
| port->SetAlias(alias); | |||||
| fCapturePortList[i] = port_index; | |||||
| jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_index); | |||||
| } | } | ||||
| port_flags = (unsigned long)PlaybackDriverFlags; | port_flags = (unsigned long)PlaybackDriverFlags; | ||||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||||
| snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); | |||||
| snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) { | |||||
| jack_error("driver: cannot register port for %s", name); | |||||
| return -1; | |||||
| } | |||||
| port = fGraphManager->GetPort(port_index); | |||||
| port->SetAlias(alias); | |||||
| fPlaybackPortList[i] = port_index; | |||||
| jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||||
| for (int i = 0, port_list_index = 0; i < alsa_driver->devices_p_count; ++i) { | |||||
| alsa_device_t *device = &alsa_driver->devices[i]; | |||||
| for (int j = 0; j < device->playback_nchannels; ++j, ++port_list_index) { | |||||
| snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, port_list_index + 1); | |||||
| snprintf(alias, sizeof(alias), "%s:%s:playback_%d", fAliasName, device->playback_name, j + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_id) < 0) { | |||||
| jack_error("driver: cannot register port for %s", name); | |||||
| return -1; | |||||
| } | |||||
| port = fGraphManager->GetPort(port_id); | |||||
| port->SetAlias(alias); | |||||
| fPlaybackPortList[port_list_index] = port_id; | |||||
| jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_id); | |||||
| // Monitor ports | |||||
| if (fWithMonitorPorts) { | |||||
| jack_log("Create monitor port"); | |||||
| snprintf(name, sizeof(name), "%s:monitor_%d", fClientControl.fName, i + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) { | |||||
| jack_error("ALSA: cannot register monitor port for %s", name); | |||||
| } else { | |||||
| fMonitorPortList[i] = port_index; | |||||
| // Monitor ports | |||||
| if (fWithMonitorPorts) { | |||||
| jack_log("Create monitor port"); | |||||
| snprintf(name, sizeof(name), "%s:monitor_%d", fClientControl.fName, port_list_index + 1); | |||||
| if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_id) < 0) { | |||||
| jack_error("ALSA: cannot register monitor port for %s", name); | |||||
| } else { | |||||
| fMonitorPortList[port_list_index] = port_id; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -204,6 +215,7 @@ int JackAlsaDriver::Detach() | |||||
| return JackAudioDriver::Detach(); | return JackAudioDriver::Detach(); | ||||
| } | } | ||||
| #ifndef __QNXNTO__ | |||||
| extern "C" char* get_control_device_name(const char * device_name) | extern "C" char* get_control_device_name(const char * device_name) | ||||
| { | { | ||||
| char * ctl_name; | char * ctl_name; | ||||
| @@ -233,7 +245,9 @@ extern "C" char* get_control_device_name(const char * device_name) | |||||
| return ctl_name; | return ctl_name; | ||||
| } | } | ||||
| #endif | |||||
| #ifndef __QNXNTO__ | |||||
| static int card_to_num(const char* device) | static int card_to_num(const char* device) | ||||
| { | { | ||||
| int err; | int err; | ||||
| @@ -273,50 +287,47 @@ free: | |||||
| fail: | fail: | ||||
| return i; | return i; | ||||
| } | } | ||||
| #endif | |||||
| int JackAlsaDriver::Open(jack_nframes_t nframes, | |||||
| jack_nframes_t user_nperiods, | |||||
| jack_nframes_t samplerate, | |||||
| bool hw_monitoring, | |||||
| bool hw_metering, | |||||
| bool capturing, | |||||
| bool playing, | |||||
| DitherAlgorithm dither, | |||||
| bool soft_mode, | |||||
| bool monitor, | |||||
| int inchannels, | |||||
| int outchannels, | |||||
| bool shorts_first, | |||||
| const char* capture_driver_name, | |||||
| const char* playback_driver_name, | |||||
| jack_nframes_t capture_latency, | |||||
| jack_nframes_t playback_latency, | |||||
| const char* midi_driver_name) | |||||
| int JackAlsaDriver::Open(alsa_driver_info_t info) | |||||
| { | { | ||||
| // Generic JackAudioDriver Open | // Generic JackAudioDriver Open | ||||
| if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, | |||||
| inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, | |||||
| capture_latency, playback_latency) != 0) { | |||||
| if (JackAudioDriver::Open( | |||||
| info.frames_per_period, | |||||
| info.frame_rate, | |||||
| info.devices_capture_size > 0, | |||||
| info.devices_playback_size > 0, | |||||
| -1, | |||||
| -1, | |||||
| info.monitor, | |||||
| info.devices_capture_size > 0 ? info.devices[0].capture_name : "-", | |||||
| info.devices_playback_size > 0 ? info.devices[0].playback_name : "-", | |||||
| info.capture_latency, | |||||
| info.playback_latency) != 0) { | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| alsa_midi_t *midi = 0; | |||||
| jack_log("JackAlsaDriver::Open capture_driver_name = %s", info.devices_capture_size > 0 ? info.devices[0].capture_name : "-"); | |||||
| jack_log("JackAlsaDriver::Open playback_driver_name = %s", info.devices_playback_size > 0 ? info.devices[0].playback_name : "-"); | |||||
| #ifndef __QNXNTO__ | |||||
| #ifndef __ANDROID__ | #ifndef __ANDROID__ | ||||
| if (strcmp(midi_driver_name, "seq") == 0) | |||||
| midi = alsa_seqmidi_new((jack_client_t*)this, 0); | |||||
| else if (strcmp(midi_driver_name, "raw") == 0) | |||||
| midi = alsa_rawmidi_new((jack_client_t*)this); | |||||
| if (strcmp(info.midi_name, "seq") == 0) | |||||
| info.midi_driver = alsa_seqmidi_new((jack_client_t*)this, 0); | |||||
| else if (strcmp(info.midi_name, "raw") == 0) | |||||
| info.midi_driver = alsa_rawmidi_new((jack_client_t*)this); | |||||
| #endif | #endif | ||||
| // FIXME: needs adaptation for multiple drivers | |||||
| if (JackServerGlobals::on_device_acquire != NULL) { | if (JackServerGlobals::on_device_acquire != NULL) { | ||||
| int capture_card = card_to_num(capture_driver_name); | |||||
| int playback_card = card_to_num(playback_driver_name); | |||||
| int capture_card = card_to_num(info.devices_capture_size > 0 ? info.devices[0].capture_name : "-"); | |||||
| int playback_card = card_to_num(info.devices_playback_size > 0 ? info.devices[0].playback_name : "-"); | |||||
| char audio_name[32]; | char audio_name[32]; | ||||
| if (capture_card >= 0) { | if (capture_card >= 0) { | ||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | ||||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | if (!JackServerGlobals::on_device_acquire(audio_name)) { | ||||
| jack_error("Audio device %s cannot be acquired...", capture_driver_name); | |||||
| jack_error("Audio device %s cannot be acquired...", info.devices_capture_size > 0 ? info.devices[0].capture_name : "-"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -324,7 +335,7 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, | |||||
| if (playback_card >= 0 && playback_card != capture_card) { | if (playback_card >= 0 && playback_card != capture_card) { | ||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | ||||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | if (!JackServerGlobals::on_device_acquire(audio_name)) { | ||||
| jack_error("Audio device %s cannot be acquired...", playback_driver_name); | |||||
| jack_error("Audio device %s cannot be acquired...",info.devices_playback_size > 0 ? info.devices[0].playback_name : "-" ); | |||||
| if (capture_card >= 0) { | if (capture_card >= 0) { | ||||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | ||||
| JackServerGlobals::on_device_release(audio_name); | JackServerGlobals::on_device_release(audio_name); | ||||
| @@ -333,40 +344,56 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| fDriver = alsa_driver_new ((char*)"alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name, | |||||
| NULL, | |||||
| nframes, | |||||
| user_nperiods, | |||||
| samplerate, | |||||
| hw_monitoring, | |||||
| hw_metering, | |||||
| capturing, | |||||
| playing, | |||||
| dither, | |||||
| soft_mode, | |||||
| monitor, | |||||
| inchannels, | |||||
| outchannels, | |||||
| shorts_first, | |||||
| capture_latency, | |||||
| playback_latency, | |||||
| midi); | |||||
| if (fDriver) { | |||||
| // ALSA driver may have changed the in/out values | |||||
| fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; | |||||
| fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; | |||||
| if (JackServerGlobals::on_device_reservation_loop != NULL) { | |||||
| device_reservation_loop_running = true; | |||||
| if (JackPosixThread::StartImp(&fReservationLoopThread, 0, 0, on_device_reservation_loop, NULL) != 0) { | |||||
| device_reservation_loop_running = false; | |||||
| fDriver = alsa_driver_new ((char*)"alsa_pcm", info, NULL); | |||||
| if (!fDriver) { | |||||
| Close(); | |||||
| return -1; | |||||
| } | |||||
| /* we need to initialize variables for all devices, mainly channels count since this is required by Jack to setup ports */ | |||||
| UpdateDriverTargetState(DriverMode::Init); | |||||
| if (alsa_driver_open((alsa_driver_t *)fDriver) < 0) { | |||||
| Close(); | |||||
| return -1; | |||||
| } | |||||
| /* we are starting with all alsa devices closed, therfore populate jack channels based on user hint */ | |||||
| if (info.features & ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT && info.features & ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE) { | |||||
| for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) { | |||||
| if (i < info.devices_capture_size && info.devices[i].capture_channels < 1) { | |||||
| jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device C: '%s'", info.devices[i].capture_name); | |||||
| Close(); | |||||
| return -1; | |||||
| } | } | ||||
| if (i < info.devices_playback_size && info.devices[i].playback_channels < 1) { | |||||
| jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device P: '%s'", info.devices[i].playback_name); | |||||
| Close(); | |||||
| return -1; | |||||
| } | |||||
| fCaptureChannels += info.devices[i].capture_channels; | |||||
| fPlaybackChannels += info.devices[i].playback_channels; | |||||
| } | } | ||||
| return 0; | |||||
| /* in case we really opened alsa devices, channel information is generated by driver */ | |||||
| } else { | } else { | ||||
| Close(); | |||||
| return -1; | |||||
| fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; | |||||
| fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; | |||||
| } | } | ||||
| #ifndef __QNXNTO__ | |||||
| if (JackServerGlobals::on_device_reservation_loop != NULL) { | |||||
| device_reservation_loop_running = true; | |||||
| if (JackPosixThread::StartImp(&fReservationLoopThread, 0, 0, on_device_reservation_loop, NULL) != 0) { | |||||
| device_reservation_loop_running = false; | |||||
| } | |||||
| } | |||||
| #endif | |||||
| return 0; | |||||
| } | } | ||||
| int JackAlsaDriver::Close() | int JackAlsaDriver::Close() | ||||
| @@ -374,15 +401,20 @@ int JackAlsaDriver::Close() | |||||
| // Generic audio driver close | // Generic audio driver close | ||||
| int res = JackAudioDriver::Close(); | int res = JackAudioDriver::Close(); | ||||
| UpdateDriverTargetState(DriverMode::Shutdown); | |||||
| alsa_driver_close((alsa_driver_t *)fDriver); | |||||
| if (fDriver) { | if (fDriver) { | ||||
| alsa_driver_delete((alsa_driver_t*)fDriver); | alsa_driver_delete((alsa_driver_t*)fDriver); | ||||
| } | } | ||||
| #ifndef __QNXNTO__ | |||||
| if (device_reservation_loop_running) { | if (device_reservation_loop_running) { | ||||
| device_reservation_loop_running = false; | device_reservation_loop_running = false; | ||||
| JackPosixThread::StopImp(fReservationLoopThread); | JackPosixThread::StopImp(fReservationLoopThread); | ||||
| } | } | ||||
| // FIXME: needs adaptation for multiple drivers | |||||
| if (JackServerGlobals::on_device_release != NULL) | if (JackServerGlobals::on_device_release != NULL) | ||||
| { | { | ||||
| char audio_name[32]; | char audio_name[32]; | ||||
| @@ -398,6 +430,7 @@ int JackAlsaDriver::Close() | |||||
| JackServerGlobals::on_device_release(audio_name); | JackServerGlobals::on_device_release(audio_name); | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| return res; | return res; | ||||
| } | } | ||||
| @@ -423,28 +456,39 @@ int JackAlsaDriver::Stop() | |||||
| return res; | return res; | ||||
| } | } | ||||
| int JackAlsaDriver::Reload() | |||||
| { | |||||
| UpdateDriverTargetState(DriverMode::Runtime); | |||||
| alsa_driver_t* driver = (alsa_driver_t*) fDriver; | |||||
| if (alsa_driver_close (driver) < 0) { | |||||
| jack_error("JackAlsaDriver::Reload close failed"); | |||||
| return -1; | |||||
| } | |||||
| if (alsa_driver_open (driver) < 0) { | |||||
| jack_error("JackAlsaDriver::Reload open failed"); | |||||
| return -1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int JackAlsaDriver::Read() | int JackAlsaDriver::Read() | ||||
| { | { | ||||
| /* Taken from alsa_driver_run_cycle */ | /* Taken from alsa_driver_run_cycle */ | ||||
| int wait_status; | |||||
| jack_nframes_t nframes; | |||||
| alsa_driver_wait_status_t wait_status; | |||||
| jack_nframes_t nframes = 0; | |||||
| fDelayedUsecs = 0.f; | fDelayedUsecs = 0.f; | ||||
| retry: | |||||
| nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | |||||
| if (wait_status < 0) | |||||
| return -1; /* driver failed */ | |||||
| /* wait until all devices have some data available */ | |||||
| do { | |||||
| nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | |||||
| if (nframes == 0) { | |||||
| /* we detected an xrun and restarted: notify | |||||
| * clients about the delay. | |||||
| */ | |||||
| jack_log("ALSA XRun wait_status = %d", wait_status); | |||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||||
| goto retry; /* recoverable error*/ | |||||
| } | |||||
| if (wait_status != ALSA_DRIVER_WAIT_OK) { | |||||
| jack_error("JackAlsaDriver::Read wait failed, xrun recovery"); | |||||
| goto retry; | |||||
| } | |||||
| } while (nframes == 0); | |||||
| if (nframes != fEngineControl->fBufferSize) | if (nframes != fEngineControl->fBufferSize) | ||||
| jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes); | jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes); | ||||
| @@ -452,20 +496,45 @@ retry: | |||||
| // Has to be done before read | // Has to be done before read | ||||
| JackDriver::CycleIncTime(); | JackDriver::CycleIncTime(); | ||||
| return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); | |||||
| if (alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize) != 0) { | |||||
| jack_error("JackAlsaDriver::Read read failed, xrun recovery"); | |||||
| goto retry; | |||||
| } | |||||
| return 0; | |||||
| retry: | |||||
| /* we detected an xrun and restarted: notify | |||||
| * clients about the delay. | |||||
| */ | |||||
| jack_error("JackAlsaDriver::Read failed, xrun recovery"); | |||||
| alsa_driver_xrun_recovery((alsa_driver_t *)fDriver, &fDelayedUsecs); | |||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||||
| return -1; | |||||
| } | } | ||||
| int JackAlsaDriver::Write() | int JackAlsaDriver::Write() | ||||
| { | { | ||||
| return alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); | |||||
| if (alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize) != 0) { | |||||
| jack_error("JackAlsaDriver::Write failed, xrun recovery"); | |||||
| alsa_driver_xrun_recovery((alsa_driver_t *)fDriver, &fDelayedUsecs); | |||||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||||
| return -1; | |||||
| } | |||||
| return 0; | |||||
| } | } | ||||
| void JackAlsaDriver::ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) | |||||
| void JackAlsaDriver::ReadInputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) | |||||
| { | { | ||||
| 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); | |||||
| /* global channel offset to fCapturePortList of this capture alsa device */ | |||||
| channel_t port_n = device->capture_channel_offset; | |||||
| for (channel_t chn = 0; chn < device->capture_nchannels; ++chn, ++port_n) { | |||||
| if (fGraphManager->GetConnectionsNum(fCapturePortList[port_n]) > 0) { | |||||
| jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_n], orig_nframes); | |||||
| alsa_driver_read_from_channel((alsa_driver_t *)fDriver, device, chn, buf + nread, contiguous); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -499,16 +568,69 @@ int JackAlsaDriver::PortSetDefaultMetadata(jack_port_id_t port_id, const char* p | |||||
| return fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, port_id, pretty_name); | return fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, port_id, pretty_name); | ||||
| } | } | ||||
| void JackAlsaDriver::WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) | |||||
| int JackAlsaDriver::UpdateDriverTargetState(DriverMode mode) | |||||
| { | { | ||||
| for (int chn = 0; chn < fPlaybackChannels; chn++) { | |||||
| int c_list_index = 0, p_list_index = 0; | |||||
| alsa_driver_t* driver = (alsa_driver_t*) fDriver; | |||||
| for (int i = 0; i < driver->devices_count; ++i) { | |||||
| alsa_device_t *device = &driver->devices[i]; | |||||
| int capture_connections_count = 0; | |||||
| for (int j = 0; j < device->capture_nchannels; ++j) { | |||||
| capture_connections_count += fGraphManager->GetConnectionsNum(fCapturePortList[c_list_index]); | |||||
| c_list_index++; | |||||
| } | |||||
| device->capture_target_state = TargetState(mode, capture_connections_count); | |||||
| int playback_connections_count = 0; | |||||
| for (int j = 0; j < device->playback_nchannels; ++j) { | |||||
| playback_connections_count += fGraphManager->GetConnectionsNum(fPlaybackPortList[p_list_index]); | |||||
| p_list_index++; | |||||
| } | |||||
| device->playback_target_state = TargetState(mode, playback_connections_count); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int JackAlsaDriver::TargetState(DriverMode mode, int connections_count) | |||||
| { | |||||
| alsa_driver_t* driver = (alsa_driver_t*) fDriver; | |||||
| if (mode == DriverMode::Shutdown) { | |||||
| return SND_PCM_STATE_NOTREADY; | |||||
| } | |||||
| if (connections_count > 0) { | |||||
| return SND_PCM_STATE_RUNNING; | |||||
| } | |||||
| // evaluation during init is disabled by user option | |||||
| if (mode == DriverMode::Init && !(driver->features & ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT)) { | |||||
| return SND_PCM_STATE_RUNNING; | |||||
| } | |||||
| if (driver->features & ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE) { | |||||
| return SND_PCM_STATE_NOTREADY; | |||||
| } | |||||
| return SND_PCM_STATE_PREPARED; | |||||
| } | |||||
| void JackAlsaDriver::WriteOutputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) | |||||
| { | |||||
| /* global channel offset to fPlaybackPortList of this playback alsa device */ | |||||
| channel_t port_n = device->playback_channel_offset; | |||||
| for (channel_t chn = 0; chn < device->playback_nchannels; ++chn, ++port_n) { | |||||
| // Output ports | // 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); | |||||
| if (fGraphManager->GetConnectionsNum(fPlaybackPortList[port_n]) > 0) { | |||||
| jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_n], orig_nframes); | |||||
| alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), device, chn, buf + nwritten, contiguous); | |||||
| // Monitor ports | // 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); | |||||
| if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[port_n]) > 0) { | |||||
| jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_n], orig_nframes); | |||||
| memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | ||||
| } | } | ||||
| } | } | ||||
| @@ -578,6 +700,7 @@ extern "C" | |||||
| { | { | ||||
| #endif | #endif | ||||
| #ifndef __QNXNTO__ | |||||
| static | static | ||||
| jack_driver_param_constraint_desc_t * | jack_driver_param_constraint_desc_t * | ||||
| enum_alsa_devices() | enum_alsa_devices() | ||||
| @@ -667,6 +790,7 @@ fail: | |||||
| jack_constraint_free(constraint_ptr); | jack_constraint_free(constraint_ptr); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| #endif | |||||
| static int | static int | ||||
| dither_opt (char c, DitherAlgorithm* dither) | dither_opt (char c, DitherAlgorithm* dither) | ||||
| @@ -705,11 +829,14 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||||
| desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "Linux ALSA API based audio backend", &filler); | desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "Linux ALSA API based audio backend", &filler); | ||||
| strcpy(value.str, "hw:0"); | strcpy(value.str, "hw:0"); | ||||
| #ifndef __QNXNTO__ | |||||
| #ifdef __ANDROID__ | #ifdef __ANDROID__ | ||||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "ALSA device name", NULL); | jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "ALSA device name", NULL); | ||||
| #else | #else | ||||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices(), "ALSA device name", NULL); | jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices(), "ALSA device name", NULL); | ||||
| #endif | #endif | ||||
| #endif | |||||
| strcpy(value.str, "none"); | strcpy(value.str, "none"); | ||||
| jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL); | jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL); | ||||
| @@ -753,9 +880,9 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||||
| "Dithering mode", | "Dithering mode", | ||||
| NULL); | NULL); | ||||
| value.ui = 0; | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of capture channels (defaults to hardware max)", NULL); | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of playback channels (defaults to hardware max)", NULL); | |||||
| strcpy(value.str, "none"); | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamString, &value, NULL, "List of device capture channels (defaults to hw max)", NULL); | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamString, &value, NULL, "List of device playback channels (defaults to hw max)", NULL); | |||||
| value.i = FALSE; | value.i = FALSE; | ||||
| jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL); | jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL); | ||||
| @@ -778,33 +905,94 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||||
| "ALSA MIDI driver", | "ALSA MIDI driver", | ||||
| NULL); | NULL); | ||||
| value.i = 0; | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "eval-on-init", 'x', JackDriverParamBool, &value, NULL, "Do not start ALSA devices on jack startup", NULL); | |||||
| value.i = 0; | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "close-idle", 'c', JackDriverParamBool, &value, NULL, "Close idle devices on alsa driver restart request", NULL); | |||||
| value.i = 0; | |||||
| jack_driver_descriptor_add_parameter(desc, &filler, "unlinked-devs", 'u', JackDriverParamBool, &value, NULL, "Do not link devices", NULL); | |||||
| return desc; | return desc; | ||||
| } | } | ||||
| struct array_string_t | |||||
| { | |||||
| enum flags { | |||||
| none, | |||||
| discard_duplicate, | |||||
| }; | |||||
| std::vector<char*> data; | |||||
| }; | |||||
| void array_string_free(struct array_string_t *obj) | |||||
| { | |||||
| if (obj == NULL) { | |||||
| return; | |||||
| } | |||||
| for (size_t i = 0; i < obj->data.size(); ++i) { | |||||
| free(obj->data[i]); | |||||
| } | |||||
| } | |||||
| struct array_string_t array_string_split(const char *str, const char sep, array_string_t::flags flags = array_string_t::none) | |||||
| { | |||||
| struct array_string_t result; | |||||
| std::stringstream stream; | |||||
| stream << std::string(str); | |||||
| if (stream.str().find(sep) == std::string::npos) { | |||||
| result.data.push_back((char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char))); | |||||
| strncpy(result.data[0], str, JACK_CLIENT_NAME_SIZE); | |||||
| result.data[0][JACK_CLIENT_NAME_SIZE] = '\0'; | |||||
| return result; | |||||
| } | |||||
| std::string driver; | |||||
| while (std::getline(stream, driver, sep)) { | |||||
| driver.erase(std::remove_if(driver.begin(), driver.end(), isspace), driver.end()); | |||||
| if (std::find(result.data.begin(), result.data.end(), driver) != result.data.end() && (flags & array_string_t::discard_duplicate)) | |||||
| continue; | |||||
| char *str = (char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char)); | |||||
| strncpy(str, driver.c_str(), JACK_CLIENT_NAME_SIZE); | |||||
| str[JACK_CLIENT_NAME_SIZE] = '\0'; | |||||
| result.data.push_back(str); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| static Jack::JackAlsaDriver* g_alsa_driver; | static Jack::JackAlsaDriver* g_alsa_driver; | ||||
| 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) | ||||
| { | { | ||||
| jack_nframes_t srate = 48000; | |||||
| jack_nframes_t frames_per_interrupt = 1024; | |||||
| unsigned long user_nperiods = 2; | |||||
| const char *playback_pcm_name = "hw:0"; | |||||
| const char *capture_pcm_name = "hw:0"; | |||||
| int hw_monitoring = FALSE; | |||||
| int hw_metering = FALSE; | |||||
| int capture = FALSE; | |||||
| int playback = FALSE; | |||||
| int soft_mode = FALSE; | |||||
| int monitor = FALSE; | |||||
| DitherAlgorithm dither = None; | |||||
| int user_capture_nchnls = 0; | |||||
| int user_playback_nchnls = 0; | |||||
| int shorts_first = FALSE; | |||||
| jack_nframes_t systemic_input_latency = 0; | |||||
| jack_nframes_t systemic_output_latency = 0; | |||||
| const JSList * node; | const JSList * node; | ||||
| const jack_driver_param_t * param; | const jack_driver_param_t * param; | ||||
| const char *midi_driver = "none"; | |||||
| alsa_driver_info_t info = {}; | |||||
| info.devices = NULL; | |||||
| info.midi_name = strdup("none"); | |||||
| info.hw_monitoring = FALSE; | |||||
| info.hw_metering = FALSE; | |||||
| info.monitor = FALSE; | |||||
| info.soft_mode = FALSE; | |||||
| info.frame_rate = 48000; | |||||
| info.frames_per_period = 1024; | |||||
| info.periods_n = 2; | |||||
| info.dither = None; | |||||
| info.shorts_first = FALSE; | |||||
| info.capture_latency = 0; | |||||
| info.playback_latency = 0; | |||||
| char *capture_names_param = NULL; | |||||
| char *playback_names_param = NULL; | |||||
| char *capture_channels_param = NULL; | |||||
| char *playback_channels_param = NULL; | |||||
| int duplex = FALSE; | |||||
| for (node = params; node; node = jack_slist_next (node)) { | for (node = params; node; node = jack_slist_next (node)) { | ||||
| param = (const jack_driver_param_t *) node->data; | param = (const jack_driver_param_t *) node->data; | ||||
| @@ -812,112 +1000,175 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke | |||||
| switch (param->character) { | switch (param->character) { | ||||
| case 'C': | case 'C': | ||||
| capture = TRUE; | |||||
| if (strcmp (param->value.str, "none") != 0) { | if (strcmp (param->value.str, "none") != 0) { | ||||
| capture_pcm_name = strdup (param->value.str); | |||||
| jack_log("capture device %s", capture_pcm_name); | |||||
| capture_names_param = strdup (param->value.str); | |||||
| jack_log("capture device %s", capture_names_param); | |||||
| } | } | ||||
| break; | break; | ||||
| case 'P': | case 'P': | ||||
| playback = TRUE; | |||||
| if (strcmp (param->value.str, "none") != 0) { | if (strcmp (param->value.str, "none") != 0) { | ||||
| playback_pcm_name = strdup (param->value.str); | |||||
| jack_log("playback device %s", playback_pcm_name); | |||||
| playback_names_param = strdup (param->value.str); | |||||
| jack_log("playback device %s", playback_names_param); | |||||
| } | } | ||||
| break; | break; | ||||
| case 'D': | case 'D': | ||||
| playback = TRUE; | |||||
| capture = TRUE; | |||||
| duplex = TRUE; | |||||
| break; | break; | ||||
| case 'd': | case 'd': | ||||
| if (strcmp (param->value.str, "none") != 0) { | if (strcmp (param->value.str, "none") != 0) { | ||||
| playback_pcm_name = strdup (param->value.str); | |||||
| capture_pcm_name = strdup (param->value.str); | |||||
| jack_log("playback device %s", playback_pcm_name); | |||||
| jack_log("capture device %s", capture_pcm_name); | |||||
| playback_names_param = strdup (param->value.str); | |||||
| capture_names_param = strdup (param->value.str); | |||||
| jack_log("playback device %s", playback_names_param); | |||||
| jack_log("capture device %s", capture_names_param); | |||||
| } | } | ||||
| break; | break; | ||||
| case 'H': | case 'H': | ||||
| hw_monitoring = param->value.i; | |||||
| info.hw_monitoring = param->value.i; | |||||
| break; | break; | ||||
| case 'm': | case 'm': | ||||
| monitor = param->value.i; | |||||
| info.monitor = param->value.i; | |||||
| break; | break; | ||||
| case 'M': | case 'M': | ||||
| hw_metering = param->value.i; | |||||
| info.hw_metering = param->value.i; | |||||
| break; | break; | ||||
| case 'r': | case 'r': | ||||
| srate = param->value.ui; | |||||
| jack_log("apparent rate = %d", srate); | |||||
| info.frame_rate = param->value.ui; | |||||
| jack_log("apparent rate = %d", info.frame_rate); | |||||
| break; | break; | ||||
| case 'p': | case 'p': | ||||
| frames_per_interrupt = param->value.ui; | |||||
| jack_log("frames per period = %d", frames_per_interrupt); | |||||
| info.frames_per_period = param->value.ui; | |||||
| jack_log("frames per period = %d", info.frames_per_period); | |||||
| break; | break; | ||||
| case 'n': | case 'n': | ||||
| user_nperiods = param->value.ui; | |||||
| if (user_nperiods < 2) { /* enforce minimum value */ | |||||
| user_nperiods = 2; | |||||
| info.periods_n = param->value.ui; | |||||
| if (info.periods_n < 2) { /* enforce minimum value */ | |||||
| info.periods_n = 2; | |||||
| } | } | ||||
| break; | break; | ||||
| case 's': | case 's': | ||||
| soft_mode = param->value.i; | |||||
| info.soft_mode = param->value.i; | |||||
| break; | break; | ||||
| case 'z': | case 'z': | ||||
| if (dither_opt (param->value.c, &dither)) { | |||||
| if (dither_opt (param->value.c, &info.dither)) { | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| break; | break; | ||||
| case 'i': | case 'i': | ||||
| user_capture_nchnls = param->value.ui; | |||||
| capture_channels_param = strdup(param->value.str); | |||||
| break; | break; | ||||
| case 'o': | case 'o': | ||||
| user_playback_nchnls = param->value.ui; | |||||
| playback_channels_param = strdup(param->value.str); | |||||
| break; | break; | ||||
| case 'S': | case 'S': | ||||
| shorts_first = param->value.i; | |||||
| info.shorts_first = param->value.i; | |||||
| break; | break; | ||||
| case 'I': | case 'I': | ||||
| systemic_input_latency = param->value.ui; | |||||
| info.capture_latency = param->value.ui; | |||||
| break; | break; | ||||
| case 'O': | case 'O': | ||||
| systemic_output_latency = param->value.ui; | |||||
| info.playback_latency = param->value.ui; | |||||
| break; | break; | ||||
| case 'X': | case 'X': | ||||
| midi_driver = strdup(param->value.str); | |||||
| free(info.midi_name); | |||||
| info.midi_name = strdup(param->value.str); | |||||
| break; | |||||
| case 'x': | |||||
| info.features |= param->value.i ? ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT : 0; | |||||
| break; | |||||
| case 'c': | |||||
| info.features |= param->value.i ? ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE : 0; | |||||
| break; | |||||
| case 'u': | |||||
| info.features |= param->value.i ? ALSA_DRIVER_FEAT_UNLINKED_DEVS : 0; | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* duplex is the default */ | /* duplex is the default */ | ||||
| if (!capture && !playback) { | |||||
| capture = TRUE; | |||||
| playback = TRUE; | |||||
| if (!capture_names_param && !playback_names_param) { | |||||
| duplex = TRUE; | |||||
| } | |||||
| if (duplex) { | |||||
| if (!capture_names_param) { | |||||
| capture_names_param = strdup("hw:0"); | |||||
| } | |||||
| if (!playback_names_param) { | |||||
| playback_names_param = strdup("hw:0"); | |||||
| } | |||||
| } | |||||
| struct array_string_t capture_names = {}; | |||||
| if (capture_names_param) { | |||||
| capture_names = array_string_split(capture_names_param, ' ', array_string_t::discard_duplicate); | |||||
| free(capture_names_param); | |||||
| } | } | ||||
| struct array_string_t playback_names = {}; | |||||
| if (playback_names_param) { | |||||
| playback_names = array_string_split(playback_names_param, ' ', array_string_t::discard_duplicate); | |||||
| free(playback_names_param); | |||||
| } | |||||
| struct array_string_t capture_channels = {}; | |||||
| if (capture_channels_param) { | |||||
| capture_channels = array_string_split(capture_channels_param, ' '); | |||||
| free(capture_channels_param); | |||||
| } | |||||
| struct array_string_t playback_channels = {}; | |||||
| if (playback_channels_param) { | |||||
| playback_channels = array_string_split(playback_channels_param, ' '); | |||||
| free(playback_channels_param); | |||||
| } | |||||
| info.devices_capture_size = capture_names.data.size(); | |||||
| info.devices_playback_size = playback_names.data.size(); | |||||
| info.devices = (alsa_device_info_t*) calloc(std::max(info.devices_capture_size, info.devices_playback_size), sizeof(alsa_device_info_t)); | |||||
| for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) { | |||||
| if (i < capture_names.data.size()) { | |||||
| info.devices[i].capture_name = strdup(capture_names.data[i]); | |||||
| } | |||||
| if (i < capture_channels.data.size()) { | |||||
| info.devices[i].capture_channels = atoi(capture_channels.data[i]); | |||||
| } | |||||
| if (i < playback_names.data.size()) { | |||||
| info.devices[i].playback_name = strdup(playback_names.data[i]); | |||||
| } | |||||
| if (i < playback_channels.data.size()) { | |||||
| info.devices[i].playback_channels = atoi(playback_channels.data[i]); | |||||
| } | |||||
| } | |||||
| array_string_free(&capture_names); | |||||
| array_string_free(&playback_names); | |||||
| array_string_free(&capture_channels); | |||||
| array_string_free(&playback_channels); | |||||
| g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table); | g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table); | ||||
| Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver); | Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver); | ||||
| // Special open for ALSA driver... | // Special open for ALSA driver... | ||||
| 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) { | |||||
| if (g_alsa_driver->Open(info) == 0) { | |||||
| return threaded_driver; | return threaded_driver; | ||||
| } else { | } else { | ||||
| delete threaded_driver; // Delete the decorated driver | delete threaded_driver; // Delete the decorated driver | ||||
| @@ -927,9 +1178,9 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke | |||||
| // Code to be used in alsa_driver.c | // 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) | |||||
| void ReadInput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) | |||||
| { | { | ||||
| g_alsa_driver->ReadInputAux(orig_nframes, contiguous, nread); | |||||
| g_alsa_driver->ReadInputAux(device, orig_nframes, contiguous, nread); | |||||
| } | } | ||||
| void MonitorInput() | void MonitorInput() | ||||
| { | { | ||||
| @@ -939,9 +1190,9 @@ void ClearOutput() | |||||
| { | { | ||||
| g_alsa_driver->ClearOutputAux(); | g_alsa_driver->ClearOutputAux(); | ||||
| } | } | ||||
| void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) | |||||
| void WriteOutput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) | |||||
| { | { | ||||
| g_alsa_driver->WriteOutputAux(orig_nframes, contiguous, nwritten); | |||||
| g_alsa_driver->WriteOutputAux(device, orig_nframes, contiguous, nwritten); | |||||
| } | } | ||||
| void SetTime(jack_time_t time) | void SetTime(jack_time_t time) | ||||
| { | { | ||||
| @@ -951,8 +1202,13 @@ void SetTime(jack_time_t time) | |||||
| int Restart() | int Restart() | ||||
| { | { | ||||
| int res; | int res; | ||||
| if ((res = g_alsa_driver->Stop()) == 0) { | |||||
| res = g_alsa_driver->Start(); | |||||
| if ((res = g_alsa_driver->Stop()) != 0) { | |||||
| jack_error("restart: stop driver failed"); | |||||
| return res; | |||||
| } | |||||
| if ((res = g_alsa_driver->Start()) != 0) { | |||||
| jack_error("restart: start driver failed"); | |||||
| return res; | |||||
| } | } | ||||
| return res; | return res; | ||||
| } | } | ||||
| @@ -38,6 +38,12 @@ class JackAlsaDriver : public JackAudioDriver | |||||
| private: | private: | ||||
| enum DriverMode { | |||||
| Init, | |||||
| Runtime, | |||||
| Shutdown, | |||||
| }; | |||||
| jack_driver_t* fDriver; | jack_driver_t* fDriver; | ||||
| jack_native_thread_t fReservationLoopThread; | jack_native_thread_t fReservationLoopThread; | ||||
| @@ -51,24 +57,7 @@ class JackAlsaDriver : public JackAudioDriver | |||||
| virtual ~JackAlsaDriver() | virtual ~JackAlsaDriver() | ||||
| {} | {} | ||||
| int Open(jack_nframes_t buffer_size, | |||||
| jack_nframes_t user_nperiods, | |||||
| jack_nframes_t samplerate, | |||||
| bool hw_monitoring, | |||||
| bool hw_metering, | |||||
| bool capturing, | |||||
| bool playing, | |||||
| DitherAlgorithm dither, | |||||
| bool soft_mode, | |||||
| bool monitor, | |||||
| int inchannels, | |||||
| int outchannels, | |||||
| bool shorts_first, | |||||
| const char* capture_driver_name, | |||||
| const char* playback_driver_name, | |||||
| jack_nframes_t capture_latency, | |||||
| jack_nframes_t playback_latency, | |||||
| const char* midi_driver_name); | |||||
| int Open(alsa_driver_info_t info); | |||||
| int Close(); | int Close(); | ||||
| int Attach(); | int Attach(); | ||||
| @@ -76,6 +65,7 @@ class JackAlsaDriver : public JackAudioDriver | |||||
| int Start(); | int Start(); | ||||
| int Stop(); | int Stop(); | ||||
| int Reload(); | |||||
| int Read(); | int Read(); | ||||
| int Write(); | int Write(); | ||||
| @@ -88,14 +78,18 @@ class JackAlsaDriver : public JackAudioDriver | |||||
| int SetBufferSize(jack_nframes_t buffer_size); | int SetBufferSize(jack_nframes_t buffer_size); | ||||
| void ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); | |||||
| void ReadInputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); | |||||
| void MonitorInputAux(); | void MonitorInputAux(); | ||||
| void ClearOutputAux(); | void ClearOutputAux(); | ||||
| void WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); | |||||
| void WriteOutputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); | |||||
| void SetTimetAux(jack_time_t time); | void SetTimetAux(jack_time_t time); | ||||
| int PortSetDefaultMetadata(jack_port_id_t port_id, const char* pretty_name); | int PortSetDefaultMetadata(jack_port_id_t port_id, const char* pretty_name); | ||||
| int UpdateDriverTargetState(DriverMode mode); | |||||
| int TargetState(DriverMode mode, int connections_count); | |||||
| // JACK API emulation for the midi driver | // JACK API emulation for the midi driver | ||||
| int is_realtime() const; | int is_realtime() const; | ||||
| int create_thread(pthread_t *thread, int prio, int rt, void *(*start_func)(void*), void *arg); | int create_thread(pthread_t *thread, int prio, int rt, void *(*start_func)(void*), void *arg); | ||||
| @@ -21,7 +21,12 @@ | |||||
| #ifndef __jack_alsa_driver_h__ | #ifndef __jack_alsa_driver_h__ | ||||
| #define __jack_alsa_driver_h__ | #define __jack_alsa_driver_h__ | ||||
| #ifdef __QNXNTO__ | |||||
| #include <sys/asoundlib.h> | |||||
| #else | |||||
| #include <alsa/asoundlib.h> | #include <alsa/asoundlib.h> | ||||
| #endif | |||||
| #include "bitset.h" | #include "bitset.h" | ||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||
| @@ -41,6 +46,34 @@ | |||||
| #include "memops.h" | #include "memops.h" | ||||
| #include "alsa_midi.h" | #include "alsa_midi.h" | ||||
| #ifdef __QNXNTO__ | |||||
| #define SND_PCM_FORMAT_S16_LE SND_PCM_SFMT_S16_LE | |||||
| #define SND_PCM_FORMAT_S16_BE SND_PCM_SFMT_S16_BE | |||||
| #define SND_PCM_FORMAT_S24_LE SND_PCM_SFMT_S24_LE | |||||
| #define SND_PCM_FORMAT_S24_BE SND_PCM_SFMT_S24_BE | |||||
| #define SND_PCM_FORMAT_S32_LE SND_PCM_SFMT_S32_LE | |||||
| #define SND_PCM_FORMAT_S32_BE SND_PCM_SFMT_S32_BE | |||||
| #define SND_PCM_FORMAT_FLOAT_LE SND_PCM_SFMT_FLOAT_LE | |||||
| #define SND_PCM_FORMAT_UNKNOWN SND_PCM_SFMT_SPECIAL | |||||
| #define SND_PCM_STATE_PREPARED SND_PCM_STATUS_PREPARED | |||||
| #define SND_PCM_STATE_SUSPENDED SND_PCM_STATUS_SUSPENDED | |||||
| #define SND_PCM_STATE_XRUN SND_PCM_STATUS_UNDERRUN | |||||
| #define SND_PCM_STATE_RUNNING SND_PCM_STATUS_RUNNING | |||||
| #define SND_PCM_STATE_NOTREADY SND_PCM_STATUS_NOTREADY | |||||
| #define SND_PCM_STREAM_PLAYBACK SND_PCM_CHANNEL_PLAYBACK | |||||
| #define SND_PCM_STREAM_CAPTURE SND_PCM_CHANNEL_CAPTURE | |||||
| typedef unsigned long snd_pcm_uframes_t; | |||||
| typedef signed long snd_pcm_sframes_t; | |||||
| typedef int32_t alsa_driver_default_format_t; | |||||
| #else | |||||
| #define SND_PCM_STATE_NOTREADY (SND_PCM_STATE_LAST + 1) | |||||
| #endif | |||||
| #define ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT (1 << 0) | |||||
| #define ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE (1 << 1) | |||||
| #define ALSA_DRIVER_FEAT_UNLINKED_DEVS (1 << 2) | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" | extern "C" | ||||
| { | { | ||||
| @@ -54,61 +87,105 @@ typedef void (*WriteCopyFunction) (char *dst, jack_default_audio_sample_t *src, | |||||
| unsigned long dst_skip_bytes, | unsigned long dst_skip_bytes, | ||||
| dither_state_t *state); | dither_state_t *state); | ||||
| typedef struct _alsa_device { | |||||
| #ifdef __QNXNTO__ | |||||
| unsigned int playback_sample_format; | |||||
| unsigned int capture_sample_format; | |||||
| void *capture_areas; | |||||
| void *playback_areas; | |||||
| void *capture_areas_ptr; | |||||
| void *playback_areas_ptr; | |||||
| #else | |||||
| snd_pcm_format_t playback_sample_format; | |||||
| snd_pcm_format_t capture_sample_format; | |||||
| const snd_pcm_channel_area_t *capture_areas; | |||||
| const snd_pcm_channel_area_t *playback_areas; | |||||
| #endif | |||||
| snd_pcm_t *playback_handle; | |||||
| snd_pcm_t *capture_handle; | |||||
| char *playback_name; | |||||
| char *capture_name; | |||||
| char **playback_addr; | |||||
| char **capture_addr; | |||||
| channel_t playback_channel_offset; | |||||
| channel_t capture_channel_offset; | |||||
| channel_t playback_nchannels; | |||||
| channel_t capture_nchannels; | |||||
| channel_t max_nchannels; | |||||
| channel_t user_nchannels; | |||||
| bitset_t channels_not_done; | |||||
| bitset_t channels_done; | |||||
| char quirk_bswap; | |||||
| ReadCopyFunction read_via_copy; | |||||
| WriteCopyFunction write_via_copy; | |||||
| unsigned long interleave_unit; | |||||
| unsigned long *capture_interleave_skip; | |||||
| unsigned long *playback_interleave_skip; | |||||
| char playback_interleaved; | |||||
| char capture_interleaved; | |||||
| unsigned long *silent; | |||||
| unsigned long playback_sample_bytes; | |||||
| unsigned long capture_sample_bytes; | |||||
| /* device is 'snd_pcm_link' to a group, only 1 group of linked devices is allowed */ | |||||
| int capture_linked; | |||||
| int playback_linked; | |||||
| int capture_xrun_count; | |||||
| int playback_xrun_count; | |||||
| /* desired state of device, decided by JackAlsaDriver */ | |||||
| int capture_target_state; | |||||
| int playback_target_state; | |||||
| jack_hardware_t *hw; | |||||
| snd_ctl_t *ctl_handle; | |||||
| char *alsa_driver; | |||||
| JSList *clock_sync_listeners; | |||||
| pthread_mutex_t clock_sync_lock; | |||||
| unsigned long next_clock_sync_listener_id; | |||||
| } alsa_device_t; | |||||
| typedef struct _alsa_driver { | typedef struct _alsa_driver { | ||||
| JACK_DRIVER_NT_DECL | JACK_DRIVER_NT_DECL | ||||
| #ifndef __QNXNTO__ | |||||
| snd_pcm_hw_params_t *playback_hw_params; | |||||
| snd_pcm_sw_params_t *playback_sw_params; | |||||
| snd_pcm_hw_params_t *capture_hw_params; | |||||
| snd_pcm_sw_params_t *capture_sw_params; | |||||
| #endif | |||||
| int poll_timeout_ms; | int poll_timeout_ms; | ||||
| jack_time_t poll_last; | jack_time_t poll_last; | ||||
| jack_time_t poll_next; | jack_time_t poll_next; | ||||
| char **playback_addr; | |||||
| char **capture_addr; | |||||
| const snd_pcm_channel_area_t *capture_areas; | |||||
| const snd_pcm_channel_area_t *playback_areas; | |||||
| struct pollfd *pfd; | struct pollfd *pfd; | ||||
| unsigned int playback_nfds; | unsigned int playback_nfds; | ||||
| unsigned int capture_nfds; | unsigned int capture_nfds; | ||||
| unsigned long interleave_unit; | |||||
| unsigned long *capture_interleave_skip; | |||||
| unsigned long *playback_interleave_skip; | |||||
| channel_t max_nchannels; | |||||
| channel_t user_nchannels; | |||||
| channel_t playback_nchannels; | channel_t playback_nchannels; | ||||
| channel_t capture_nchannels; | channel_t capture_nchannels; | ||||
| unsigned long playback_sample_bytes; | |||||
| unsigned long capture_sample_bytes; | |||||
| jack_nframes_t frame_rate; | jack_nframes_t frame_rate; | ||||
| jack_nframes_t frames_per_cycle; | jack_nframes_t frames_per_cycle; | ||||
| jack_nframes_t capture_frame_latency; | jack_nframes_t capture_frame_latency; | ||||
| jack_nframes_t playback_frame_latency; | jack_nframes_t playback_frame_latency; | ||||
| unsigned long *silent; | |||||
| char *alsa_name_playback; | |||||
| char *alsa_name_capture; | |||||
| char *alsa_driver; | |||||
| bitset_t channels_not_done; | |||||
| bitset_t channels_done; | |||||
| snd_pcm_format_t playback_sample_format; | |||||
| snd_pcm_format_t capture_sample_format; | |||||
| float max_sample_val; | |||||
| unsigned long user_nperiods; | unsigned long user_nperiods; | ||||
| unsigned int playback_nperiods; | unsigned int playback_nperiods; | ||||
| unsigned int capture_nperiods; | unsigned int capture_nperiods; | ||||
| unsigned long last_mask; | |||||
| snd_ctl_t *ctl_handle; | |||||
| snd_pcm_t *playback_handle; | |||||
| snd_pcm_t *capture_handle; | |||||
| snd_pcm_hw_params_t *playback_hw_params; | |||||
| snd_pcm_sw_params_t *playback_sw_params; | |||||
| snd_pcm_hw_params_t *capture_hw_params; | |||||
| snd_pcm_sw_params_t *capture_sw_params; | |||||
| jack_hardware_t *hw; | |||||
| ClockSyncStatus *clock_sync_data; | |||||
| jack_client_t *client; | jack_client_t *client; | ||||
| JSList *capture_ports; | |||||
| JSList *playback_ports; | |||||
| JSList *monitor_ports; | |||||
| unsigned long input_monitor_mask; | unsigned long input_monitor_mask; | ||||
| @@ -116,28 +193,17 @@ typedef struct _alsa_driver { | |||||
| char hw_monitoring; | char hw_monitoring; | ||||
| char hw_metering; | char hw_metering; | ||||
| char all_monitor_in; | char all_monitor_in; | ||||
| char capture_and_playback_not_synced; | |||||
| char playback_interleaved; | |||||
| char capture_interleaved; | |||||
| char with_monitor_ports; | char with_monitor_ports; | ||||
| char has_clock_sync_reporting; | char has_clock_sync_reporting; | ||||
| char has_hw_monitoring; | char has_hw_monitoring; | ||||
| char has_hw_metering; | char has_hw_metering; | ||||
| char quirk_bswap; | |||||
| ReadCopyFunction read_via_copy; | |||||
| WriteCopyFunction write_via_copy; | |||||
| int preferred_sample_bytes; | |||||
| int dither; | int dither; | ||||
| dither_state_t *dither_state; | dither_state_t *dither_state; | ||||
| SampleClockMode clock_mode; | SampleClockMode clock_mode; | ||||
| JSList *clock_sync_listeners; | |||||
| pthread_mutex_t clock_sync_lock; | |||||
| unsigned long next_clock_sync_listener_id; | |||||
| int running; | |||||
| int run; | |||||
| int poll_late; | int poll_late; | ||||
| int xrun_count; | int xrun_count; | ||||
| @@ -146,83 +212,115 @@ typedef struct _alsa_driver { | |||||
| alsa_midi_t *midi; | alsa_midi_t *midi; | ||||
| int xrun_recovery; | int xrun_recovery; | ||||
| alsa_device_t *devices; | |||||
| int devices_count; | |||||
| int devices_c_count; | |||||
| int devices_p_count; | |||||
| int features; | |||||
| } alsa_driver_t; | } alsa_driver_t; | ||||
| typedef struct _alsa_device_info { | |||||
| char *capture_name; | |||||
| char *playback_name; | |||||
| int capture_channels; | |||||
| int playback_channels; | |||||
| } alsa_device_info_t; | |||||
| typedef struct _alsa_driver_info { | |||||
| alsa_device_info_t *devices; | |||||
| uint32_t devices_capture_size; | |||||
| uint32_t devices_playback_size; | |||||
| char *midi_name; | |||||
| alsa_midi_t *midi_driver; | |||||
| jack_nframes_t frame_rate; | |||||
| jack_nframes_t frames_per_period; | |||||
| int periods_n; | |||||
| DitherAlgorithm dither; | |||||
| int shorts_first; | |||||
| jack_nframes_t capture_latency; | |||||
| jack_nframes_t playback_latency; | |||||
| // these 4 should be reworked as struct.features | |||||
| int hw_monitoring; | |||||
| int hw_metering; | |||||
| int monitor; | |||||
| int soft_mode; | |||||
| int features; | |||||
| } alsa_driver_info_t; | |||||
| static inline void | 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, alsa_device_t *device, channel_t chn) { | |||||
| bitset_remove (device->channels_not_done, chn); | |||||
| device->silent[chn] = 0; | |||||
| } | } | ||||
| static inline void | static inline void | ||||
| alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, | |||||
| alsa_driver_silence_on_channel (alsa_driver_t *driver, alsa_device_t *device, channel_t chn, | |||||
| jack_nframes_t nframes) { | jack_nframes_t nframes) { | ||||
| if (driver->playback_interleaved) { | |||||
| if (device->playback_interleaved) { | |||||
| memset_interleave | memset_interleave | ||||
| (driver->playback_addr[chn], | |||||
| 0, nframes * driver->playback_sample_bytes, | |||||
| driver->interleave_unit, | |||||
| driver->playback_interleave_skip[chn]); | |||||
| (device->playback_addr[chn], | |||||
| 0, nframes * device->playback_sample_bytes, | |||||
| device->interleave_unit, | |||||
| device->playback_interleave_skip[chn]); | |||||
| } else { | } else { | ||||
| memset (driver->playback_addr[chn], 0, | |||||
| nframes * driver->playback_sample_bytes); | |||||
| memset (device->playback_addr[chn], 0, | |||||
| nframes * device->playback_sample_bytes); | |||||
| } | } | ||||
| alsa_driver_mark_channel_done (driver,chn); | |||||
| alsa_driver_mark_channel_done (driver, device, chn); | |||||
| } | } | ||||
| static inline void | static inline void | ||||
| alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, | |||||
| alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, alsa_device_t *device, channel_t chn, | |||||
| jack_nframes_t nframes) { | jack_nframes_t nframes) { | ||||
| if (driver->playback_interleaved) { | |||||
| if (device->playback_interleaved) { | |||||
| memset_interleave | memset_interleave | ||||
| (driver->playback_addr[chn], | |||||
| 0, nframes * driver->playback_sample_bytes, | |||||
| driver->interleave_unit, | |||||
| driver->playback_interleave_skip[chn]); | |||||
| (device->playback_addr[chn], | |||||
| 0, nframes * device->playback_sample_bytes, | |||||
| device->interleave_unit, | |||||
| device->playback_interleave_skip[chn]); | |||||
| } else { | } else { | ||||
| memset (driver->playback_addr[chn], 0, | |||||
| nframes * driver->playback_sample_bytes); | |||||
| memset (device->playback_addr[chn], 0, | |||||
| nframes * device->playback_sample_bytes); | |||||
| } | } | ||||
| } | } | ||||
| static inline void | static inline void | ||||
| alsa_driver_read_from_channel (alsa_driver_t *driver, | alsa_driver_read_from_channel (alsa_driver_t *driver, | ||||
| alsa_device_t *device, | |||||
| channel_t channel, | channel_t channel, | ||||
| jack_default_audio_sample_t *buf, | jack_default_audio_sample_t *buf, | ||||
| jack_nframes_t nsamples) | jack_nframes_t nsamples) | ||||
| { | { | ||||
| driver->read_via_copy (buf, | |||||
| driver->capture_addr[channel], | |||||
| device->read_via_copy (buf, | |||||
| device->capture_addr[channel], | |||||
| nsamples, | nsamples, | ||||
| driver->capture_interleave_skip[channel]); | |||||
| device->capture_interleave_skip[channel]); | |||||
| } | } | ||||
| static inline void | static inline void | ||||
| alsa_driver_write_to_channel (alsa_driver_t *driver, | alsa_driver_write_to_channel (alsa_driver_t *driver, | ||||
| alsa_device_t *device, | |||||
| channel_t channel, | channel_t channel, | ||||
| jack_default_audio_sample_t *buf, | jack_default_audio_sample_t *buf, | ||||
| jack_nframes_t nsamples) | jack_nframes_t nsamples) | ||||
| { | { | ||||
| driver->write_via_copy (driver->playback_addr[channel], | |||||
| device->write_via_copy (device->playback_addr[channel], | |||||
| buf, | buf, | ||||
| nsamples, | nsamples, | ||||
| driver->playback_interleave_skip[channel], | |||||
| device->playback_interleave_skip[channel], | |||||
| driver->dither_state+channel); | driver->dither_state+channel); | ||||
| alsa_driver_mark_channel_done (driver, channel); | |||||
| alsa_driver_mark_channel_done (driver, device, channel); | |||||
| } | } | ||||
| void alsa_driver_silence_untouched_channels (alsa_driver_t *driver, | |||||
| jack_nframes_t nframes); | |||||
| void alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn, | |||||
| ClockSyncStatus status); | |||||
| int alsa_driver_listen_for_clock_sync_status (alsa_driver_t *, | |||||
| ClockSyncListenerFunction, | |||||
| void *arg); | |||||
| int alsa_driver_stop_listen_for_clock_sync_status (alsa_driver_t *, | |||||
| unsigned int); | |||||
| void alsa_driver_clock_sync_notify (alsa_driver_t *, channel_t chn, | |||||
| ClockSyncStatus); | |||||
| int | int | ||||
| alsa_driver_reset_parameters (alsa_driver_t *driver, | alsa_driver_reset_parameters (alsa_driver_t *driver, | ||||
| jack_nframes_t frames_per_cycle, | jack_nframes_t frames_per_cycle, | ||||
| @@ -230,37 +328,31 @@ alsa_driver_reset_parameters (alsa_driver_t *driver, | |||||
| jack_nframes_t rate); | jack_nframes_t rate); | ||||
| jack_driver_t * | 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 | |||||
| ); | |||||
| alsa_driver_new (char *name, alsa_driver_info_t info, jack_client_t *client); | |||||
| void | void | ||||
| alsa_driver_delete (alsa_driver_t *driver); | alsa_driver_delete (alsa_driver_t *driver); | ||||
| int | |||||
| alsa_driver_open (alsa_driver_t *driver); | |||||
| int | int | ||||
| alsa_driver_start (alsa_driver_t *driver); | alsa_driver_start (alsa_driver_t *driver); | ||||
| int | int | ||||
| alsa_driver_stop (alsa_driver_t *driver); | alsa_driver_stop (alsa_driver_t *driver); | ||||
| int | |||||
| alsa_driver_close (alsa_driver_t *driver); | |||||
| typedef enum { | |||||
| ALSA_DRIVER_WAIT_OK = 0, | |||||
| ALSA_DRIVER_WAIT_ERROR = -1, | |||||
| ALSA_DRIVER_WAIT_XRUN = -2, | |||||
| } alsa_driver_wait_status_t; | |||||
| jack_nframes_t | jack_nframes_t | ||||
| alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| alsa_driver_wait (alsa_driver_t *driver, int extra_fd, alsa_driver_wait_status_t *status, float | |||||
| *delayed_usecs); | *delayed_usecs); | ||||
| int | int | ||||
| @@ -269,15 +361,17 @@ alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes); | |||||
| int | int | ||||
| alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes); | alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes); | ||||
| jack_time_t jack_get_microseconds(void); | |||||
| int | |||||
| alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs); | |||||
| // Code implemented in JackAlsaDriver.cpp | // Code implemented in JackAlsaDriver.cpp | ||||
| void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); | |||||
| void ReadInput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread); | |||||
| void MonitorInput(); | void MonitorInput(); | ||||
| void ClearOutput(); | void ClearOutput(); | ||||
| void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); | |||||
| void WriteOutput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten); | |||||
| void SetTime(jack_time_t time); | void SetTime(jack_time_t time); | ||||
| int Restart(); | int Restart(); | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -27,7 +27,7 @@ extern "C" | |||||
| #endif | #endif | ||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_generic_hw_new (alsa_driver_t *driver); | |||||
| jack_alsa_generic_hw_new (alsa_device_t *device); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -38,7 +38,7 @@ generic_release (jack_hardware_t *hw) | |||||
| } | } | ||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_generic_hw_new (alsa_driver_t *driver) | |||||
| jack_alsa_generic_hw_new (alsa_device_t *device) | |||||
| { | { | ||||
| jack_hardware_t *hw; | jack_hardware_t *hw; | ||||
| @@ -62,7 +62,7 @@ hammerfall_broadcast_channel_status_change (hammerfall_t *h, int lock, int sync, | |||||
| } | } | ||||
| for (chn = lowchn; chn < highchn; chn++) { | for (chn = lowchn; chn < highchn; chn++) { | ||||
| alsa_driver_set_clock_sync_status (h->driver, chn, status); | |||||
| alsa_driver_set_clock_sync_status (h->device, chn, status); | |||||
| } | } | ||||
| } | } | ||||
| @@ -87,8 +87,8 @@ hammerfall_check_sync_state (hammerfall_t *h, int val, int adat_id) | |||||
| /* XXX broken! fix for hammerfall light ! */ | /* XXX broken! fix for hammerfall light ! */ | ||||
| alsa_driver_set_clock_sync_status (h->driver, 24, status); | |||||
| alsa_driver_set_clock_sync_status (h->driver, 25, status); | |||||
| alsa_driver_set_clock_sync_status (h->device, 24, status); | |||||
| alsa_driver_set_clock_sync_status (h->device, 25, status); | |||||
| h->said_that_spdif_is_fine = TRUE; | h->said_that_spdif_is_fine = TRUE; | ||||
| } | } | ||||
| @@ -153,7 +153,7 @@ hammerfall_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||||
| snd_ctl_elem_value_set_integer (ctl, i, (mask & (1<<i)) ? 1 : 0); | snd_ctl_elem_value_set_integer (ctl, i, (mask & (1<<i)) ? 1 : 0); | ||||
| } | } | ||||
| if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) { | |||||
| if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) != 0) { | |||||
| jack_error ("ALSA/Hammerfall: cannot set input monitoring (%s)", snd_strerror (err)); | jack_error ("ALSA/Hammerfall: cannot set input monitoring (%s)", snd_strerror (err)); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -188,7 +188,7 @@ hammerfall_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||||
| break; | break; | ||||
| } | } | ||||
| if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) < 0) { | |||||
| if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) < 0) { | |||||
| jack_error ("ALSA-Hammerfall: cannot set clock mode"); | jack_error ("ALSA-Hammerfall: cannot set clock mode"); | ||||
| } | } | ||||
| @@ -244,17 +244,17 @@ hammerfall_monitor_controls (void *arg) | |||||
| snd_ctl_elem_value_set_id (sw[2], switch_id[2]); | snd_ctl_elem_value_set_id (sw[2], switch_id[2]); | ||||
| while (1) { | while (1) { | ||||
| if (snd_ctl_elem_read (h->driver->ctl_handle, sw[0])) { | |||||
| if (snd_ctl_elem_read (h->device->ctl_handle, sw[0])) { | |||||
| jack_error ("cannot read control switch 0 ..."); | jack_error ("cannot read control switch 0 ..."); | ||||
| } | } | ||||
| hammerfall_check_sync (h, sw[0]); | hammerfall_check_sync (h, sw[0]); | ||||
| if (snd_ctl_elem_read (h->driver->ctl_handle, sw[1])) { | |||||
| if (snd_ctl_elem_read (h->device->ctl_handle, sw[1])) { | |||||
| jack_error ("cannot read control switch 0 ..."); | jack_error ("cannot read control switch 0 ..."); | ||||
| } | } | ||||
| hammerfall_check_sync (h, sw[1]); | hammerfall_check_sync (h, sw[1]); | ||||
| if (snd_ctl_elem_read (h->driver->ctl_handle, sw[2])) { | |||||
| if (snd_ctl_elem_read (h->device->ctl_handle, sw[2])) { | |||||
| jack_error ("cannot read control switch 0 ..."); | jack_error ("cannot read control switch 0 ..."); | ||||
| } | } | ||||
| hammerfall_check_sync (h, sw[2]); | hammerfall_check_sync (h, sw[2]); | ||||
| @@ -269,7 +269,7 @@ hammerfall_monitor_controls (void *arg) | |||||
| #endif /* HAMMERFALL_MONITOR_CONTROLS */ | #endif /* HAMMERFALL_MONITOR_CONTROLS */ | ||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_hammerfall_hw_new (alsa_driver_t *driver) | |||||
| jack_alsa_hammerfall_hw_new (alsa_device_t *device) | |||||
| { | { | ||||
| jack_hardware_t *hw; | jack_hardware_t *hw; | ||||
| hammerfall_t *h; | hammerfall_t *h; | ||||
| @@ -293,7 +293,7 @@ jack_alsa_hammerfall_hw_new (alsa_driver_t *driver) | |||||
| h->lock_status[2] = FALSE; | h->lock_status[2] = FALSE; | ||||
| h->sync_status[2] = FALSE; | h->sync_status[2] = FALSE; | ||||
| h->said_that_spdif_is_fine = FALSE; | h->said_that_spdif_is_fine = FALSE; | ||||
| h->driver = driver; | |||||
| h->device = device; | |||||
| h->monitor_interval.tv_sec = 1; | h->monitor_interval.tv_sec = 1; | ||||
| h->monitor_interval.tv_nsec = 0; | h->monitor_interval.tv_nsec = 0; | ||||
| @@ -29,7 +29,7 @@ typedef struct | |||||
| int sync_status[3]; | int sync_status[3]; | ||||
| int said_that_spdif_is_fine; | int said_that_spdif_is_fine; | ||||
| pthread_t monitor_thread; | pthread_t monitor_thread; | ||||
| alsa_driver_t *driver; | |||||
| alsa_device_t *device; | |||||
| struct timespec monitor_interval; | struct timespec monitor_interval; | ||||
| } | } | ||||
| hammerfall_t; | hammerfall_t; | ||||
| @@ -39,7 +39,7 @@ extern "C" | |||||
| { | { | ||||
| #endif | #endif | ||||
| jack_hardware_t *jack_alsa_hammerfall_hw_new (alsa_driver_t *driver); | |||||
| jack_hardware_t *jack_alsa_hammerfall_hw_new (alsa_device_t *device); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -115,7 +115,7 @@ static int hdsp_set_mixer_gain(jack_hardware_t *hw, int input_channel, | |||||
| snd_ctl_elem_value_set_integer (ctl, 2, gain); | snd_ctl_elem_value_set_integer (ctl, 2, gain); | ||||
| /* Commit the mixer value and check for errors */ | /* Commit the mixer value and check for errors */ | ||||
| if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) { | |||||
| if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) != 0) { | |||||
| jack_error ("ALSA/HDSP: cannot set mixer gain (%s)", snd_strerror (err)); | jack_error ("ALSA/HDSP: cannot set mixer gain (%s)", snd_strerror (err)); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -206,7 +206,7 @@ hdsp_release (jack_hardware_t *hw) | |||||
| /* Mostly copied directly from hammerfall.c */ | /* Mostly copied directly from hammerfall.c */ | ||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_hdsp_hw_new (alsa_driver_t *driver) | |||||
| jack_alsa_hdsp_hw_new (alsa_device_t *device) | |||||
| { | { | ||||
| jack_hardware_t *hw; | jack_hardware_t *hw; | ||||
| hdsp_t *h; | hdsp_t *h; | ||||
| @@ -227,7 +227,7 @@ jack_alsa_hdsp_hw_new (alsa_driver_t *driver) | |||||
| hw->get_hardware_power = hdsp_get_hardware_power; | hw->get_hardware_power = hdsp_get_hardware_power; | ||||
| h = (hdsp_t *) malloc (sizeof (hdsp_t)); | h = (hdsp_t *) malloc (sizeof (hdsp_t)); | ||||
| h->driver = driver; | |||||
| h->device = device; | |||||
| hw->private_hw = h; | hw->private_hw = h; | ||||
| return hw; | return hw; | ||||
| @@ -25,7 +25,7 @@ | |||||
| typedef struct | typedef struct | ||||
| { | { | ||||
| alsa_driver_t *driver; | |||||
| alsa_device_t *device; | |||||
| } | } | ||||
| hdsp_t; | hdsp_t; | ||||
| @@ -35,7 +35,7 @@ extern "C" | |||||
| #endif | #endif | ||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_hdsp_hw_new (alsa_driver_t *driver); | |||||
| jack_alsa_hdsp_hw_new (alsa_device_t *device); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -47,7 +47,7 @@ ice1712_hw_monitor_toggle(jack_hardware_t *hw, int idx, int onoff) | |||||
| } else { | } else { | ||||
| snd_ctl_elem_value_set_enumerated (val, 0, 0); | snd_ctl_elem_value_set_enumerated (val, 0, 0); | ||||
| } | } | ||||
| if ((err = snd_ctl_elem_write (h->driver->ctl_handle, val)) != 0) { | |||||
| if ((err = snd_ctl_elem_write (h->device->ctl_handle, val)) != 0) { | |||||
| jack_error ("ALSA/ICE1712: (%d) cannot set input monitoring (%s)", | jack_error ("ALSA/ICE1712: (%d) cannot set input monitoring (%s)", | ||||
| idx,snd_strerror (err)); | idx,snd_strerror (err)); | ||||
| return -1; | return -1; | ||||
| @@ -94,7 +94,7 @@ ice1712_release (jack_hardware_t *hw) | |||||
| jack_hardware_t * | jack_hardware_t * | ||||
| jack_alsa_ice1712_hw_new (alsa_driver_t *driver) | |||||
| jack_alsa_ice1712_hw_new (alsa_device_t *device) | |||||
| { | { | ||||
| jack_hardware_t *hw; | jack_hardware_t *hw; | ||||
| ice1712_t *h; | ice1712_t *h; | ||||
| @@ -113,14 +113,14 @@ jack_alsa_ice1712_hw_new (alsa_driver_t *driver) | |||||
| h = (ice1712_t *) malloc (sizeof (ice1712_t)); | h = (ice1712_t *) malloc (sizeof (ice1712_t)); | ||||
| h->driver = driver; | |||||
| h->device = device; | |||||
| /* Get the EEPROM (adopted from envy24control) */ | /* Get the EEPROM (adopted from envy24control) */ | ||||
| h->eeprom = (ice1712_eeprom_t *) malloc (sizeof (ice1712_eeprom_t)); | h->eeprom = (ice1712_eeprom_t *) malloc (sizeof (ice1712_eeprom_t)); | ||||
| snd_ctl_elem_value_alloca (&val); | snd_ctl_elem_value_alloca (&val); | ||||
| snd_ctl_elem_value_set_interface (val, SND_CTL_ELEM_IFACE_CARD); | snd_ctl_elem_value_set_interface (val, SND_CTL_ELEM_IFACE_CARD); | ||||
| snd_ctl_elem_value_set_name (val, "ICE1712 EEPROM"); | snd_ctl_elem_value_set_name (val, "ICE1712 EEPROM"); | ||||
| if ((err = snd_ctl_elem_read (driver->ctl_handle, val)) < 0) { | |||||
| if ((err = snd_ctl_elem_read (device->ctl_handle, val)) < 0) { | |||||
| jack_error( "ALSA/ICE1712: Unable to read EEPROM contents (%s)\n", snd_strerror (err)); | jack_error( "ALSA/ICE1712: Unable to read EEPROM contents (%s)\n", snd_strerror (err)); | ||||
| /* Recover? */ | /* Recover? */ | ||||
| } | } | ||||
| @@ -59,7 +59,7 @@ ice1712_eeprom_t; | |||||
| typedef struct | typedef struct | ||||
| { | { | ||||
| alsa_driver_t *driver; | |||||
| alsa_device_t *device; | |||||
| ice1712_eeprom_t *eeprom; | ice1712_eeprom_t *eeprom; | ||||
| unsigned long active_channels; | unsigned long active_channels; | ||||
| } | } | ||||
| @@ -70,7 +70,7 @@ extern "C" | |||||
| { | { | ||||
| #endif | #endif | ||||
| jack_hardware_t *jack_alsa_ice1712_hw_new (alsa_driver_t *driver); | |||||
| jack_hardware_t *jack_alsa_ice1712_hw_new (alsa_device_t *device); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| @@ -22,6 +22,8 @@ | |||||
| #ifndef __jack_usx2y_h__ | #ifndef __jack_usx2y_h__ | ||||
| #define __jack_usx2y_h__ | #define __jack_usx2y_h__ | ||||
| #include <poll.h> | |||||
| #define USX2Y_MAXPACK 50 | #define USX2Y_MAXPACK 50 | ||||
| #define USX2Y_MAXBUFFERMS 100 | #define USX2Y_MAXBUFFERMS 100 | ||||
| #define USX2Y_MAXSTRIDE 3 | #define USX2Y_MAXSTRIDE 3 | ||||
| @@ -51,7 +53,9 @@ typedef struct snd_usX2Y_hwdep_pcm_shm snd_usX2Y_hwdep_pcm_shm_t; | |||||
| typedef struct | typedef struct | ||||
| { | { | ||||
| alsa_driver_t *driver; | alsa_driver_t *driver; | ||||
| #ifndef __QNXNTO__ | |||||
| snd_hwdep_t *hwdep_handle; | snd_hwdep_t *hwdep_handle; | ||||
| #endif | |||||
| struct pollfd pfds; | struct pollfd pfds; | ||||
| struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm; | struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm; | ||||
| int playback_iso_start; | int playback_iso_start; | ||||
| @@ -44,7 +44,7 @@ class SERVER_EXPORT JackFifo : public detail::JackSynchro | |||||
| protected: | protected: | ||||
| void BuildName(const char* name, const char* server_name, char* res); | |||||
| void BuildName(const char* name, const char* server_name, char* res, int size); | |||||
| public: | public: | ||||
| @@ -0,0 +1,86 @@ | |||||
| /* | |||||
| 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. | |||||
| */ | |||||
| #ifndef __JackAtomic_linux__ | |||||
| #define __JackAtomic_linux__ | |||||
| #include "JackTypes.h" | |||||
| #ifdef __PPC__ | |||||
| static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr) | |||||
| { | |||||
| register int result; | |||||
| register UInt32 tmp; | |||||
| asm volatile ( | |||||
| "# CAS \n" | |||||
| " lwarx %4, 0, %1 \n" // creates a reservation on addr | |||||
| " cmpw %4, %2 \n" // test value at addr | |||||
| " bne- 1f \n" | |||||
| " sync \n" // synchronize instructions | |||||
| " stwcx. %3, 0, %1 \n" // if the reservation is not altered | |||||
| // stores the new value at addr | |||||
| " bne- 1f \n" | |||||
| " li %0, 1 \n" | |||||
| " b 2f \n" | |||||
| "1: \n" | |||||
| " li %0, 0 \n" | |||||
| "2: \n" | |||||
| : "=r" (result) | |||||
| : "r" (addr), "r" (value), "r" (newvalue), "r" (tmp) | |||||
| ); | |||||
| return result; | |||||
| } | |||||
| #endif | |||||
| #if defined(__i386__) || defined(__x86_64__) | |||||
| #define LOCK "lock ; " | |||||
| static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) | |||||
| { | |||||
| register char ret; | |||||
| __asm__ __volatile__ ( | |||||
| "# CAS \n\t" | |||||
| LOCK "cmpxchg %2, (%1) \n\t" | |||||
| "sete %0 \n\t" | |||||
| : "=a" (ret) | |||||
| : "c" (addr), "d" (newvalue), "a" (value) | |||||
| ); | |||||
| return ret; | |||||
| } | |||||
| #endif | |||||
| #if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__) | |||||
| static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) | |||||
| { | |||||
| return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue); | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,215 @@ | |||||
| /* | |||||
| Copyright (C) 2001-2003 Paul Davis | |||||
| Copyright (C) 2005 Jussi Laako | |||||
| 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. | |||||
| */ | |||||
| #include "JackConstants.h" | |||||
| #include "JackTime.h" | |||||
| #include "JackTypes.h" | |||||
| #include "JackError.h" | |||||
| #include <stdint.h> | |||||
| #include <stdio.h> | |||||
| #include <sys/mman.h> | |||||
| #include <sys/time.h> | |||||
| #include <sys/types.h> | |||||
| #include <sys/stat.h> | |||||
| #include <fcntl.h> | |||||
| #include <errno.h> | |||||
| #include <string.h> | |||||
| #include <unistd.h> | |||||
| #include <stdlib.h> | |||||
| #include <inttypes.h> | |||||
| jack_time_t (*_jack_get_microseconds)(void) = 0; | |||||
| #if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__)) | |||||
| #define HPET_SUPPORT | |||||
| #define HPET_MMAP_SIZE 1024 | |||||
| #define HPET_CAPS 0x000 | |||||
| #define HPET_PERIOD 0x004 | |||||
| #define HPET_COUNTER 0x0f0 | |||||
| #define HPET_CAPS_COUNTER_64BIT (1 << 13) | |||||
| #if defined(__x86_64__) | |||||
| typedef uint64_t hpet_counter_t; | |||||
| #else | |||||
| typedef uint32_t hpet_counter_t; | |||||
| #endif | |||||
| static int hpet_fd; | |||||
| static unsigned char *hpet_ptr; | |||||
| static uint32_t hpet_period; /* period length in femto secs */ | |||||
| static uint64_t hpet_offset = 0; | |||||
| static uint64_t hpet_wrap; | |||||
| static hpet_counter_t hpet_previous = 0; | |||||
| #endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */ | |||||
| #ifdef HPET_SUPPORT | |||||
| static int jack_hpet_init () | |||||
| { | |||||
| uint32_t hpet_caps; | |||||
| hpet_fd = open("/dev/hpet", O_RDONLY); | |||||
| if (hpet_fd < 0) { | |||||
| jack_error ("This system has no accessible HPET device (%s)", strerror (errno)); | |||||
| return -1; | |||||
| } | |||||
| hpet_ptr = (unsigned char *) mmap(NULL, HPET_MMAP_SIZE, | |||||
| PROT_READ, MAP_SHARED, hpet_fd, 0); | |||||
| if (hpet_ptr == MAP_FAILED) { | |||||
| jack_error ("This system has no mappable HPET device (%s)", strerror (errno)); | |||||
| close (hpet_fd); | |||||
| return -1; | |||||
| } | |||||
| /* this assumes period to be constant. if needed, | |||||
| 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)); | |||||
| hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) && | |||||
| (sizeof(hpet_counter_t) == sizeof(uint64_t))) ? | |||||
| 0 : ((uint64_t) 1 << 32); | |||||
| return 0; | |||||
| } | |||||
| static jack_time_t jack_get_microseconds_from_hpet (void) | |||||
| { | |||||
| hpet_counter_t hpet_counter; | |||||
| long double hpet_time; | |||||
| hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER)); | |||||
| if (hpet_counter < hpet_previous) | |||||
| hpet_offset += hpet_wrap; | |||||
| hpet_previous = hpet_counter; | |||||
| hpet_time = (long double) (hpet_offset + hpet_counter) * | |||||
| (long double) hpet_period * (long double) 1e-9; | |||||
| return ((jack_time_t) (hpet_time + 0.5)); | |||||
| } | |||||
| #else | |||||
| static int jack_hpet_init () | |||||
| { | |||||
| jack_error ("This version of JACK or this computer does not have HPET support.\n" | |||||
| "Please choose a different clock source."); | |||||
| return -1; | |||||
| } | |||||
| static jack_time_t jack_get_microseconds_from_hpet (void) | |||||
| { | |||||
| /* never called */ | |||||
| return 0; | |||||
| } | |||||
| #endif /* HPET_SUPPORT */ | |||||
| #define HAVE_CLOCK_GETTIME 1 | |||||
| #ifndef HAVE_CLOCK_GETTIME | |||||
| static jack_time_t jack_get_microseconds_from_system (void) | |||||
| { | |||||
| jack_time_t jackTime; | |||||
| struct timeval tv; | |||||
| gettimeofday (&tv, NULL); | |||||
| jackTime = (jack_time_t) tv.tv_sec * 1000000 + (jack_time_t) tv.tv_usec; | |||||
| return jackTime; | |||||
| } | |||||
| #else | |||||
| static jack_time_t jack_get_microseconds_from_system (void) | |||||
| { | |||||
| jack_time_t jackTime; | |||||
| struct timespec time; | |||||
| clock_gettime(CLOCK_MONOTONIC, &time); | |||||
| jackTime = (jack_time_t) time.tv_sec * 1e6 + | |||||
| (jack_time_t) time.tv_nsec / 1e3; | |||||
| return jackTime; | |||||
| } | |||||
| #endif /* HAVE_CLOCK_GETTIME */ | |||||
| SERVER_EXPORT void JackSleep(long usec) | |||||
| { | |||||
| usleep(usec); | |||||
| } | |||||
| SERVER_EXPORT void InitTime() | |||||
| { | |||||
| /* nothing to do on a generic system - we use the system clock */ | |||||
| } | |||||
| SERVER_EXPORT void EndTime() | |||||
| {} | |||||
| void SetClockSource(jack_timer_type_t source) | |||||
| { | |||||
| jack_log("Clock source : %s", ClockSourceName(source)); | |||||
| switch (source) | |||||
| { | |||||
| case JACK_TIMER_HPET: | |||||
| if (jack_hpet_init () == 0) { | |||||
| _jack_get_microseconds = jack_get_microseconds_from_hpet; | |||||
| } else { | |||||
| _jack_get_microseconds = jack_get_microseconds_from_system; | |||||
| } | |||||
| break; | |||||
| case JACK_TIMER_SYSTEM_CLOCK: | |||||
| default: | |||||
| _jack_get_microseconds = jack_get_microseconds_from_system; | |||||
| break; | |||||
| } | |||||
| } | |||||
| const char* ClockSourceName(jack_timer_type_t source) | |||||
| { | |||||
| switch (source) { | |||||
| case JACK_TIMER_HPET: | |||||
| return "hpet"; | |||||
| case JACK_TIMER_SYSTEM_CLOCK: | |||||
| #ifdef HAVE_CLOCK_GETTIME | |||||
| return "system clock via clock_gettime"; | |||||
| #else | |||||
| return "system clock via gettimeofday"; | |||||
| #endif | |||||
| } | |||||
| /* what is wrong with gcc ? */ | |||||
| return "unknown"; | |||||
| } | |||||
| SERVER_EXPORT jack_time_t GetMicroSeconds() | |||||
| { | |||||
| return _jack_get_microseconds(); | |||||
| } | |||||
| SERVER_EXPORT jack_time_t jack_get_microseconds() | |||||
| { | |||||
| return _jack_get_microseconds(); | |||||
| } | |||||
| @@ -0,0 +1,85 @@ | |||||
| /* | |||||
| 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. | |||||
| */ | |||||
| #ifndef __JackPlatformPlug_linux__ | |||||
| #define __JackPlatformPlug_linux__ | |||||
| #define jack_server_dir "/dev/shm" | |||||
| #define jack_client_dir "/dev/shm" | |||||
| #define JACK_DEFAULT_DRIVER "alsa" | |||||
| namespace Jack | |||||
| { | |||||
| struct JackRequest; | |||||
| struct JackResult; | |||||
| class JackPosixMutex; | |||||
| class JackPosixThread; | |||||
| class JackFifo; | |||||
| class JackSocketServerChannel; | |||||
| class JackSocketClientChannel; | |||||
| class JackSocketServerNotifyChannel; | |||||
| class JackSocketNotifyChannel; | |||||
| class JackClientSocket; | |||||
| class JackNetUnixSocket; | |||||
| } | |||||
| /* __JackPlatformMutex__ */ | |||||
| #include "JackPosixMutex.h" | |||||
| namespace Jack {typedef JackPosixMutex JackMutex; } | |||||
| /* __JackPlatformThread__ */ | |||||
| #include "JackPosixThread.h" | |||||
| namespace Jack { typedef JackPosixThread JackThread; } | |||||
| #include "JackFifo.h" | |||||
| namespace Jack { typedef JackFifo JackSynchro; } | |||||
| /* __JackPlatformChannelTransaction__ */ | |||||
| /* | |||||
| #include "JackSocket.h" | |||||
| namespace Jack { typedef JackClientSocket JackChannelTransaction; } | |||||
| */ | |||||
| /* __JackPlatformProcessSync__ */ | |||||
| #include "JackPosixProcessSync.h" | |||||
| namespace Jack { typedef JackPosixProcessSync JackProcessSync; } | |||||
| /* __JackPlatformServerChannel__ */ | |||||
| #include "JackSocketServerChannel.h" | |||||
| namespace Jack { typedef JackSocketServerChannel JackServerChannel; } | |||||
| /* __JackPlatformClientChannel__ */ | |||||
| #include "JackSocketClientChannel.h" | |||||
| namespace Jack { typedef JackSocketClientChannel JackClientChannel; } | |||||
| /* __JackPlatformServerNotifyChannel__ */ | |||||
| #include "JackSocketServerNotifyChannel.h" | |||||
| namespace Jack { typedef JackSocketServerNotifyChannel JackServerNotifyChannel; } | |||||
| /* __JackPlatformNotifyChannel__ */ | |||||
| #include "JackSocketNotifyChannel.h" | |||||
| namespace Jack { typedef JackSocketNotifyChannel JackNotifyChannel; } | |||||
| /* __JackPlatformNetSocket__ */ | |||||
| #include "JackNetUnixSocket.h" | |||||
| namespace Jack { typedef JackNetUnixSocket JackNetSocket; } | |||||
| #endif | |||||
| @@ -0,0 +1,300 @@ | |||||
| /* | |||||
| 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. | |||||
| $Id: driver.h,v 1.2 2005/11/23 11:24:29 letz Exp $ | |||||
| */ | |||||
| #ifndef __jack_driver_h__ | |||||
| #define __jack_driver_h__ | |||||
| #include <pthread.h> | |||||
| #include "types.h" | |||||
| #include "jslist.h" | |||||
| #include "driver_interface.h" | |||||
| typedef float gain_t; | |||||
| typedef long channel_t; | |||||
| typedef enum { | |||||
| Lock = 0x1, | |||||
| NoLock = 0x2, | |||||
| Sync = 0x4, | |||||
| NoSync = 0x8 | |||||
| } ClockSyncStatus; | |||||
| typedef void (*ClockSyncListenerFunction)(channel_t, ClockSyncStatus, void*); | |||||
| typedef struct | |||||
| { | |||||
| unsigned long id; | |||||
| ClockSyncListenerFunction function; | |||||
| void *arg; | |||||
| } | |||||
| ClockSyncListener; | |||||
| struct _jack_engine; | |||||
| struct _jack_driver; | |||||
| typedef int (*JackDriverAttachFunction)(struct _jack_driver *, | |||||
| struct _jack_engine *); | |||||
| typedef int (*JackDriverDetachFunction)(struct _jack_driver *, | |||||
| struct _jack_engine *); | |||||
| typedef int (*JackDriverReadFunction)(struct _jack_driver *, | |||||
| jack_nframes_t nframes); | |||||
| typedef int (*JackDriverWriteFunction)(struct _jack_driver *, | |||||
| jack_nframes_t nframes); | |||||
| typedef int (*JackDriverNullCycleFunction)(struct _jack_driver *, | |||||
| jack_nframes_t nframes); | |||||
| typedef int (*JackDriverStopFunction)(struct _jack_driver *); | |||||
| typedef int (*JackDriverStartFunction)(struct _jack_driver *); | |||||
| typedef int (*JackDriverBufSizeFunction)(struct _jack_driver *, | |||||
| jack_nframes_t nframes); | |||||
| /* | |||||
| Call sequence summary: | |||||
| 1) engine loads driver via runtime dynamic linking | |||||
| - calls jack_driver_load | |||||
| - we call dlsym for "driver_initialize" and execute it | |||||
| 2) engine attaches to driver | |||||
| 3) engine starts driver | |||||
| 4) driver runs its own thread, calling | |||||
| while () { | |||||
| driver->wait (); | |||||
| driver->engine->run_cycle () | |||||
| } | |||||
| 5) engine stops driver | |||||
| 6) engine detaches from driver | |||||
| 7) engine calls driver `finish' routine | |||||
| Note that stop/start may be called multiple times in the event of an | |||||
| error return from the `wait' function. | |||||
| */ | |||||
| typedef struct _jack_driver | |||||
| { | |||||
| /* The _jack_driver structure fields are included at the beginning of | |||||
| each driver-specific structure using the JACK_DRIVER_DECL macro, | |||||
| which is defined below. The comments that follow describe each | |||||
| common field. | |||||
| The driver should set this to be the interval it expects to elapse | |||||
| between returning from the `wait' function. if set to zero, it | |||||
| implies that the driver does not expect regular periodic wakeups. | |||||
| jack_time_t period_usecs; | |||||
| The driver should set this within its "wait" function to indicate | |||||
| the UST of the most recent determination that the engine cycle | |||||
| should run. it should not be set if the "extra_fd" argument of | |||||
| the wait function is set to a non-zero value. | |||||
| jack_time_t last_wait_ust; | |||||
| These are not used by the driver. They should not be written to or | |||||
| modified in any way | |||||
| void *handle; | |||||
| struct _jack_internal_client *internal_client; | |||||
| This should perform any cleanup associated with the driver. it will | |||||
| be called when jack server process decides to get rid of the | |||||
| driver. in some systems, it may not be called at all, so the driver | |||||
| should never rely on a call to this. it can set it to NULL if | |||||
| it has nothing do do. | |||||
| void (*finish)(struct _jack_driver *); | |||||
| The JACK engine will call this when it wishes to attach itself to | |||||
| the driver. the engine will pass a pointer to itself, which the driver | |||||
| may use in anyway it wishes to. the driver may assume that this | |||||
| is the same engine object that will make `wait' calls until a | |||||
| `detach' call is made. | |||||
| JackDriverAttachFunction attach; | |||||
| The JACK engine will call this when it is finished using a driver. | |||||
| JackDriverDetachFunction detach; | |||||
| The JACK engine will call this when it wants to wait until the | |||||
| driver decides that its time to process some data. the driver returns | |||||
| a count of the number of audioframes that can be processed. | |||||
| it should set the variable pointed to by `status' as follows: | |||||
| zero: the wait completed normally, processing may begin | |||||
| negative: the wait failed, and recovery is not possible | |||||
| positive: the wait failed, and the driver stopped itself. | |||||
| a call to `start' will return the driver to | |||||
| a correct and known state. | |||||
| the driver should also fill out the `delayed_usecs' variable to | |||||
| indicate any delay in its expected periodic execution. for example, | |||||
| if it discovers that its return from poll(2) is later than it | |||||
| expects it to be, it would place an estimate of the delay | |||||
| in this variable. the engine will use this to decide if it | |||||
| plans to continue execution. | |||||
| JackDriverWaitFunction wait; | |||||
| The JACK engine will call this to ask the driver to move | |||||
| data from its inputs to its output port buffers. it should | |||||
| return 0 to indicate successful completion, negative otherwise. | |||||
| This function will always be called after the wait function (above). | |||||
| JackDriverReadFunction read; | |||||
| The JACK engine will call this to ask the driver to move | |||||
| data from its input port buffers to its outputs. it should | |||||
| return 0 to indicate successful completion, negative otherwise. | |||||
| this function will always be called after the read function (above). | |||||
| JackDriverWriteFunction write; | |||||
| The JACK engine will call this after the wait function (above) has | |||||
| been called, but for some reason the engine is unable to execute | |||||
| a full "cycle". the driver should do whatever is necessary to | |||||
| keep itself running correctly, but cannot reference ports | |||||
| or other JACK data structures in any way. | |||||
| JackDriverNullCycleFunction null_cycle; | |||||
| The engine will call this when it plans to stop calling the `wait' | |||||
| function for some period of time. the driver should take | |||||
| appropriate steps to handle this (possibly no steps at all). | |||||
| NOTE: the driver must silence its capture buffers (if any) | |||||
| from within this function or the function that actually | |||||
| implements the change in state. | |||||
| JackDriverStopFunction stop; | |||||
| The engine will call this to let the driver know that it plans | |||||
| to start calling the `wait' function on a regular basis. the driver | |||||
| should take any appropriate steps to handle this (possibly no steps | |||||
| at all). NOTE: The driver may wish to silence its playback buffers | |||||
| (if any) from within this function or the function that actually | |||||
| implements the change in state. | |||||
| JackDriverStartFunction start; | |||||
| The engine will call this to let the driver know that some client | |||||
| has requested a new buffer size. The stop function will be called | |||||
| prior to this, and the start function after this one has returned. | |||||
| JackDriverBufSizeFunction bufsize; | |||||
| */ | |||||
| /* define the fields here... */ | |||||
| #define JACK_DRIVER_DECL \ | |||||
| jack_time_t period_usecs; \ | |||||
| jack_time_t last_wait_ust; \ | |||||
| void *handle; \ | |||||
| struct _jack_client_internal * internal_client; \ | |||||
| void (*finish)(struct _jack_driver *);\ | |||||
| JackDriverAttachFunction attach; \ | |||||
| JackDriverDetachFunction detach; \ | |||||
| JackDriverReadFunction read; \ | |||||
| JackDriverWriteFunction write; \ | |||||
| JackDriverNullCycleFunction null_cycle; \ | |||||
| JackDriverStopFunction stop; \ | |||||
| JackDriverStartFunction start; \ | |||||
| JackDriverBufSizeFunction bufsize; | |||||
| JACK_DRIVER_DECL /* expand the macro */ | |||||
| } | |||||
| jack_driver_t; | |||||
| void jack_driver_init (jack_driver_t *); | |||||
| void jack_driver_release (jack_driver_t *); | |||||
| jack_driver_t *jack_driver_load (int argc, char **argv); | |||||
| void jack_driver_unload (jack_driver_t *); | |||||
| /**************************** | |||||
| *** Non-Threaded Drivers *** | |||||
| ****************************/ | |||||
| /* | |||||
| Call sequence summary: | |||||
| 1) engine loads driver via runtime dynamic linking | |||||
| - calls jack_driver_load | |||||
| - we call dlsym for "driver_initialize" and execute it | |||||
| - driver_initialize calls jack_driver_nt_init | |||||
| 2) nt layer attaches to driver | |||||
| 3) nt layer starts driver | |||||
| 4) nt layer runs a thread, calling | |||||
| while () { | |||||
| driver->nt_run_ctcle(); | |||||
| } | |||||
| 5) nt layer stops driver | |||||
| 6) nt layer detaches driver | |||||
| 7) engine calls driver `finish' routine which calls jack_driver_nt_finish | |||||
| Note that stop/start may be called multiple times in the event of an | |||||
| error return from the `wait' function. | |||||
| */ | |||||
| struct _jack_driver_nt; | |||||
| typedef int (*JackDriverNTAttachFunction)(struct _jack_driver_nt *); | |||||
| typedef int (*JackDriverNTDetachFunction)(struct _jack_driver_nt *); | |||||
| typedef int (*JackDriverNTStopFunction)(struct _jack_driver_nt *); | |||||
| typedef int (*JackDriverNTStartFunction)(struct _jack_driver_nt *); | |||||
| typedef int (*JackDriverNTBufSizeFunction)(struct _jack_driver_nt *, | |||||
| jack_nframes_t nframes); | |||||
| typedef int (*JackDriverNTRunCycleFunction)(struct _jack_driver_nt *); | |||||
| typedef struct _jack_driver_nt | |||||
| { | |||||
| #define JACK_DRIVER_NT_DECL \ | |||||
| JACK_DRIVER_DECL \ | |||||
| struct _jack_engine * engine; \ | |||||
| volatile int nt_run; \ | |||||
| pthread_t nt_thread; \ | |||||
| pthread_mutex_t nt_run_lock; \ | |||||
| JackDriverNTAttachFunction nt_attach; \ | |||||
| JackDriverNTDetachFunction nt_detach; \ | |||||
| JackDriverNTStopFunction nt_stop; \ | |||||
| JackDriverNTStartFunction nt_start; \ | |||||
| JackDriverNTBufSizeFunction nt_bufsize; \ | |||||
| JackDriverNTRunCycleFunction nt_run_cycle; | |||||
| #define nt_read read | |||||
| #define nt_write write | |||||
| #define nt_null_cycle null_cycle | |||||
| JACK_DRIVER_NT_DECL | |||||
| } | |||||
| jack_driver_nt_t; | |||||
| void jack_driver_nt_init (jack_driver_nt_t * driver); | |||||
| void jack_driver_nt_finish (jack_driver_nt_t * driver); | |||||
| #endif /* __jack_driver_h__ */ | |||||
| @@ -20,6 +20,8 @@ def build(bld): | |||||
| prog.includes = ['..','../macosx', '../posix', '../common/jack', '../common'] | prog.includes = ['..','../macosx', '../posix', '../common/jack', '../common'] | ||||
| if bld.env['IS_LINUX']: | if bld.env['IS_LINUX']: | ||||
| prog.includes = ['..','../linux', '../posix', '../common/jack', '../common'] | prog.includes = ['..','../linux', '../posix', '../common/jack', '../common'] | ||||
| if bld.env['IS_QNX']: | |||||
| prog.includes = ['..','../qnx', '../posix', '../common/jack', '../common'] | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| prog.includes = ['..','../solaris', '../posix', '../common/jack', '../common'] | prog.includes = ['..','../solaris', '../posix', '../common/jack', '../common'] | ||||
| prog.source = test_program_sources | prog.source = test_program_sources | ||||
| @@ -95,6 +95,15 @@ def options(opt): | |||||
| alsa.check_cfg( | alsa.check_cfg( | ||||
| package='alsa >= 1.0.18', | package='alsa >= 1.0.18', | ||||
| args='--cflags --libs') | args='--cflags --libs') | ||||
| # Check for QNX sound headers | |||||
| qsa = opt.add_auto_option( | |||||
| 'qsa', | |||||
| help='Enable QNX sound driver', | |||||
| conf_dest='BUILD_DRIVER_ALSA') | |||||
| qsa.check(lib='asound', uselib_store='ALSA') | |||||
| qsa.check( | |||||
| header_name=['sys/asoundlib.h'], | |||||
| msg='Checking for header sys/asoundlib.h') | |||||
| firewire = opt.add_auto_option( | firewire = opt.add_auto_option( | ||||
| 'firewire', | 'firewire', | ||||
| help='Enable FireWire driver (FFADO)', | help='Enable FireWire driver (FFADO)', | ||||
| @@ -185,6 +194,7 @@ def detect_platform(conf): | |||||
| platforms = [ | platforms = [ | ||||
| # ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for']) | # ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for']) | ||||
| ('IS_LINUX', 'Linux', ['gnu0', 'gnukfreebsd', 'linux', 'posix']), | ('IS_LINUX', 'Linux', ['gnu0', 'gnukfreebsd', 'linux', 'posix']), | ||||
| ('IS_QNX', 'QNX', ['qnx']), | |||||
| ('IS_MACOSX', 'MacOS X', ['darwin']), | ('IS_MACOSX', 'MacOS X', ['darwin']), | ||||
| ('IS_SUN', 'SunOS', ['sunos']), | ('IS_SUN', 'SunOS', ['sunos']), | ||||
| ('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32']) | ('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32']) | ||||
| @@ -304,7 +314,11 @@ def configure(conf): | |||||
| conf.check_cc(fragment=fragment, define_name='HAVE_NGREG', mandatory=False, | conf.check_cc(fragment=fragment, define_name='HAVE_NGREG', mandatory=False, | ||||
| msg='Checking for NGREG') | msg='Checking for NGREG') | ||||
| conf.env['LIB_PTHREAD'] = ['pthread'] | |||||
| if conf.env['IS_QNX']: | |||||
| conf.env['LIB_PTHREAD'] = ['c'] | |||||
| conf.env['LIB_SOCKET'] = ['socket'] | |||||
| else: | |||||
| conf.env['LIB_PTHREAD'] = ['pthread'] | |||||
| conf.env['LIB_DL'] = ['dl'] | conf.env['LIB_DL'] = ['dl'] | ||||
| conf.env['LIB_RT'] = ['rt'] | conf.env['LIB_RT'] = ['rt'] | ||||
| conf.env['LIB_M'] = ['m'] | conf.env['LIB_M'] = ['m'] | ||||
| @@ -512,6 +526,9 @@ def obj_add_includes(bld, obj): | |||||
| if bld.env['IS_MACOSX']: | if bld.env['IS_MACOSX']: | ||||
| obj.includes += ['macosx', 'posix'] | obj.includes += ['macosx', 'posix'] | ||||
| if bld.env['IS_QNX']: | |||||
| obj.includes += ['qnx', 'posix'] | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| obj.includes += ['posix', 'solaris'] | obj.includes += ['posix', 'solaris'] | ||||
| @@ -540,6 +557,10 @@ def build_jackd(bld): | |||||
| jackd.use += ['DL', 'PTHREAD'] | jackd.use += ['DL', 'PTHREAD'] | ||||
| jackd.framework = ['CoreFoundation'] | jackd.framework = ['CoreFoundation'] | ||||
| if bld.env['IS_QNX']: | |||||
| jackd.use += ['M', 'PTHREAD'] | |||||
| if bld.env['IS_SUN']: | if bld.env['IS_SUN']: | ||||
| jackd.use += ['DL', 'PTHREAD'] | jackd.use += ['DL', 'PTHREAD'] | ||||
| @@ -598,16 +619,20 @@ def build_drivers(bld): | |||||
| alsa_src = [ | alsa_src = [ | ||||
| 'common/memops.c', | 'common/memops.c', | ||||
| 'linux/alsa/JackAlsaDriver.cpp', | 'linux/alsa/JackAlsaDriver.cpp', | ||||
| 'linux/alsa/alsa_rawmidi.c', | |||||
| 'linux/alsa/alsa_seqmidi.c', | |||||
| 'linux/alsa/alsa_midi_jackmp.cpp', | |||||
| 'linux/alsa/generic_hw.c', | |||||
| 'linux/alsa/hdsp.c', | |||||
| 'linux/alsa/alsa_driver.c', | |||||
| 'linux/alsa/hammerfall.c', | |||||
| 'linux/alsa/ice1712.c' | |||||
| 'linux/alsa/alsa_driver.c' | |||||
| ] | ] | ||||
| if not bld.env['IS_QNX']: | |||||
| alsa_src += [ | |||||
| 'linux/alsa/alsa_rawmidi.c', | |||||
| 'linux/alsa/alsa_seqmidi.c', | |||||
| 'linux/alsa/alsa_midi_jackmp.cpp', | |||||
| 'linux/alsa/generic_hw.c', | |||||
| 'linux/alsa/hdsp.c', | |||||
| 'linux/alsa/hammerfall.c', | |||||
| 'linux/alsa/ice1712.c' | |||||
| ] | |||||
| alsarawmidi_src = [ | alsarawmidi_src = [ | ||||
| 'linux/alsarawmidi/JackALSARawMidiDriver.cpp', | 'linux/alsarawmidi/JackALSARawMidiDriver.cpp', | ||||
| 'linux/alsarawmidi/JackALSARawMidiInputPort.cpp', | 'linux/alsarawmidi/JackALSARawMidiInputPort.cpp', | ||||
| @@ -704,11 +729,12 @@ def build_drivers(bld): | |||||
| target = 'alsa', | target = 'alsa', | ||||
| source = alsa_src, | source = alsa_src, | ||||
| use = ['ALSA']) | use = ['ALSA']) | ||||
| create_driver_obj( | |||||
| bld, | |||||
| target = 'alsarawmidi', | |||||
| source = alsarawmidi_src, | |||||
| use = ['ALSA']) | |||||
| if not bld.env['IS_QNX']: | |||||
| create_driver_obj( | |||||
| bld, | |||||
| target = 'alsarawmidi', | |||||
| source = alsarawmidi_src, | |||||
| use = ['ALSA']) | |||||
| if bld.env['BUILD_DRIVER_FFADO']: | if bld.env['BUILD_DRIVER_FFADO']: | ||||
| create_driver_obj( | create_driver_obj( | ||||