| @@ -0,0 +1,54 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <?fileVersion 4.0.0?> | |||
| <cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> | |||
| <storageModule moduleId="org.eclipse.cdt.core.settings"> | |||
| <cconfiguration id="com.qnx.qcc.toolChain.1426688628"> | |||
| <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.toolChain.1426688628" moduleId="org.eclipse.cdt.core.settings" name="Default"> | |||
| <externalSettings/> | |||
| <extensions> | |||
| <extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/> | |||
| <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> | |||
| <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> | |||
| <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> | |||
| </extensions> | |||
| </storageModule> | |||
| <storageModule moduleId="cdtBuildSystem" version="4.0.0"> | |||
| <configuration artifactName="${ProjName}" buildProperties="" id="com.qnx.qcc.toolChain.1426688628" name="Default" parent="org.eclipse.cdt.build.core.emptycfg"> | |||
| <folderInfo id="com.qnx.qcc.toolChain.1426688628.2053955807" name="/" resourcePath=""> | |||
| <toolChain id="com.qnx.qcc.toolChain.438169716" name="com.qnx.qcc.toolChain" superClass="com.qnx.qcc.toolChain"> | |||
| <option id="com.qnx.qcc.option.os.1677980343" name="Target OS:" superClass="com.qnx.qcc.option.os"/> | |||
| <option id="com.qnx.qcc.option.cpu.56565625" name="Target CPU:" superClass="com.qnx.qcc.option.cpu"/> | |||
| <option id="com.qnx.qcc.option.compiler.742352083" name="Compiler:" superClass="com.qnx.qcc.option.compiler"/> | |||
| <option id="com.qnx.qcc.option.runtime.1596137464" name="Runtime:" superClass="com.qnx.qcc.option.runtime"/> | |||
| <targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1124193828" osList="all" superClass="com.qnx.qcc.targetPlatform"/> | |||
| <builder id="com.qnx.qcc.toolChain.1426688628.655316141" managedBuildOn="false" name="Gnu Make Builder.Preference Configuration" superClass="org.eclipse.cdt.build.core.settings.default.builder"/> | |||
| <tool id="com.qnx.qcc.tool.compiler.938460844" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler"> | |||
| <option id="com.qnx.qcc.option.compiler.optlevel.1413154425" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.0" valueType="enumerated"/> | |||
| <inputType id="com.qnx.qcc.inputType.compiler.775408002" superClass="com.qnx.qcc.inputType.compiler"/> | |||
| </tool> | |||
| <tool id="com.qnx.qcc.tool.assembler.1741326744" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler"> | |||
| <inputType id="com.qnx.qcc.inputType.assembler.969556839" superClass="com.qnx.qcc.inputType.assembler"/> | |||
| </tool> | |||
| <tool id="com.qnx.qcc.tool.linker.1638240831" name="QCC Linker" superClass="com.qnx.qcc.tool.linker"> | |||
| <option id="com.qnx.qcc.option.linker.langcpp.1442166281" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/> | |||
| </tool> | |||
| <tool id="com.qnx.qcc.tool.archiver.594954823" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/> | |||
| </toolChain> | |||
| </folderInfo> | |||
| </configuration> | |||
| </storageModule> | |||
| <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> | |||
| </cconfiguration> | |||
| </storageModule> | |||
| <storageModule moduleId="cdtBuildSystem" version="4.0.0"> | |||
| <project id="jack2.null.1473030055" name="jack2"/> | |||
| </storageModule> | |||
| <storageModule moduleId="scannerConfiguration"> | |||
| <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/> | |||
| <scannerConfigBuildInfo instanceId="com.qnx.qcc.toolChain.1426688628"> | |||
| <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/> | |||
| </scannerConfigBuildInfo> | |||
| </storageModule> | |||
| <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> | |||
| </cproject> | |||
| @@ -0,0 +1,27 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <projectDescription> | |||
| <name>jack2</name> | |||
| <comment></comment> | |||
| <projects> | |||
| </projects> | |||
| <buildSpec> | |||
| <buildCommand> | |||
| <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> | |||
| <triggers>clean,full,incremental,</triggers> | |||
| <arguments> | |||
| </arguments> | |||
| </buildCommand> | |||
| <buildCommand> | |||
| <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> | |||
| <triggers>full,incremental,</triggers> | |||
| <arguments> | |||
| </arguments> | |||
| </buildCommand> | |||
| </buildSpec> | |||
| <natures> | |||
| <nature>org.eclipse.cdt.core.cnature</nature> | |||
| <nature>org.eclipse.cdt.core.ccnature</nature> | |||
| <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> | |||
| <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> | |||
| </natures> | |||
| </projectDescription> | |||
| @@ -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__ */ | |||
| @@ -0,0 +1,940 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004 Grame | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #define __STDC_FORMAT_MACROS // For inttypes.h to work in C++ | |||
| #include <iostream> | |||
| #include <math.h> | |||
| #include <stdio.h> | |||
| #include <memory.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <errno.h> | |||
| #include <stdarg.h> | |||
| #include <signal.h> | |||
| #include <sys/types.h> | |||
| #include <sys/time.h> | |||
| #include <string.h> | |||
| #include "JackIoAudioDriver.h" | |||
| #include "JackEngineControl.h" | |||
| #include "JackClientControl.h" | |||
| #include "JackPort.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackLockedEngine.h" | |||
| #ifdef __ANDROID__ | |||
| #include "JackAndroidThread.h" | |||
| #else | |||
| #include "JackPosixThread.h" | |||
| #endif | |||
| #include "JackCompilerDeps.h" | |||
| #include "JackServerGlobals.h" | |||
| static struct jack_constraint_enum_str_descriptor midi_constraint_descr_array[] = | |||
| { | |||
| { "none", "no MIDI driver" }, | |||
| { "seq", "IoAudio Sequencer driver" }, | |||
| { "raw", "IoAudio RawMIDI driver" }, | |||
| { 0 } | |||
| }; | |||
| static struct jack_constraint_enum_char_descriptor dither_constraint_descr_array[] = | |||
| { | |||
| { 'n', "none" }, | |||
| { 'r', "rectangular" }, | |||
| { 's', "shaped" }, | |||
| { 't', "triangular" }, | |||
| { 0 } | |||
| }; | |||
| namespace Jack | |||
| { | |||
| int JackIoAudioDriver::SetBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| jack_log("JackIoAudioDriver::SetBufferSize %ld", buffer_size); | |||
| int res = ioaudio_driver_reset_parameters((ioaudio_driver_t *)fDriver, buffer_size, | |||
| ((ioaudio_driver_t *)fDriver)->user_nperiods, | |||
| ((ioaudio_driver_t *)fDriver)->frame_rate); | |||
| if (res == 0) { // update fEngineControl and fGraphManager | |||
| JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails | |||
| // IoAudio specific | |||
| UpdateLatencies(); | |||
| } else { | |||
| // Restore old values | |||
| ioaudio_driver_reset_parameters((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize, | |||
| ((ioaudio_driver_t *)fDriver)->user_nperiods, | |||
| ((ioaudio_driver_t *)fDriver)->frame_rate); | |||
| } | |||
| return res; | |||
| } | |||
| void JackIoAudioDriver::UpdateLatencies() | |||
| { | |||
| jack_latency_range_t range; | |||
| ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| range.min = range.max = ioaudio_driver->frames_per_cycle + ioaudio_driver->capture_frame_latency; | |||
| fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range); | |||
| } | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| // Add one buffer more latency if "async" mode is used... | |||
| range.min = range.max = (ioaudio_driver->frames_per_cycle * (ioaudio_driver->user_nperiods - 1)) + | |||
| ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + ioaudio_driver->playback_frame_latency; | |||
| fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range); | |||
| // Monitor port | |||
| if (fWithMonitorPorts) { | |||
| range.min = range.max = ioaudio_driver->frames_per_cycle; | |||
| fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range); | |||
| } | |||
| } | |||
| } | |||
| int JackIoAudioDriver::Attach() | |||
| { | |||
| JackPort* port; | |||
| jack_port_id_t port_index; | |||
| unsigned long port_flags = (unsigned long)CaptureDriverFlags; | |||
| char name[REAL_JACK_PORT_NAME_SIZE]; | |||
| char alias[REAL_JACK_PORT_NAME_SIZE]; | |||
| assert(fCaptureChannels < DRIVER_PORT_NUM); | |||
| assert(fPlaybackChannels < DRIVER_PORT_NUM); | |||
| ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; | |||
| if (ioaudio_driver->has_hw_monitoring) | |||
| port_flags |= JackPortCanMonitor; | |||
| // IoAudio driver may have changed the values | |||
| JackAudioDriver::SetBufferSize(ioaudio_driver->frames_per_cycle); | |||
| JackAudioDriver::SetSampleRate(ioaudio_driver->frame_rate); | |||
| jack_log("JackIoAudioDriver::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) { | |||
| jack_error("driver: cannot register port for %s", name); | |||
| return -1; | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| fCapturePortList[i] = port_index; | |||
| jack_log("JackIoAudioDriver::Attach fCapturePortList[i] %ld ", port_index); | |||
| } | |||
| 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("JackIoAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index); | |||
| // 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("IoAudio: cannot register monitor port for %s", name); | |||
| } else { | |||
| fMonitorPortList[i] = port_index; | |||
| } | |||
| } | |||
| } | |||
| UpdateLatencies(); | |||
| // if (ioaudio_driver->midi) { | |||
| // int err = (ioaudio_driver->midi->attach)(ioaudio_driver->midi); | |||
| // if (err) | |||
| // jack_error ("IoAudio: cannot attach MIDI: %d", err); | |||
| // } | |||
| return 0; | |||
| } | |||
| int JackIoAudioDriver::Detach() | |||
| { | |||
| ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; | |||
| // if (ioaudio_driver->midi) | |||
| // (ioaudio_driver->midi->detach)(ioaudio_driver->midi); | |||
| return JackAudioDriver::Detach(); | |||
| } | |||
| extern "C" char* get_control_device_name(const char * device_name) | |||
| { | |||
| char * ctl_name; | |||
| const char * comma; | |||
| /* the user wants a hw or plughw device, the ctl name | |||
| * should be hw:x where x is the card identification. | |||
| * We skip the subdevice suffix that starts with comma */ | |||
| if (strncasecmp(device_name, "plughw:", 7) == 0) { | |||
| /* skip the "plug" prefix" */ | |||
| device_name += 4; | |||
| } | |||
| comma = strchr(device_name, ','); | |||
| if (comma == NULL) { | |||
| ctl_name = strdup(device_name); | |||
| if (ctl_name == NULL) { | |||
| jack_error("strdup(\"%s\") failed.", device_name); | |||
| } | |||
| } else { | |||
| // ctl_name = strndup(device_name, comma - device_name); | |||
| ctl_name = strdup(device_name); | |||
| if (ctl_name == NULL) { | |||
| jack_error("strdup(\"%s\", %u) failed.", device_name, (unsigned int)(comma - device_name)); | |||
| } | |||
| ctl_name[comma - device_name] = '\0'; | |||
| } | |||
| return ctl_name; | |||
| } | |||
| static int card_to_num(const char* device) | |||
| { | |||
| int err; | |||
| char* ctl_name; | |||
| snd_ctl_card_info_t *card_info; | |||
| snd_ctl_t* ctl_handle; | |||
| int i = -1; | |||
| snd_ctl_card_info_alloca (&card_info); | |||
| ctl_name = get_control_device_name(device); | |||
| if (ctl_name == NULL) { | |||
| jack_error("get_control_device_name() failed."); | |||
| goto fail; | |||
| } | |||
| if ((err = snd_ctl_open (&ctl_handle, ctl_name, 0)) < 0) { | |||
| jack_error ("control open \"%s\" (%s)", ctl_name, | |||
| snd_strerror(err)); | |||
| goto free; | |||
| } | |||
| if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) { | |||
| jack_error ("control hardware info \"%s\" (%s)", | |||
| device, snd_strerror (err)); | |||
| goto close; | |||
| } | |||
| i = snd_ctl_card_info_get_card(card_info); | |||
| close: | |||
| snd_ctl_close(ctl_handle); | |||
| free: | |||
| free(ctl_name); | |||
| fail: | |||
| return i; | |||
| } | |||
| int JackIoAudioDriver::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 */ | |||
| ) | |||
| { | |||
| // Generic JackAudioDriver Open | |||
| if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, | |||
| inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, | |||
| capture_latency, playback_latency) != 0) { | |||
| return -1; | |||
| } | |||
| // ioaudio_midi_t *midi = 0; | |||
| //#ifndef __ANDROID__ | |||
| // if (strcmp(midi_driver_name, "seq") == 0) | |||
| // midi = ioaudio_seqmidi_new((jack_client_t*)this, 0); | |||
| // else if (strcmp(midi_driver_name, "raw") == 0) | |||
| // midi = ioaudio_rawmidi_new((jack_client_t*)this); | |||
| //#endif | |||
| if (JackServerGlobals::on_device_acquire != NULL) { | |||
| int capture_card = card_to_num(capture_driver_name); | |||
| int playback_card = card_to_num(playback_driver_name); | |||
| char audio_name[32]; | |||
| if (capture_card >= 0) { | |||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | |||
| jack_error("Audio device %s cannot be acquired...", capture_driver_name); | |||
| return -1; | |||
| } | |||
| } | |||
| if (playback_card >= 0 && playback_card != capture_card) { | |||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | |||
| if (!JackServerGlobals::on_device_acquire(audio_name)) { | |||
| jack_error("Audio device %s cannot be acquired...", playback_driver_name); | |||
| if (capture_card >= 0) { | |||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||
| JackServerGlobals::on_device_release(audio_name); | |||
| } | |||
| return -1; | |||
| } | |||
| } | |||
| } | |||
| fDriver = ioaudio_driver_new ((char*)"ioaudio_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) { | |||
| // IoAudio driver may have changed the in/out values | |||
| fCaptureChannels = ((ioaudio_driver_t *)fDriver)->capture_nchannels; | |||
| fPlaybackChannels = ((ioaudio_driver_t *)fDriver)->playback_nchannels; | |||
| return 0; | |||
| } else { | |||
| JackAudioDriver::Close(); | |||
| return -1; | |||
| } | |||
| } | |||
| int JackIoAudioDriver::Close() | |||
| { | |||
| // Generic audio driver close | |||
| int res = JackAudioDriver::Close(); | |||
| ioaudio_driver_delete((ioaudio_driver_t*)fDriver); | |||
| if (JackServerGlobals::on_device_release != NULL) | |||
| { | |||
| char audio_name[32]; | |||
| int capture_card = card_to_num(fCaptureDriverName); | |||
| if (capture_card >= 0) { | |||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card); | |||
| JackServerGlobals::on_device_release(audio_name); | |||
| } | |||
| int playback_card = card_to_num(fPlaybackDriverName); | |||
| if (playback_card >= 0 && playback_card != capture_card) { | |||
| snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card); | |||
| JackServerGlobals::on_device_release(audio_name); | |||
| } | |||
| } | |||
| return res; | |||
| } | |||
| int JackIoAudioDriver::Start() | |||
| { | |||
| int res = JackAudioDriver::Start(); | |||
| if (res >= 0) { | |||
| res = ioaudio_driver_start((ioaudio_driver_t *)fDriver); | |||
| if (res < 0) { | |||
| JackAudioDriver::Stop(); | |||
| } | |||
| } | |||
| return res; | |||
| } | |||
| int JackIoAudioDriver::Stop() | |||
| { | |||
| int res = ioaudio_driver_stop((ioaudio_driver_t *)fDriver); | |||
| if (JackAudioDriver::Stop() < 0) { | |||
| res = -1; | |||
| } | |||
| return res; | |||
| } | |||
| int JackIoAudioDriver::Read() | |||
| { | |||
| /* Taken from ioaudio_driver_run_cycle */ | |||
| int wait_status; | |||
| jack_nframes_t nframes; | |||
| fDelayedUsecs = 0.f; | |||
| retry: | |||
| nframes = ioaudio_driver_wait((ioaudio_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); | |||
| if (wait_status < 0) | |||
| return -1; /* driver failed */ | |||
| if (nframes == 0) { | |||
| /* we detected an xrun and restarted: notify | |||
| * clients about the delay. | |||
| */ | |||
| jack_log("IoAudio XRun wait_status = %d", wait_status); | |||
| NotifyXRun(fBeginDateUst, fDelayedUsecs); | |||
| goto retry; /* recoverable error*/ | |||
| } | |||
| if (nframes != fEngineControl->fBufferSize) | |||
| jack_log("JackIoAudioDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes); | |||
| // Has to be done before read | |||
| JackDriver::CycleIncTime(); | |||
| return ioaudio_driver_read((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize); | |||
| } | |||
| int JackIoAudioDriver::Write() | |||
| { | |||
| return ioaudio_driver_write((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize); | |||
| } | |||
| void JackIoAudioDriver::ReadInputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_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); | |||
| ioaudio_driver_read_from_channel((ioaudio_driver_t *)fDriver, chn, buf + nread, contiguous); | |||
| } | |||
| } | |||
| } | |||
| void JackIoAudioDriver::MonitorInputAux() | |||
| { | |||
| for (int chn = 0; chn < fCaptureChannels; chn++) { | |||
| JackPort* port = fGraphManager->GetPort(fCapturePortList[chn]); | |||
| if (port->MonitoringInput()) { | |||
| ((ioaudio_driver_t *)fDriver)->input_monitor_mask |= (1 << chn); | |||
| } | |||
| } | |||
| } | |||
| void JackIoAudioDriver::ClearOutputAux() | |||
| { | |||
| for (int chn = 0; chn < fPlaybackChannels; chn++) { | |||
| jack_default_audio_sample_t* buf = | |||
| (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], fEngineControl->fBufferSize); | |||
| memset(buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize); | |||
| } | |||
| } | |||
| void JackIoAudioDriver::SetTimetAux(jack_time_t time) | |||
| { | |||
| fBeginDateUst = time; | |||
| } | |||
| void JackIoAudioDriver::WriteOutputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten) | |||
| { | |||
| for (int chn = 0; chn < fPlaybackChannels; chn++) { | |||
| // Output ports | |||
| if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) { | |||
| jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes); | |||
| ioaudio_driver_write_to_channel(((ioaudio_driver_t *)fDriver), chn, buf + nwritten, contiguous); | |||
| // Monitor ports | |||
| if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) { | |||
| jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes); | |||
| memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| int JackIoAudioDriver::is_realtime() const | |||
| { | |||
| return fEngineControl->fRealTime; | |||
| } | |||
| int JackIoAudioDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg) | |||
| { | |||
| #ifdef __ANDROID__ | |||
| return JackAndroidThread::StartImp(thread, priority, realtime, start_routine, arg); | |||
| #else | |||
| return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg); | |||
| #endif | |||
| } | |||
| jack_port_id_t JackIoAudioDriver::port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) | |||
| { | |||
| jack_port_id_t port_index; | |||
| int res = fEngine->PortRegister(fClientControl.fRefNum, port_name, port_type, flags, buffer_size, &port_index); | |||
| return (res == 0) ? port_index : 0; | |||
| } | |||
| int JackIoAudioDriver::port_unregister(jack_port_id_t port_index) | |||
| { | |||
| return fEngine->PortUnRegister(fClientControl.fRefNum, port_index); | |||
| } | |||
| void* JackIoAudioDriver::port_get_buffer(int port, jack_nframes_t nframes) | |||
| { | |||
| return fGraphManager->GetBuffer(port, nframes); | |||
| } | |||
| int JackIoAudioDriver::port_set_alias(int port, const char* name) | |||
| { | |||
| return fGraphManager->GetPort(port)->SetAlias(name); | |||
| } | |||
| jack_nframes_t JackIoAudioDriver::get_sample_rate() const | |||
| { | |||
| return fEngineControl->fSampleRate; | |||
| } | |||
| jack_nframes_t JackIoAudioDriver::frame_time() const | |||
| { | |||
| JackTimer timer; | |||
| fEngineControl->ReadFrameTime(&timer); | |||
| return timer.Time2Frames(GetMicroSeconds(), fEngineControl->fBufferSize); | |||
| } | |||
| jack_nframes_t JackIoAudioDriver::last_frame_time() const | |||
| { | |||
| JackTimer timer; | |||
| fEngineControl->ReadFrameTime(&timer); | |||
| return timer.CurFrame(); | |||
| } | |||
| } // end of namespace | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| static | |||
| jack_driver_param_constraint_desc_t * | |||
| enum_ioaudio_devices() | |||
| { | |||
| snd_ctl_t * handle; | |||
| snd_ctl_hw_info_t info; | |||
| snd_pcm_info_t pcminfo_capture; | |||
| snd_pcm_info_t pcminfo_playback; | |||
| int card_no = -1; | |||
| jack_driver_param_value_t card_id; | |||
| jack_driver_param_value_t device_id; | |||
| char description[64]; | |||
| int device_no; | |||
| bool has_capture; | |||
| bool has_playback; | |||
| jack_driver_param_constraint_desc_t * constraint_ptr; | |||
| uint32_t array_size = 0; | |||
| constraint_ptr = NULL; | |||
| int numcards = snd_cards_list( NULL, 0, NULL ); | |||
| int* cards = malloc( numcards * sizeof(int) ); | |||
| numcards = snd_cards_list( cards, numcards, NULL ); | |||
| for( int c = 0; c < numcards; ++c ) | |||
| { | |||
| card_no = cards[c]; | |||
| snprintf(card_id.str, sizeof(card_id.str), "hw:%d", card_no); | |||
| if (snd_ctl_open(&handle, card_no) >= 0 && | |||
| snd_ctl_hw_info(handle, &info) >= 0) | |||
| { | |||
| snprintf(card_id.str, sizeof(card_id.str), "hw:%s", snd_ctl_card_info_get_id(info)); | |||
| if (!jack_constraint_add_enum( | |||
| &constraint_ptr, | |||
| &array_size, | |||
| &card_id, | |||
| snd_ctl_card_info_get_name(info))) | |||
| goto fail; | |||
| device_no = -1; | |||
| for( device_no = 0; device_no < info.pcmdevs; ++device_no ) | |||
| { | |||
| snprintf(device_id.str, sizeof(device_id.str), "%s,%d", card_id.str, device_no); | |||
| snd_pcm_info_set_device(pcminfo_capture, device_no); | |||
| snd_pcm_info_set_subdevice(pcminfo_capture, 0); | |||
| snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_CHANNEL_CAPTURE); | |||
| has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0; | |||
| snd_pcm_info_set_device(pcminfo_playback, device_no); | |||
| snd_pcm_info_set_subdevice(pcminfo_playback, 0); | |||
| snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_CHANNEL_PLAYBACK); | |||
| has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0; | |||
| if (has_capture && has_playback) | |||
| { | |||
| snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture)); | |||
| } | |||
| else if (has_capture) | |||
| { | |||
| snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture)); | |||
| } | |||
| else if (has_playback) | |||
| { | |||
| snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback)); | |||
| } | |||
| else | |||
| { | |||
| continue; | |||
| } | |||
| if (!jack_constraint_add_enum( | |||
| &constraint_ptr, | |||
| &array_size, | |||
| &device_id, | |||
| description)) | |||
| goto fail; | |||
| } | |||
| snd_ctl_close(handle); | |||
| } | |||
| } | |||
| return constraint_ptr; | |||
| fail: | |||
| jack_constraint_free(constraint_ptr); | |||
| return NULL; | |||
| } | |||
| static int | |||
| dither_opt (char c, DitherAlgorithm* dither) | |||
| { | |||
| switch (c) { | |||
| case '-': | |||
| case 'n': | |||
| *dither = None; | |||
| break; | |||
| case 'r': | |||
| *dither = Rectangular; | |||
| break; | |||
| case 's': | |||
| *dither = Shaped; | |||
| break; | |||
| case 't': | |||
| *dither = Triangular; | |||
| break; | |||
| default: | |||
| fprintf (stderr, "IoAudio driver: illegal dithering mode %c\n", c); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
| { | |||
| jack_driver_desc_t * desc; | |||
| jack_driver_desc_filler_t filler; | |||
| jack_driver_param_value_t value; | |||
| desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "QNX IoAudio API based audio backend", &filler); | |||
| strcpy(value.str, "pcmPreferredp"); | |||
| #ifdef __ANDROID__ | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "IoAudio device name", NULL); | |||
| #else | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_ioaudio_devices(), "IoAudio device name", NULL); | |||
| #endif | |||
| 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, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set device", NULL); | |||
| value.ui = 48000U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); | |||
| value.ui = 1024U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); | |||
| value.ui = 2U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "hwmon", 'H', JackDriverParamBool, &value, NULL, "Hardware monitoring, if available", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "hwmeter", 'M', JackDriverParamBool, &value, NULL, "Hardware metering, if available", NULL); | |||
| value.i = 1; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "softmode", 's', JackDriverParamBool, &value, NULL, "Soft-mode, no xrun handling", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL); | |||
| value.c = 'n'; | |||
| jack_driver_descriptor_add_parameter( | |||
| desc, | |||
| &filler, | |||
| "dither", | |||
| 'z', | |||
| JackDriverParamChar, | |||
| &value, | |||
| jack_constraint_compose_enum_char( | |||
| JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE, | |||
| dither_constraint_descr_array), | |||
| "Dithering mode", | |||
| 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); | |||
| value.i = FALSE; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL); | |||
| value.ui = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL); | |||
| strcpy(value.str, "none"); | |||
| jack_driver_descriptor_add_parameter( | |||
| desc, | |||
| &filler, | |||
| "midi-driver", | |||
| 'X', | |||
| JackDriverParamString, | |||
| &value, | |||
| jack_constraint_compose_enum_str( | |||
| JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE, | |||
| midi_constraint_descr_array), | |||
| "IoAudio MIDI driver", | |||
| NULL); | |||
| return desc; | |||
| } | |||
| static Jack::JackIoAudioDriver* g_ioaudio_driver; | |||
| 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 = "pcmPreferredp"; | |||
| const char *capture_pcm_name = "pcmPreferredc"; | |||
| 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 jack_driver_param_t * param; | |||
| const char *midi_driver = "none"; | |||
| for (node = params; node; node = jack_slist_next (node)) { | |||
| param = (const jack_driver_param_t *) node->data; | |||
| switch (param->character) { | |||
| case 'C': | |||
| capture = TRUE; | |||
| if (strcmp (param->value.str, "none") != 0) { | |||
| capture_pcm_name = strdup (param->value.str); | |||
| jack_log("capture device %s", capture_pcm_name); | |||
| } | |||
| break; | |||
| case 'P': | |||
| playback = TRUE; | |||
| if (strcmp (param->value.str, "none") != 0) { | |||
| playback_pcm_name = strdup (param->value.str); | |||
| jack_log("playback device %s", playback_pcm_name); | |||
| } | |||
| break; | |||
| case 'D': | |||
| playback = TRUE; | |||
| capture = TRUE; | |||
| break; | |||
| case 'd': | |||
| 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); | |||
| } | |||
| break; | |||
| case 'H': | |||
| hw_monitoring = param->value.i; | |||
| break; | |||
| case 'm': | |||
| monitor = param->value.i; | |||
| break; | |||
| case 'M': | |||
| hw_metering = param->value.i; | |||
| break; | |||
| case 'r': | |||
| srate = param->value.ui; | |||
| jack_log("apparent rate = %d", srate); | |||
| break; | |||
| case 'p': | |||
| frames_per_interrupt = param->value.ui; | |||
| jack_log("frames per period = %d", frames_per_interrupt); | |||
| break; | |||
| case 'n': | |||
| user_nperiods = param->value.ui; | |||
| if (user_nperiods < 2) { /* enforce minimum value */ | |||
| user_nperiods = 2; | |||
| } | |||
| break; | |||
| case 's': | |||
| soft_mode = param->value.i; | |||
| break; | |||
| case 'z': | |||
| if (dither_opt (param->value.c, &dither)) { | |||
| return NULL; | |||
| } | |||
| break; | |||
| case 'i': | |||
| user_capture_nchnls = param->value.ui; | |||
| break; | |||
| case 'o': | |||
| user_playback_nchnls = param->value.ui; | |||
| break; | |||
| case 'S': | |||
| shorts_first = param->value.i; | |||
| break; | |||
| case 'I': | |||
| systemic_input_latency = param->value.ui; | |||
| break; | |||
| case 'O': | |||
| systemic_output_latency = param->value.ui; | |||
| break; | |||
| case 'X': | |||
| midi_driver = strdup(param->value.str); | |||
| break; | |||
| } | |||
| } | |||
| /* duplex is the default */ | |||
| if (!capture && !playback) { | |||
| capture = TRUE; | |||
| playback = TRUE; | |||
| } | |||
| g_ioaudio_driver = new Jack::JackIoAudioDriver("system", "ioaudio_pcm", engine, table); | |||
| Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_ioaudio_driver); | |||
| // Special open for IoAudio driver... | |||
| if (g_ioaudio_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor, | |||
| user_capture_nchnls, user_playback_nchnls, shorts_first, capture_pcm_name, playback_pcm_name, | |||
| systemic_input_latency, systemic_output_latency, midi_driver ) == 0) { | |||
| return threaded_driver; | |||
| } else { | |||
| delete threaded_driver; // Delete the decorated driver | |||
| return NULL; | |||
| } | |||
| } | |||
| // Code to be used in ioaudio_driver.c | |||
| void ReadInput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread) | |||
| { | |||
| g_ioaudio_driver->ReadInputAux(orig_nframes, contiguous, nread); | |||
| } | |||
| void MonitorInput() | |||
| { | |||
| g_ioaudio_driver->MonitorInputAux(); | |||
| } | |||
| void ClearOutput() | |||
| { | |||
| g_ioaudio_driver->ClearOutputAux(); | |||
| } | |||
| void WriteOutput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten) | |||
| { | |||
| g_ioaudio_driver->WriteOutputAux(orig_nframes, contiguous, nwritten); | |||
| } | |||
| void SetTime(jack_time_t time) | |||
| { | |||
| g_ioaudio_driver->SetTimetAux(time); | |||
| } | |||
| int Restart() | |||
| { | |||
| int res; | |||
| if ((res = g_ioaudio_driver->Stop()) == 0) { | |||
| res = g_ioaudio_driver->Start(); | |||
| } | |||
| return res; | |||
| } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,112 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004 Grame | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (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. | |||
| */ | |||
| #ifndef __JackIoAudioDriver__ | |||
| #define __JackIoAudioDriver__ | |||
| #include "JackAudioDriver.h" | |||
| #include "JackThreadedDriver.h" | |||
| #include "JackTime.h" | |||
| #include "ioaudio_backend.h" | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief The IoAudio driver. | |||
| */ | |||
| class JackIoAudioDriver : public JackAudioDriver | |||
| { | |||
| private: | |||
| jack_driver_t* fDriver; | |||
| void UpdateLatencies(); | |||
| public: | |||
| JackIoAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | |||
| : JackAudioDriver(name, alias, engine, table),fDriver(NULL) | |||
| {} | |||
| virtual ~JackIoAudioDriver() | |||
| {} | |||
| 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 Close(); | |||
| int Attach(); | |||
| int Detach(); | |||
| int Start(); | |||
| int Stop(); | |||
| int Read(); | |||
| int Write(); | |||
| // BufferSize can be changed | |||
| bool IsFixedBufferSize() | |||
| { | |||
| return false; | |||
| } | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| void ReadInputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread); | |||
| void MonitorInputAux(); | |||
| void ClearOutputAux(); | |||
| void WriteOutputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten); | |||
| void SetTimetAux(jack_time_t time); | |||
| // JACK API emulation for the midi driver | |||
| int is_realtime() const; | |||
| int create_thread(pthread_t *thread, int prio, int rt, void *(*start_func)(void*), void *arg); | |||
| jack_port_id_t port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size); | |||
| int port_unregister(jack_port_id_t port_index); | |||
| void* port_get_buffer(int port, jack_nframes_t nframes); | |||
| int port_set_alias(int port, const char* name); | |||
| jack_nframes_t get_sample_rate() const; | |||
| jack_nframes_t frame_time() const; | |||
| jack_nframes_t last_frame_time() const; | |||
| }; | |||
| } // end of namespace | |||
| #endif | |||
| @@ -0,0 +1,132 @@ | |||
| /* | |||
| * bitset.h -- some simple bit vector set operations. | |||
| * | |||
| * This is useful for sets of small non-negative integers. There are | |||
| * some obvious set operations that are not implemented because I | |||
| * don't need them right now. | |||
| * | |||
| * These functions represent sets as arrays of unsigned 32-bit | |||
| * integers allocated on the heap. The first entry contains the set | |||
| * cardinality (number of elements allowed), followed by one or more | |||
| * words containing bit vectors. | |||
| * | |||
| * $Id: bitset.h,v 1.2 2005/11/23 11:24:29 letz Exp $ | |||
| */ | |||
| /* | |||
| * Copyright (C) 2005 Jack O'Quin | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef __bitset_h__ | |||
| #define __bitset_h__ | |||
| #include <inttypes.h> /* POSIX standard fixed-size types */ | |||
| #include <assert.h> /* `#define NDEBUG' to disable */ | |||
| /* On some 64-bit machines, this implementation may be slightly | |||
| * inefficient, depending on how compilers allocate space for | |||
| * uint32_t. For the set sizes I currently need, this is acceptable. | |||
| * It should not be hard to pack the bits better, if that becomes | |||
| * worthwhile. | |||
| */ | |||
| typedef uint32_t _bitset_word_t; | |||
| typedef _bitset_word_t *bitset_t; | |||
| #define WORD_SIZE(cardinality) (1+((cardinality)+31)/32) | |||
| #define BYTE_SIZE(cardinality) (WORD_SIZE(cardinality)*sizeof(_bitset_word_t)) | |||
| #define WORD_INDEX(element) (1+(element)/32) | |||
| #define BIT_INDEX(element) ((element)&037) | |||
| static inline void | |||
| bitset_add(bitset_t set | |||
| , unsigned int element) | |||
| { | |||
| assert(element < set | |||
| [0]); | |||
| set | |||
| [WORD_INDEX(element)] |= (1 << BIT_INDEX(element)); | |||
| } | |||
| static inline void | |||
| bitset_copy(bitset_t to_set, bitset_t from_set) | |||
| { | |||
| assert(to_set[0] == from_set[0]); | |||
| memcpy(to_set, from_set, BYTE_SIZE(to_set[0])); | |||
| } | |||
| static inline void | |||
| bitset_create(bitset_t *set | |||
| , unsigned int cardinality) | |||
| { | |||
| *set | |||
| = (bitset_t) calloc(WORD_SIZE(cardinality), | |||
| sizeof(_bitset_word_t)); | |||
| assert(*set | |||
| ); | |||
| *set | |||
| [0] = cardinality; | |||
| } | |||
| static inline void | |||
| bitset_destroy(bitset_t *set | |||
| ) | |||
| { | |||
| if (*set | |||
| ) { | |||
| free(*set | |||
| ); | |||
| *set | |||
| = (bitset_t) 0; | |||
| } | |||
| } | |||
| static inline int | |||
| bitset_empty(bitset_t set | |||
| ) | |||
| { | |||
| int i; | |||
| _bitset_word_t result = 0; | |||
| int nwords = WORD_SIZE(set | |||
| [0]); | |||
| for (i = 1; i < nwords; i++) { | |||
| result |= set | |||
| [i]; | |||
| } | |||
| return (result == 0); | |||
| } | |||
| static inline int | |||
| bitset_contains(bitset_t set | |||
| , unsigned int element) | |||
| { | |||
| assert(element < set | |||
| [0]); | |||
| return (0 != (set | |||
| [WORD_INDEX(element)] & (1 << BIT_INDEX(element)))); | |||
| } | |||
| static inline void | |||
| bitset_remove(bitset_t set | |||
| , unsigned int element) | |||
| { | |||
| assert(element < set | |||
| [0]); | |||
| set | |||
| [WORD_INDEX(element)] &= ~(1 << BIT_INDEX(element)); | |||
| } | |||
| #endif /* __bitset_h__ */ | |||
| @@ -0,0 +1,295 @@ | |||
| /* | |||
| 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: ioaudio_driver.h 945 2006-05-04 15:14:45Z pbd $ | |||
| */ | |||
| #ifndef __jack_ioaudio_driver_h__ | |||
| #define __jack_ioaudio_driver_h__ | |||
| #include <sys/asoundlib.h> | |||
| #include "bitset.h" | |||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | |||
| #define IS_LE 0 | |||
| #define IS_BE 1 | |||
| #elif __BYTE_ORDER == __BIG_ENDIAN | |||
| #define IS_LE 1 | |||
| #define IS_BE 0 | |||
| #endif | |||
| #define TRUE 1 | |||
| #define FALSE 0 | |||
| #include "types.h" | |||
| //#include "hardware.h" | |||
| #include "driver.h" | |||
| #include "memops.h" | |||
| //#include "ioaudio_midi.h" | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| typedef void (*ReadCopyFunction) (jack_default_audio_sample_t *dst, char *src, | |||
| unsigned long src_bytes, | |||
| unsigned long src_skip_bytes); | |||
| typedef void (*WriteCopyFunction) (char *dst, jack_default_audio_sample_t *src, | |||
| unsigned long src_bytes, | |||
| unsigned long dst_skip_bytes, | |||
| dither_state_t *state); | |||
| typedef struct _snd_pcm_channel_area { | |||
| void *addr; | |||
| unsigned int first; | |||
| unsigned int step; | |||
| } snd_pcm_channel_area_t; | |||
| typedef struct _ioaudio_driver { | |||
| JACK_DRIVER_NT_DECL | |||
| int poll_timeout; | |||
| jack_time_t poll_last; | |||
| 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; | |||
| unsigned int playback_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 capture_nchannels; | |||
| unsigned long playback_sample_bytes; | |||
| unsigned long capture_sample_bytes; | |||
| jack_nframes_t frame_rate; | |||
| jack_nframes_t frames_per_cycle; | |||
| jack_nframes_t capture_frame_latency; | |||
| jack_nframes_t playback_frame_latency; | |||
| unsigned long *silent; | |||
| char *ioaudio_name_playback; | |||
| char *ioaudio_name_capture; | |||
| char *ioaudio_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 int playback_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_channel_params_t *playback_hw_params; | |||
| snd_pcm_channel_params_t *playback_sw_params; | |||
| snd_pcm_channel_params_t *capture_hw_params; | |||
| snd_pcm_channel_params_t *capture_sw_params; | |||
| jack_hardware_t *hw; | |||
| ClockSyncStatus *clock_sync_data; | |||
| jack_client_t *client; | |||
| JSList *capture_ports; | |||
| JSList *playback_ports; | |||
| JSList *monitor_ports; | |||
| unsigned long input_monitor_mask; | |||
| char soft_mode; | |||
| char hw_monitoring; | |||
| char hw_metering; | |||
| char all_monitor_in; | |||
| char capture_and_playback_not_synced; | |||
| char playback_interleaved; | |||
| char capture_interleaved; | |||
| char with_monitor_ports; | |||
| char has_clock_sync_reporting; | |||
| char has_hw_monitoring; | |||
| char has_hw_metering; | |||
| char quirk_bswap; | |||
| ReadCopyFunction read_via_copy; | |||
| WriteCopyFunction write_via_copy; | |||
| int dither; | |||
| dither_state_t *dither_state; | |||
| 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 xrun_count; | |||
| int process_count; | |||
| // ioaudio_midi_t *midi; | |||
| char *midi; | |||
| int xrun_recovery; | |||
| } ioaudio_driver_t; | |||
| static inline void | |||
| ioaudio_driver_mark_channel_done (ioaudio_driver_t *driver, channel_t chn) { | |||
| bitset_remove (driver->channels_not_done, chn); | |||
| driver->silent[chn] = 0; | |||
| } | |||
| static inline void | |||
| ioaudio_driver_silence_on_channel (ioaudio_driver_t *driver, channel_t chn, | |||
| jack_nframes_t nframes) { | |||
| if (driver->playback_interleaved) { | |||
| memset_interleave | |||
| (driver->playback_addr[chn], | |||
| 0, nframes * driver->playback_sample_bytes, | |||
| driver->interleave_unit, | |||
| driver->playback_interleave_skip[chn]); | |||
| } else { | |||
| memset (driver->playback_addr[chn], 0, | |||
| nframes * driver->playback_sample_bytes); | |||
| } | |||
| ioaudio_driver_mark_channel_done (driver,chn); | |||
| } | |||
| static inline void | |||
| ioaudio_driver_silence_on_channel_no_mark (ioaudio_driver_t *driver, channel_t chn, | |||
| jack_nframes_t nframes) { | |||
| if (driver->playback_interleaved) { | |||
| memset_interleave | |||
| (driver->playback_addr[chn], | |||
| 0, nframes * driver->playback_sample_bytes, | |||
| driver->interleave_unit, | |||
| driver->playback_interleave_skip[chn]); | |||
| } else { | |||
| memset (driver->playback_addr[chn], 0, | |||
| nframes * driver->playback_sample_bytes); | |||
| } | |||
| } | |||
| static inline void | |||
| ioaudio_driver_read_from_channel (ioaudio_driver_t *driver, | |||
| channel_t channel, | |||
| jack_default_audio_sample_t *buf, | |||
| jack_nframes_t nsamples) | |||
| { | |||
| driver->read_via_copy (buf, | |||
| driver->capture_addr[channel], | |||
| nsamples, | |||
| driver->capture_interleave_skip[channel]); | |||
| } | |||
| static inline void | |||
| ioaudio_driver_write_to_channel (ioaudio_driver_t *driver, | |||
| channel_t channel, | |||
| jack_default_audio_sample_t *buf, | |||
| jack_nframes_t nsamples) | |||
| { | |||
| driver->write_via_copy (driver->playback_addr[channel], | |||
| buf, | |||
| nsamples, | |||
| driver->playback_interleave_skip[channel], | |||
| driver->dither_state+channel); | |||
| ioaudio_driver_mark_channel_done (driver, channel); | |||
| } | |||
| void ioaudio_driver_silence_untouched_channels (ioaudio_driver_t *driver, | |||
| jack_nframes_t nframes); | |||
| void ioaudio_driver_set_clock_sync_status (ioaudio_driver_t *driver, channel_t chn, | |||
| ClockSyncStatus status); | |||
| int ioaudio_driver_listen_for_clock_sync_status (ioaudio_driver_t *, | |||
| ClockSyncListenerFunction, | |||
| void *arg); | |||
| int ioaudio_driver_stop_listen_for_clock_sync_status (ioaudio_driver_t *, | |||
| unsigned int); | |||
| void ioaudio_driver_clock_sync_notify (ioaudio_driver_t *, channel_t chn, | |||
| ClockSyncStatus); | |||
| int | |||
| ioaudio_driver_reset_parameters (ioaudio_driver_t *driver, | |||
| jack_nframes_t frames_per_cycle, | |||
| jack_nframes_t user_nperiods, | |||
| jack_nframes_t rate); | |||
| jack_driver_t * | |||
| ioaudio_driver_new (char *name, char *playback_ioaudio_device, | |||
| char *capture_ioaudio_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 /*, | |||
| ioaudio_midi_t *midi_driver */ | |||
| ); | |||
| void | |||
| ioaudio_driver_delete (ioaudio_driver_t *driver); | |||
| int | |||
| ioaudio_driver_start (ioaudio_driver_t *driver); | |||
| int | |||
| ioaudio_driver_stop (ioaudio_driver_t *driver); | |||
| jack_nframes_t | |||
| ioaudio_driver_wait (ioaudio_driver_t *driver, int extra_fd, int *status, float | |||
| *delayed_usecs); | |||
| int | |||
| ioaudio_driver_read (ioaudio_driver_t *driver, jack_nframes_t nframes); | |||
| int | |||
| ioaudio_driver_write (ioaudio_driver_t* driver, jack_nframes_t nframes); | |||
| jack_time_t jack_get_microseconds(void); | |||
| // Code implemented in JackioaudioDriver.cpp | |||
| void ReadInput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread); | |||
| void MonitorInput(); | |||
| void ClearOutput(); | |||
| void WriteOutput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten); | |||
| void SetTime(jack_time_t time); | |||
| int Restart(); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* __jack_ioaudio_driver_h__ */ | |||
| @@ -41,3 +41,11 @@ def build(bld): | |||
| deva = create_jack_driver_obj(bld, 'jack', 'ioaudio/ioaudio_driver.c', ['IOAUDIO', 'clientlib', 'PTHREAD']) | |||
| deva.env['cxxshlib_PATTERN'] = 'deva-ctrl-%s.so' | |||
| deva.install_path = '/lib/dll' | |||
| ioaudio_driver_src = [ | |||
| 'ioaudio/JackIoAudioDriver.cpp', | |||
| '../common/memops.c', | |||
| 'ioaudio/ioaudio_backend.c', | |||
| ] | |||
| create_jack_driver_obj(bld, 'ioaudio', ioaudio_driver_src, ['IOAUDIO', 'PTHREAD']) | |||