2006-09-03 10:39:10 +03:00
/*
2008-03-05 18:39:51 +02:00
Copyright ( C ) 2005 Grame
2006-09-03 10:39:10 +03:00
This program is free software ; you can redistribute it and / or modify
2007-10-07 16:14:15 +03:00
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 0213 9 , USA .
2006-09-03 10:39:10 +03:00
*/
2007-08-20 10:31:02 +03:00
2006-09-03 10:39:10 +03:00
# include "JackServerGlobals.h"
2011-03-13 14:56:30 +02:00
# include "JackLockedEngine.h"
2007-11-01 16:46:02 +02:00
# include "JackTools.h"
2006-09-03 10:39:10 +03:00
# include "shm.h"
# include <getopt.h>
2008-05-26 12:49:27 +03:00
# include <errno.h>
2006-09-03 10:39:10 +03:00
2007-10-05 12:20:55 +03:00
static char * server_name = NULL ;
2006-09-03 10:39:10 +03:00
namespace Jack
{
2011-03-04 13:02:25 +02:00
JackServer * JackServerGlobals : : fInstance ;
2009-01-14 17:01:58 +02:00
unsigned int JackServerGlobals : : fUserCount ;
2011-03-13 14:56:30 +02:00
std : : map < std : : string , JackDriverInfo * > JackServerGlobals : : fSlavesList ;
std : : map < std : : string , int > JackServerGlobals : : fInternalsList ;
2011-03-04 13:02:25 +02:00
2009-07-07 20:18:11 +03:00
bool ( * JackServerGlobals : : on_device_acquire ) ( const char * device_name ) = NULL ;
void ( * JackServerGlobals : : on_device_release ) ( const char * device_name ) = NULL ;
2019-10-28 12:16:09 +02:00
void ( * JackServerGlobals : : on_device_reservation_loop ) ( void ) = NULL ;
2019-05-22 11:47:08 +03:00
void ( * JackServerGlobals : : on_failure ) ( ) = NULL ;
2006-09-03 10:39:10 +03:00
2008-03-05 18:39:51 +02:00
int JackServerGlobals : : Start ( const char * server_name ,
jack_driver_desc_t * driver_desc ,
JSList * driver_params ,
int sync ,
int temporary ,
int time_out_ms ,
int rt ,
int priority ,
2009-11-24 18:52:22 +02:00
int port_max ,
2009-04-20 17:01:41 +03:00
int verbose ,
2009-05-26 14:05:34 +03:00
jack_timer_type_t clock ,
2014-03-10 03:31:23 +02:00
char self_connect_mode )
2006-09-03 10:39:10 +03:00
{
2008-03-10 18:47:42 +02:00
jack_log ( " Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld " , sync , time_out_ms , rt , priority , verbose ) ;
2010-02-10 21:28:50 +02:00
new JackServer ( sync , temporary , time_out_ms , rt , priority , port_max , verbose , clock , self_connect_mode , server_name ) ; // Will setup fInstance and fUserCount globals
2009-01-14 17:01:58 +02:00
int res = fInstance - > Open ( driver_desc , driver_params ) ;
return ( res < 0 ) ? res : fInstance - > Start ( ) ;
2006-09-03 10:39:10 +03:00
}
2009-01-14 17:01:58 +02:00
void JackServerGlobals : : Stop ( )
2006-09-03 10:39:10 +03:00
{
2008-03-10 18:47:42 +02:00
jack_log ( " Jackdmp: server close " ) ;
2009-01-14 17:01:58 +02:00
fInstance - > Stop ( ) ;
fInstance - > Close ( ) ;
2006-09-03 10:39:10 +03:00
}
2009-01-14 17:01:58 +02:00
void JackServerGlobals : : Delete ( )
2006-09-03 10:39:10 +03:00
{
2008-03-10 18:47:42 +02:00
jack_log ( " Jackdmp: delete server " ) ;
2011-03-13 14:56:30 +02:00
// Slave drivers
std : : map < std : : string , JackDriverInfo * > : : iterator it1 ;
for ( it1 = fSlavesList . begin ( ) ; it1 ! = fSlavesList . end ( ) ; it1 + + ) {
JackDriverInfo * info = ( * it1 ) . second ;
if ( info ) {
fInstance - > RemoveSlave ( ( info ) ) ;
delete ( info ) ;
}
}
fSlavesList . clear ( ) ;
// Internal clients
std : : map < std : : string , int > : : iterator it2 ;
for ( it2 = fInternalsList . begin ( ) ; it2 ! = fInternalsList . end ( ) ; it2 + + ) {
int status ;
int refnum = ( * it2 ) . second ;
if ( refnum > 0 ) {
2011-07-19 18:24:36 +03:00
// Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
2011-03-13 14:56:30 +02:00
fInstance - > GetEngine ( ) - > InternalClientUnload ( refnum , & status ) ;
}
}
fInternalsList . clear ( ) ;
2009-01-14 17:01:58 +02:00
delete fInstance ;
fInstance = NULL ;
2006-09-03 10:39:10 +03:00
}
2007-10-04 17:23:35 +03:00
bool JackServerGlobals : : Init ( )
2006-09-03 10:39:10 +03:00
{
2008-08-27 13:56:53 +03:00
int realtime = 0 ;
int client_timeout = 0 ; /* msecs; if zero, use period size. */
int realtime_priority = 10 ;
int verbose_aux = 0 ;
unsigned int port_max = 128 ;
int temporary = 0 ;
2008-09-22 18:27:23 +03:00
2008-08-27 13:56:53 +03:00
int opt = 0 ;
int option_index = 0 ;
2011-03-13 14:56:30 +02:00
char * master_driver_name = NULL ;
char * * master_driver_args = NULL ;
JSList * master_driver_params = NULL ;
jack_driver_desc_t * driver_desc ;
jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK ;
2008-08-27 13:56:53 +03:00
int driver_nargs = 1 ;
JSList * drivers = NULL ;
2011-03-13 14:56:30 +02:00
int loopback = 0 ;
2008-08-27 13:56:53 +03:00
int sync = 0 ;
int rc , i ;
2013-01-26 21:51:57 +02:00
int res ;
2011-03-13 14:56:30 +02:00
int replace_registry = 0 ;
2008-08-27 13:56:53 +03:00
FILE * fp = 0 ;
char filename [ 255 ] ;
char buffer [ 255 ] ;
int argc = 0 ;
char * argv [ 32 ] ;
2011-03-04 13:02:25 +02:00
2009-01-14 17:01:58 +02:00
// First user starts the server
if ( fUserCount + + = = 0 ) {
2008-03-05 18:39:51 +02:00
2008-03-10 18:47:42 +02:00
jack_log ( " JackServerGlobals Init " ) ;
2008-09-22 18:27:23 +03:00
2011-03-13 14:56:30 +02:00
const char * options = " -d:X:I:P:uvshVrRL:STFl:t:mn:p: "
# ifdef __linux__
" c: "
# endif
;
struct option long_options [ ] = {
# ifdef __linux__
{ " clock-source " , 1 , 0 , ' c ' } ,
# endif
{ " loopback-driver " , 1 , 0 , ' L ' } ,
{ " audio-driver " , 1 , 0 , ' d ' } ,
{ " midi-driver " , 1 , 0 , ' X ' } ,
{ " internal-client " , 1 , 0 , ' I ' } ,
{ " verbose " , 0 , 0 , ' v ' } ,
{ " help " , 0 , 0 , ' h ' } ,
{ " port-max " , 1 , 0 , ' p ' } ,
{ " no-mlock " , 0 , 0 , ' m ' } ,
{ " name " , 1 , 0 , ' n ' } ,
{ " unlock " , 0 , 0 , ' u ' } ,
{ " realtime " , 0 , 0 , ' R ' } ,
{ " no-realtime " , 0 , 0 , ' r ' } ,
{ " replace-registry " , 0 , & replace_registry , 0 } ,
{ " loopback " , 0 , 0 , ' L ' } ,
{ " realtime-priority " , 1 , 0 , ' P ' } ,
{ " timeout " , 1 , 0 , ' t ' } ,
{ " temporary " , 0 , 0 , ' T ' } ,
{ " version " , 0 , 0 , ' V ' } ,
{ " silent " , 0 , 0 , ' s ' } ,
{ " sync " , 0 , 0 , ' S ' } ,
{ 0 , 0 , 0 , 0 }
} ;
2008-09-22 18:27:23 +03:00
2008-03-05 18:39:51 +02:00
snprintf ( filename , 255 , " %s/.jackdrc " , getenv ( " HOME " ) ) ;
fp = fopen ( filename , " r " ) ;
if ( ! fp ) {
fp = fopen ( " /etc/jackdrc " , " r " ) ;
}
2019-08-23 01:30:45 +03:00
// if still not found, check old config name for backwards compatibility
2008-03-05 18:39:51 +02:00
if ( ! fp ) {
fp = fopen ( " /etc/jackd.conf " , " r " ) ;
}
argc = 0 ;
if ( fp ) {
2013-01-26 21:51:57 +02:00
res = fscanf ( fp , " %s " , buffer ) ;
while ( res ! = 0 & & res ! = EOF ) {
2008-03-05 18:39:51 +02:00
argv [ argc ] = ( char * ) malloc ( 64 ) ;
strcpy ( argv [ argc ] , buffer ) ;
2013-01-26 21:51:57 +02:00
res = fscanf ( fp , " %s " , buffer ) ;
2008-03-05 18:39:51 +02:00
argc + + ;
}
fclose ( fp ) ;
}
/*
For testing
int argc = 15 ;
char * argv [ ] = { " jackdmp " , " -R " , " -v " , " -d " , " coreaudio " , " -p " , " 512 " , " -d " , " ~:Aggregate:0 " , " -r " , " 48000 " , " -i " , " 2 " , " -o " , " 2 " } ;
*/
opterr = 0 ;
optind = 1 ; // Important : to reset argv parsing
2011-03-13 14:56:30 +02:00
while ( ! master_driver_name & &
2008-03-05 18:39:51 +02:00
( opt = getopt_long ( argc , argv , options , long_options , & option_index ) ) ! = EOF ) {
switch ( opt ) {
2011-03-04 13:02:25 +02:00
2009-04-20 17:01:41 +03:00
case ' c ' :
if ( tolower ( optarg [ 0 ] ) = = ' h ' ) {
clock_source = JACK_TIMER_HPET ;
} else if ( tolower ( optarg [ 0 ] ) = = ' c ' ) {
2014-03-14 20:07:00 +02:00
/* For backwards compatibility with scripts, allow
* the user to request the cycle clock on the
* command line , but use the system clock instead
*/
clock_source = JACK_TIMER_SYSTEM_CLOCK ;
2009-04-20 17:01:41 +03:00
} else if ( tolower ( optarg [ 0 ] ) = = ' s ' ) {
clock_source = JACK_TIMER_SYSTEM_CLOCK ;
} else {
jack_error ( " unknown option character %c " , optopt ) ;
2011-03-04 13:02:25 +02:00
}
2009-04-20 17:01:41 +03:00
break ;
2008-03-05 18:39:51 +02:00
case ' d ' :
2011-03-13 14:56:30 +02:00
master_driver_name = optarg ;
2008-03-05 18:39:51 +02:00
break ;
2011-03-13 14:56:30 +02:00
case ' L ' :
loopback = atoi ( optarg ) ;
2008-03-05 18:39:51 +02:00
break ;
2011-03-13 14:56:30 +02:00
case ' X ' :
fSlavesList [ optarg ] = NULL ;
2008-03-05 18:39:51 +02:00
break ;
2011-03-13 14:56:30 +02:00
case ' I ' :
fInternalsList [ optarg ] = - 1 ;
break ;
case ' p ' :
port_max = ( unsigned int ) atol ( optarg ) ;
2008-03-05 18:39:51 +02:00
break ;
2013-07-18 08:40:57 +03:00
case ' m ' :
break ;
case ' u ' :
break ;
2011-03-13 14:56:30 +02:00
case ' v ' :
verbose_aux = 1 ;
break ;
case ' S ' :
sync = 1 ;
break ;
case ' n ' :
server_name = optarg ;
2008-03-05 18:39:51 +02:00
break ;
case ' P ' :
realtime_priority = atoi ( optarg ) ;
break ;
2011-03-13 14:56:30 +02:00
case ' r ' :
realtime = 0 ;
break ;
2008-03-05 18:39:51 +02:00
case ' R ' :
realtime = 1 ;
break ;
case ' T ' :
temporary = 1 ;
break ;
case ' t ' :
client_timeout = atoi ( optarg ) ;
break ;
default :
2008-03-10 15:17:48 +02:00
jack_error ( " unknown option character %c " , optopt ) ;
2008-03-05 18:39:51 +02:00
break ;
}
}
drivers = jack_drivers_load ( drivers ) ;
if ( ! drivers ) {
2008-03-10 15:17:48 +02:00
jack_error ( " jackdmp: no drivers found; exiting " ) ;
2008-03-05 18:39:51 +02:00
goto error ;
}
2011-03-13 14:56:30 +02:00
driver_desc = jack_find_driver_descriptor ( drivers , master_driver_name ) ;
2008-03-05 18:39:51 +02:00
if ( ! driver_desc ) {
2011-03-13 14:56:30 +02:00
jack_error ( " jackdmp: unknown master driver '%s' " , master_driver_name ) ;
2008-03-05 18:39:51 +02:00
goto error ;
}
if ( optind < argc ) {
driver_nargs = 1 + argc - optind ;
} else {
driver_nargs = 1 ;
}
if ( driver_nargs = = 0 ) {
2008-03-10 15:17:48 +02:00
jack_error ( " No driver specified ... hmm. JACK won't do "
2008-03-13 15:50:18 +02:00
" anything when run like this. " ) ;
2008-03-05 18:39:51 +02:00
goto error ;
}
2011-03-13 14:56:30 +02:00
master_driver_args = ( char * * ) malloc ( sizeof ( char * ) * driver_nargs ) ;
master_driver_args [ 0 ] = master_driver_name ;
2008-03-05 18:39:51 +02:00
for ( i = 1 ; i < driver_nargs ; i + + ) {
2011-03-13 14:56:30 +02:00
master_driver_args [ i ] = argv [ optind + + ] ;
2008-03-05 18:39:51 +02:00
}
2011-03-13 14:56:30 +02:00
if ( jack_parse_driver_params ( driver_desc , driver_nargs , master_driver_args , & master_driver_params ) ) {
2008-03-05 18:39:51 +02:00
goto error ;
}
# ifndef WIN32
2013-01-12 13:30:49 +02:00
if ( server_name = = NULL ) {
2008-03-05 18:39:51 +02:00
server_name = ( char * ) JackTools : : DefaultServerName ( ) ;
2013-01-12 13:30:49 +02:00
}
2008-03-05 18:39:51 +02:00
# endif
rc = jack_register_server ( server_name , false ) ;
switch ( rc ) {
case EEXIST :
2008-03-10 15:17:48 +02:00
jack_error ( " `%s' server already active " , server_name ) ;
2008-03-05 18:39:51 +02:00
goto error ;
case ENOSPC :
2008-03-10 15:17:48 +02:00
jack_error ( " too many servers already active " ) ;
2008-03-05 18:39:51 +02:00
goto error ;
case ENOMEM :
2008-03-10 15:17:48 +02:00
jack_error ( " no access to shm registry " ) ;
2008-03-05 18:39:51 +02:00
goto error ;
default :
2008-05-26 12:49:27 +03:00
jack_info ( " server `%s' registered " , server_name ) ;
2008-03-05 18:39:51 +02:00
}
/* clean up shared memory and files from any previous instance of this server name */
jack_cleanup_shm ( ) ;
JackTools : : CleanupFiles ( server_name ) ;
2013-01-12 13:30:49 +02:00
if ( ! realtime & & client_timeout = = 0 ) {
2008-03-05 18:39:51 +02:00
client_timeout = 500 ; /* 0.5 sec; usable when non realtime. */
2013-01-12 13:30:49 +02:00
}
2008-03-05 18:39:51 +02:00
for ( i = 0 ; i < argc ; i + + ) {
free ( argv [ i ] ) ;
}
2011-03-14 22:13:11 +02:00
int res = Start ( server_name , driver_desc , master_driver_params , sync , temporary , client_timeout , realtime , realtime_priority , port_max , verbose_aux , clock_source , JACK_DEFAULT_SELF_CONNECT_MODE ) ;
2008-03-05 18:39:51 +02:00
if ( res < 0 ) {
jack_error ( " Cannot start server... exit " ) ;
Delete ( ) ;
jack_cleanup_shm ( ) ;
JackTools : : CleanupFiles ( server_name ) ;
jack_unregister_server ( server_name ) ;
goto error ;
}
2011-03-13 14:56:30 +02:00
// Slave drivers
std : : map < std : : string , JackDriverInfo * > : : iterator it1 ;
for ( it1 = fSlavesList . begin ( ) ; it1 ! = fSlavesList . end ( ) ; it1 + + ) {
const char * name = ( ( * it1 ) . first ) . c_str ( ) ;
driver_desc = jack_find_driver_descriptor ( drivers , name ) ;
if ( ! driver_desc ) {
jack_error ( " jackdmp: unknown slave driver '%s' " , name ) ;
} else {
2011-03-14 12:40:16 +02:00
( * it1 ) . second = fInstance - > AddSlave ( driver_desc , NULL ) ;
2011-03-13 14:56:30 +02:00
}
}
// Loopback driver
if ( loopback > 0 ) {
driver_desc = jack_find_driver_descriptor ( drivers , " loopback " ) ;
if ( ! driver_desc ) {
jack_error ( " jackdmp: unknown driver '%s' " , " loopback " ) ;
} else {
2011-03-14 12:40:16 +02:00
fSlavesList [ " loopback " ] = fInstance - > AddSlave ( driver_desc , NULL ) ;
2011-03-13 14:56:30 +02:00
}
}
// Internal clients
std : : map < std : : string , int > : : iterator it2 ;
for ( it2 = fInternalsList . begin ( ) ; it2 ! = fInternalsList . end ( ) ; it2 + + ) {
int status , refnum ;
const char * name = ( ( * it2 ) . first ) . c_str ( ) ;
fInstance - > InternalClientLoad2 ( name , name , NULL , JackNullOption , & refnum , - 1 , & status ) ;
( * it2 ) . second = refnum ;
}
2008-03-05 18:39:51 +02:00
}
2008-09-22 18:27:23 +03:00
2013-01-12 13:30:49 +02:00
if ( master_driver_params ) {
2011-03-13 14:56:30 +02:00
jack_free_driver_params ( master_driver_params ) ;
2013-01-12 13:30:49 +02:00
}
2008-03-05 18:39:51 +02:00
return true ;
2007-10-04 17:23:35 +03:00
error :
2011-03-13 14:56:30 +02:00
jack_log ( " JackServerGlobals Init error " ) ;
2013-01-12 13:30:49 +02:00
if ( master_driver_params ) {
2011-03-13 14:56:30 +02:00
jack_free_driver_params ( master_driver_params ) ;
2013-01-12 13:30:49 +02:00
}
2011-03-13 14:56:30 +02:00
Destroy ( ) ;
2008-03-05 18:39:51 +02:00
return false ;
2006-09-03 10:39:10 +03:00
}
void JackServerGlobals : : Destroy ( )
{
2009-01-14 17:01:58 +02:00
if ( - - fUserCount = = 0 ) {
2008-03-10 18:47:42 +02:00
jack_log ( " JackServerGlobals Destroy " ) ;
2008-03-05 18:39:51 +02:00
Stop ( ) ;
2009-01-14 17:01:58 +02:00
Delete ( ) ;
2008-03-05 18:39:51 +02:00
jack_cleanup_shm ( ) ;
JackTools : : CleanupFiles ( server_name ) ;
jack_unregister_server ( server_name ) ;
2006-09-03 10:39:10 +03:00
}
}
} // end of namespace