AudioManager  7.5.11
Native Application Runtime Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
main.cpp
Go to the documentation of this file.
1 
25 #include "audiomanagerconfig.h"
26 
27 #ifdef WITH_TELNET
28  #include "CAmTelnetServer.h"
29 #endif
30 
31 #ifdef WITH_CAPI_WRAPPER
32  #include "CAmCommonAPIWrapper.h"
33 #endif
34 
35 #ifdef WITH_DBUS_WRAPPER
36  #include "CAmDbusWrapper.h"
37 #endif
38 
39 
40 #ifdef WITH_DATABASE_STORAGE
41  #include "CAmDatabaseHandlerSQLite.h"
42 #else
43  #include "CAmDatabaseHandlerMap.h"
44 #endif
45 
46 #ifdef WITH_SYSTEMD_WATCHDOG
47  #include "CAmWatchdog.h"
48 #endif
49 
50 #include <sys/resource.h>
51 #include <sys/stat.h>
52 #include <unistd.h>
53 #include <cstdlib>
54 #include <cstdlib>
55 #include <cassert>
56 #include <fcntl.h>
57 #include <csignal>
58 #include <cstring>
59 #include <cstdio>
60 #include <new>
61 
62 #include "CAmRouter.h"
63 #include "CAmControlSender.h"
64 #include "CAmCommandSender.h"
65 #include "CAmRoutingSender.h"
66 #include "CAmRoutingReceiver.h"
67 #include "CAmCommandReceiver.h"
68 #include "CAmControlReceiver.h"
69 #include "CAmDatabaseObserver.h"
70 #include "CAmDltWrapper.h"
71 #include "CAmSocketHandler.h"
73 
74 
75 using namespace am;
76 
77 //we need these because we parse them beforehand.
78 std::vector<std::string> listCommandPluginDirs;
79 std::vector<std::string> listRoutingPluginDirs;
80 
81 //commandline options used by the Audiomanager itself
82 TCLAP::ValueArg<std::string> controllerPlugin("c","controllerPlugin","use controllerPlugin full path with .so ending",false,CONTROLLER_PLUGIN_DIR,"string");
83 TCLAP::ValueArg<std::string> additionalCommandPluginDirs("L","additionalCommandPluginDirs","additional path for looking for command plugins, can be used after -l option",false," ","string");
84 TCLAP::ValueArg<std::string> additionalRoutingPluginDirs("R","additionalRoutingPluginDirs","additional path for looking for routing plugins, can be used after -r option ",false," ","string");
85 TCLAP::ValueArg<std::string> routingPluginDir("r","RoutingPluginDir","path for looking for routing plugins",false," ","string");
86 TCLAP::ValueArg<std::string> commandPluginDir("l","CommandPluginDir","path for looking for command plugins",false," ","string");
87 TCLAP::ValueArg<std::string> dltLogFilename("F","dltLogFilename","the name of the logfile, absolute path. Only if logging is et to file",false," ","string");
88 TCLAP::ValueArg<unsigned int> dltOutput ("O","dltOutput","defines where logs are written. 0=dlt-daemon(default), 1=command line, 2=file ",false,0,"int");
89 TCLAP::ValueArg<unsigned int> telnetPort ("t","telnetport","The port that is used for telnet",false,DEFAULT_TELNETPORT,"int");
90 TCLAP::ValueArg<unsigned int> maxConnections ("m","maxConnections","Maximal number of connections for telnet",false,MAX_TELNETCONNECTIONS,"int");
91 TCLAP::SwitchArg dltEnable ("e","dltEnable","Enables or disables dlt logging. Default = enabled",true);
92 TCLAP::SwitchArg dbusWrapperTypeBool ("T","dbusType","DbusType to be used by CAmDbusWrapper: if option is selected, DBUS_SYSTEM is used otherwise DBUS_SESSION",false);
93 TCLAP::SwitchArg currentSettings("i","currentSettings","print current settings and exit",false);
94 TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...",false);
95 
96 int fd0, fd1, fd2;
97 
98 #ifdef WITH_DBUS_WRAPPER
99  DBusBusType dbusWrapperType=DBUS_BUS_SESSION;
100 #endif
101 
106 {
107  logError("No more memory - bye");
108  throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error."));
109 }
110 
114 void daemonize()
115 {
116  umask(0);
117  std::string dir = "/";
118 
119  rlimit rl;
120  if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
121  {
122  logError("can't get file limit ");
123  }
124 
125  pid_t pid;
126  if ((pid = fork()) < 0)
127  {
128  logError("cannot fork!");
129  }
130  else if (pid != 0)
131  {
132  exit(0);
133  }
134 
135  setsid();
136 
137  if (!dir.empty() && chdir(dir.c_str()) < 0)
138  {
139  logError("couldn't chdir to the new directory");
140  }
141 
142  if (rl.rlim_max == RLIM_INFINITY)
143  {
144  rl.rlim_max = 1024;
145  }
146 
147  for (unsigned int i = 0; i < rl.rlim_max; i++)
148  {
149  close(i);
150  }
151 
152  fd0 = open("/dev/null", O_RDONLY);
153  fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
154  fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
155 
156  if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
157  {
158  logError("new standard file descriptors were not opened");
159  }
160 }
161 
162 
163 
165 {
166  printf("\n\n\nCurrent settings:\n\n");
167  printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
168 #ifdef WITH_TELNET
169  printf("\tTelnet portNumber:\t\t\t%i\n", telnetPort.getValue());
170  printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections.getValue());
171 #endif
172  printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.getValue().c_str());
173  printf("\tDirectories of CommandPlugins: \t\t\n");
174  std::vector<std::string>::const_iterator dirIter = listCommandPluginDirs.begin();
175  std::vector<std::string>::const_iterator dirIterEnd = listCommandPluginDirs.end();
176  for (; dirIter < dirIterEnd; ++dirIter)
177  {
178  printf("\t \t\t%s\n", dirIter->c_str());
179  }
180 
181  printf("\tDirectories of RoutingPlugins: \t\t\n");
182  dirIter = listRoutingPluginDirs.begin();
183  dirIterEnd = listRoutingPluginDirs.end();
184  for (; dirIter < dirIterEnd; ++dirIter)
185  {
186  printf("\t \t\t%s\n", dirIter->c_str());
187  }
188  exit(0);
189 }
190 
197 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
198 {
199  (void) sig;
200  (void) siginfo;
201  (void) context;
202  logInfo("signal handler was called, signal",sig);
203 
204  switch (sig)
205  {
206  /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment.
207  But there is the risk of interrupting something important */
208  case SIGINT:
210  break;
211 
212  /* huch- we are getting killed. Better take the fast but risky way: */
213  case SIGQUIT:
215  break;
216 
217  /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */
218  case SIGTERM:
220  break;
221 
222  /* looks friendly, too, so lets take the long run */
223  case SIGHUP:
225  break;
226  default:
227  break;
228  }
229 }
230 
231 void mainProgram(int argc, char *argv[])
232 {
233 
234  //initialize the commandline parser, and add all neccessary commands
235  try
236  {
237  TCLAP::CmdLine* cmd(CAmCommandLineSingleton::instanciateOnce("The team of the AudioManager wishes you a nice day!",' ',DAEMONVERSION,true));
238  cmd->add(controllerPlugin);
239  cmd->add(additionalCommandPluginDirs);
240  cmd->add(commandPluginDir);
241  cmd->add(additionalRoutingPluginDirs);
242  cmd->add(routingPluginDir);
243  cmd->add(currentSettings);
244  cmd->add(daemonizeAM);
245  cmd->add(dltEnable);
246  cmd->add(dltLogFilename);
247  cmd->add(dltOutput);
248 #ifdef WITH_DBUS_WRAPPER
249  cmd->add(dbusWrapperTypeBool);
250 #endif
251 #ifdef WITH_TELNET
252  cmd->add(telnetPort);
253  cmd->add(maxConnections);
254 #endif
255 #ifdef WITH_DATABASE_STORAGE
256  cmd->add(databasePath);
257 #endif
258  }
259  catch (TCLAP::ArgException &e) // catch any exceptions
260  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
261 
262  //hen and egg. We need to parse a part of the commandline options to get the paths of the controller and the plugins.
263  //So we do some little parsing first and the real parsing later so that the plugins can profit from that.
264  CAmCommandLineSingleton::instance()->preparse(argc,argv);
265  if (daemonizeAM.getValue())
266  {
267  daemonize();
268  }
269 
270  CAmDltWrapper::instanctiateOnce("AUDI", "AudioManager",dltEnable.getValue(),static_cast<am::CAmDltWrapper::logDestination>(dltOutput.getValue()),dltLogFilename.getValue());
271 
272  //Instantiate all classes. Keep in same order !
273  CAmSocketHandler iSocketHandler;
274 
275  if(commandPluginDir.isSet())
276  {
277  listCommandPluginDirs.clear();
278  listCommandPluginDirs.push_back(commandPluginDir.getValue());
279  }
280 
281  if (additionalCommandPluginDirs.isSet())
282  {
284  }
285 
286  if(routingPluginDir.isSet())
287  {
288  listRoutingPluginDirs.clear();
289  listRoutingPluginDirs.push_back(routingPluginDir.getValue());
290  }
291 
292  if (additionalRoutingPluginDirs.isSet())
293  {
295  }
296 
297  //in this place, the plugins can get the gloval commandlineparser via CAmCommandLineSingleton::instance() and add their options to the commandline
298  //this must be done in the constructor.
299  //later when the plugins are started, the commandline is already parsed and the objects defined before can be used to get the neccesary information
300 
301  CAmDatabaseHandlerMap iDatabaseHandler;
302  IAmDatabaseHandler *pDatabaseHandler = dynamic_cast<IAmDatabaseHandler*>( &iDatabaseHandler );
303 
304  CAmRoutingSender iRoutingSender(listRoutingPluginDirs,pDatabaseHandler);
305  CAmCommandSender iCommandSender(listCommandPluginDirs);
306  CAmControlSender iControlSender(controllerPlugin.getValue(),&iSocketHandler);
307 
308  try
309  {
310  //parse the commandline options
312  CAmCommandLineSingleton::instance()->parse(argc,argv);
313  if (currentSettings.getValue())
314  {
316  }
317  }
318  catch (TCLAP::ArgException &e) // catch any exceptions
319  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
320 
321  logInfo("The Audiomanager is started");
322  logInfo("The version of the Audiomanager", DAEMONVERSION);
323 
324 #ifdef WITH_CAPI_WRAPPER
325  //We instantiate a singleton with the current socket handler, which loads the common-api runtime.
326  CAmCommonAPIWrapper *pCAPIWrapper = CAmCommonAPIWrapper::instantiateOnce(&iSocketHandler, "AudioManager");
327 #endif /*WITH_CAPI_WRAPPER */
328 
329 #ifdef WITH_DBUS_WRAPPER
330  if (dbusWrapperTypeBool.getValue())
331  dbusWrapperType=DBUS_BUS_SYSTEM;
332  CAmDbusWrapper iDBusWrapper(&iSocketHandler,dbusWrapperType);
333 #endif /*WITH_DBUS_WRAPPER */
334 
335 #ifdef WITH_SYSTEMD_WATCHDOG
336  CAmWatchdog iWatchdog(&iSocketHandler);
337 #endif /*WITH_SYSTEMD_WATCHDOG*/
338 
339 CAmRouter iRouter(pDatabaseHandler, &iControlSender);
340 
341 #ifdef WITH_DBUS_WRAPPER
342  CAmCommandReceiver iCommandReceiver(pDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
343  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
344 #else /*WITH_DBUS_WRAPPER*/
345  CAmCommandReceiver iCommandReceiver(pDatabaseHandler,&iControlSender,&iSocketHandler);
346  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
347 #endif /*WITH_DBUS_WRAPPER*/
348 
349 CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
350 
351 #ifdef WITH_TELNET
352  CAmTelnetServer iTelnetServer(&iSocketHandler, &iCommandSender, &iCommandReceiver, &iRoutingSender, &iRoutingReceiver, &iControlSender, &iControlReceiver, pDatabaseHandler, &iRouter, telnetPort.getValue(), maxConnections.getValue());
353  CAmDatabaseObserver iObserver(&iCommandSender, &iRoutingSender, &iSocketHandler, &iTelnetServer);
354 #else /*WITH_TELNET*/
355  CAmDatabaseObserver iObserver(&iCommandSender,&iRoutingSender, &iSocketHandler);
356 #endif
357 
358  iDatabaseHandler.registerObserver(&iObserver);
359 
360  //startup all the Plugins and Interfaces
361  //at this point, commandline arguments can be parsed
362  iControlSender.startupController(&iControlReceiver);
363  iCommandSender.startupInterfaces(&iCommandReceiver);
364  iRoutingSender.startupInterfaces(&iRoutingReceiver);
365 
366  //when the routingInterface is done, all plugins are loaded:
367  iControlSender.setControllerReady();
368 
369 #ifdef WITH_SYSTEMD_WATCHDOG
370  iWatchdog.startWatchdog();
371 #endif /*WITH_SYSTEMD_WATCHDOG*/
372 
373  //start the mainloop here....
374  iSocketHandler.start_listenting();
375 }
376 
383 int main(int argc, char *argv[], char** envp)
384 {
385  (void) envp;
386  listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
387  listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
388 
389  //now the signal handler:
390  struct sigaction signalAction;
391  memset(&signalAction, '\0', sizeof(signalAction));
392  signalAction.sa_sigaction = &signalHandler;
393  signalAction.sa_flags = SA_SIGINFO;
394  sigaction(SIGINT, &signalAction, NULL);
395  sigaction(SIGQUIT, &signalAction, NULL);
396  sigaction(SIGTERM, &signalAction, NULL);
397  sigaction(SIGHUP, &signalAction, NULL);
398 
399  struct sigaction signalChildAction;
400  memset(&signalChildAction, '\0', sizeof(signalChildAction));
401  signalChildAction.sa_flags = SA_NOCLDWAIT;
402  sigaction(SIGCHLD, &signalChildAction, NULL);
403 
404  //register new out of memory handler
405  std::set_new_handler(&OutOfMemoryHandler);
406 
407  try
408  {
409  //we do this to catch all exceptions and have a graceful ending just in case
410  mainProgram(argc,argv);
411  }
412 
413  catch (std::exception& exc)
414  {
415  logError("The AudioManager ended by throwing the exception", exc.what());
416  std::cerr<<"The AudioManager ended by throwing an exception "<<exc.what()<<std::endl;
417  exit(EXIT_FAILURE);
418  }
419 
420  close(fd0);
421  close(fd1);
422  close(fd2);
423  exit(0);
424 
425 }
426 
Implements the RoutingSendInterface.
int fd0
Definition: main.cpp:96
This class realizes the command Interface.
SPDX license identifier: MPL-2.0.
TCLAP::ValueArg< std::string > commandPluginDir("l","CommandPluginDir","path for looking for command plugins", false," ","string")
am_Error_e startupInterfaces(CAmCommandReceiver *iCommandReceiver)
int main(int argc, char *argv[], char **envp)
main
Definition: main.cpp:383
void daemonize()
daemonizes the AudioManager
Definition: main.cpp:114
void logInfo(T value, TArgs...args)
logs given values with infolevel with the default context
Implements an autorouting algorithm for connecting sinks and sources via different audio domains...
Definition: CAmRouter.h:152
TCLAP::ValueArg< std::string > additionalCommandPluginDirs("L","additionalCommandPluginDirs","additional path for looking for command plugins, can be used after -l option", false," ","string")
This class is used to receive all commands from the control interface.
static CAmCommonAPIWrapper * instantiateOnce(CAmSocketHandler *socketHandler, const std::string &applicationName="")
Creates a singleton instance attached to the provided socket handler object.
The am::CAmSocketHandler implements a mainloop for the AudioManager.
static CAmDltWrapper * instanctiateOnce(const char *appid, const char *description, const bool debugEnabled=true, const logDestination logDest=logDestination::DAEMON, const std::string Filename="", bool onlyError=false)
Instanciate the Dlt Wrapper.
SPDX license identifier: MPL-2.0.
static TCLAP::CmdLine * instance()
Implements the watchdog of the AudioManager with the help of systemd.
Definition: CAmWatchdog.h:35
void printCmdInformation()
Definition: main.cpp:164
void registerObserver(CAmDatabaseObserver *iObserver)
registers the Observer at the Database
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
int fd2
Definition: main.cpp:96
Implements the Receiving side of the RoutingPlugins.
int fd1
Definition: main.cpp:96
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
void OutOfMemoryHandler()
the out of memory handler
Definition: main.cpp:105
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
static TCLAP::CmdLine * instanciateOnce(const std::string &message, const char delimiter= ' ', const std::string &version="none", bool helpAndVersion=true)
TCLAP::ValueArg< std::string > routingPluginDir("r","RoutingPluginDir","path for looking for routing plugins", false," ","string")
SPDX license identifier: MPL-2.0.
TCLAP::SwitchArg dbusWrapperTypeBool("T","dbusType","DbusType to be used by CAmDbusWrapper: if option is selected, DBUS_SYSTEM is used otherwise DBUS_SESSION", false)
TCLAP::ValueArg< std::string > additionalRoutingPluginDirs("R","additionalRoutingPluginDirs","additional path for looking for routing plugins, can be used after -r option ", false," ","string")
TCLAP::SwitchArg dltEnable("e","dltEnable","Enables or disables dlt logging. Default = enabled", true)
sends data to the commandInterface, takes the file of the library that needs to be loaded ...
This class handles and abstracts the database.
SPDX license identifier: MPL-2.0.
Implements a telnetserver that can be used to connect to the audiomanager, retrieve some information ...
void startWatchdog()
starts the watchdog by sending ready to systemD
Definition: CAmWatchdog.cpp:95
SPDX license identifier: MPL-2.0.
static void CallsetControllerRundownSafe(int16_t signal)
TCLAP::ValueArg< unsigned int > dltOutput("O","dltOutput","defines where logs are written. 0=dlt-daemon(default), 1=command line, 2=file ", false, 0,"int")
am_Error_e startupInterfaces(CAmRoutingReceiver *iRoutingReceiver)
TCLAP::ValueArg< unsigned int > telnetPort("t","telnetport","The port that is used for telnet", false, DEFAULT_TELNETPORT,"int")
TCLAP::SwitchArg currentSettings("i","currentSettings","print current settings and exit", false)
void logError(T value, TArgs...args)
logs given values with errorlevel with the default context
std::vector< std::string > listRoutingPluginDirs
Definition: main.cpp:79
TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...", false)
SPDX license identifier: MPL-2.0.
This wraps dbus and provides everything needed to anyone who wants to use dbus (including plugins)...
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
static void CallsetControllerRundown(int16_t signal)
TCLAP::ValueArg< std::string > dltLogFilename("F","dltLogFilename","the name of the logfile, absolute path. Only if logging is et to file", false," ","string")
std::vector< std::string > listCommandPluginDirs
Definition: main.cpp:78
void mainProgram(int argc, char *argv[])
Definition: main.cpp:231
This class is used to send data to the CommandInterface.
This class handles and abstracts the database.
SPDX license identifier: MPL-2.0.
TCLAP::ValueArg< unsigned int > maxConnections("m","maxConnections","Maximal number of connections for telnet", false, MAX_TELNETCONNECTIONS,"int")
This class observes the Database and notifies other classes about important events, mainly the CommandSender.
TCLAP::ValueArg< std::string > controllerPlugin("c","controllerPlugin","use controllerPlugin full path with .so ending", false, CONTROLLER_PLUGIN_DIR,"string")