AudioManager  7.6.6
Native Application Runtime Environment
main.cpp
Go to the documentation of this file.
1 
25 #include "audiomanagerconfig.h"
26 
27 #ifdef WITH_CAPI_WRAPPER
28  #include "CAmCommonAPIWrapper.h"
29 #endif
30 
31 #ifdef WITH_DBUS_WRAPPER
32  #include "CAmDbusWrapper.h"
33 #endif
34 
35 #ifdef WITH_SYSTEMD_WATCHDOG
36  #include "CAmWatchdog.h"
37 #endif
38 
39 #include <sys/resource.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <cstdlib>
43 #include <cstdlib>
44 #include <cassert>
45 #include <fcntl.h>
46 #include <csignal>
47 #include <cstring>
48 #include <cstdio>
49 #include <new>
50 
51 #include "CAmRouter.h"
52 #include "CAmControlSender.h"
53 #include "CAmCommandSender.h"
54 #include "CAmRoutingSender.h"
55 #include "CAmRoutingReceiver.h"
56 #include "CAmCommandReceiver.h"
57 #include "CAmControlReceiver.h"
58 #include "CAmDltWrapper.h"
59 #include "CAmSocketHandler.h"
61 #include "CAmDatabaseHandlerMap.h"
62 
63 #ifndef AUDIOMANGER_APP_ID
64  #define AUDIOMANGER_APP_ID "AUDI"
65 #endif
66 
67 #ifndef AUDIOMANGER_APP_DESCRIPTION
68  #define AUDIOMANGER_APP_DESCRIPTION "AudioManager"
69 #endif
70 
71 
72 using namespace am;
73 
74 //we need these because we parse them beforehand.
75 std::vector<std::string> listCommandPluginDirs;
76 std::vector<std::string> listRoutingPluginDirs;
77 
78 // List of signals to be handled with signalfd
79 std::vector<uint8_t> listOfSignalsFD = {SIGHUP, SIGTERM, SIGCHLD};
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::SwitchArg dltEnable ("e","dltEnable","Enables or disables dlt logging. Default = enabled",true);
90 TCLAP::SwitchArg dbusWrapperTypeBool ("T","dbusType","DbusType to be used by CAmDbusWrapper: if option is selected, DBUS_SYSTEM is used otherwise DBUS_SESSION",false);
91 TCLAP::SwitchArg currentSettings("i","currentSettings","print current settings and exit",false);
92 TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...",false);
93 
94 int fd0, fd1, fd2;
95 
96 #ifdef WITH_DBUS_WRAPPER
97  DBusBusType dbusWrapperType=DBUS_BUS_SESSION;
98 #endif
99 
104 {
105  logError("No more memory - bye");
106  throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error."));
107 }
108 
112 void daemonize()
113 {
114  umask(0);
115  std::string dir = "/";
116 
117  rlimit rl;
118  if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
119  {
120  logError("can't get file limit ");
121  }
122 
123  pid_t pid;
124  if ((pid = fork()) < 0)
125  {
126  logError("cannot fork!");
127  }
128  else if (pid != 0)
129  {
130  exit(0);
131  }
132 
133  setsid();
134 
135  if (!dir.empty() && chdir(dir.c_str()) < 0)
136  {
137  logError("couldn't chdir to the new directory");
138  }
139 
140  if (rl.rlim_max == RLIM_INFINITY)
141  {
142  rl.rlim_max = 1024;
143  }
144 
145  for (unsigned int i = 0; i < rl.rlim_max; i++)
146  {
147  close(i);
148  }
149 
150  fd0 = open("/dev/null", O_RDONLY);
151  fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
152  fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
153 
154  if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
155  {
156  logError("new standard file descriptors were not opened");
157  }
158 }
159 
160 
161 
163 {
164  printf("\n\n\nCurrent settings:\n\n");
165  printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
166  printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.getValue().c_str());
167  printf("\tDirectories of CommandPlugins: \t\t\n");
168  std::vector<std::string>::const_iterator dirIter = listCommandPluginDirs.begin();
169  std::vector<std::string>::const_iterator dirIterEnd = listCommandPluginDirs.end();
170  for (; dirIter < dirIterEnd; ++dirIter)
171  {
172  printf("\t \t\t%s\n", dirIter->c_str());
173  }
174 
175  printf("\tDirectories of RoutingPlugins: \t\t\n");
176  dirIter = listRoutingPluginDirs.begin();
177  dirIterEnd = listRoutingPluginDirs.end();
178  for (; dirIter < dirIterEnd; ++dirIter)
179  {
180  printf("\t \t\t%s\n", dirIter->c_str());
181  }
182  exit(0);
183 }
184 
191 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
192 {
193  (void) sig;
194  (void) siginfo;
195  (void) context;
196  logInfo("signal handler was called, signal",sig);
197 
198  switch (sig)
199  {
200  /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment.
201  But there is the risk of interrupting something important */
202  case SIGINT:
204  break;
205 
206  /* huch- we are getting killed. Better take the fast but risky way: */
207  case SIGQUIT:
209  break;
210  default:
211  break;
212  }
213 }
214 
215 
216 void mainProgram(int argc, char *argv[])
217 {
218 
219  //initialize the commandline parser, and add all neccessary commands
220  try
221  {
222  TCLAP::CmdLine* cmd(CAmCommandLineSingleton::instanciateOnce("The team of the AudioManager wishes you a nice day!",' ',DAEMONVERSION,true));
223  cmd->add(controllerPlugin);
224  cmd->add(additionalCommandPluginDirs);
225  cmd->add(commandPluginDir);
226  cmd->add(additionalRoutingPluginDirs);
227  cmd->add(routingPluginDir);
228  cmd->add(currentSettings);
229  cmd->add(daemonizeAM);
230  cmd->add(dltEnable);
231  cmd->add(dltLogFilename);
232  cmd->add(dltOutput);
233 #ifdef WITH_DBUS_WRAPPER
234  cmd->add(dbusWrapperTypeBool);
235 #endif
236  }
237  catch (TCLAP::ArgException &e) // catch any exceptions
238  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
239 
240  //hen and egg. We need to parse a part of the commandline options to get the paths of the controller and the plugins.
241  //So we do some little parsing first and the real parsing later so that the plugins can profit from that.
242  CAmCommandLineSingleton::instance()->preparse(argc,argv);
243  if (daemonizeAM.getValue())
244  {
245  daemonize();
246  }
247 
249 
250  //Instantiate all classes. Keep in same order !
251  CAmSocketHandler iSocketHandler;
252  if(iSocketHandler.fatalErrorOccurred())
253  {
254  throw std::runtime_error(std::string("CAmSocketHandler: Could not create pipe or file descriptor is invalid."));
255  }
256 
257  if(E_OK != iSocketHandler.listenToSignals(listOfSignalsFD))
258  {
259  logWarning("CAmSocketHandler failed to register itself as signal handler.");
260  }
261  //Register signal handler
262  sh_pollHandle_t signalHandler;
263  iSocketHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData){
264 
265  unsigned sig = info.ssi_signo;
266  unsigned user = info.ssi_uid;
267 
268  logInfo("signal handler was called from user", user, "with signal ",sig);
269 
270  switch (sig)
271  {
272  /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */
273  case SIGTERM:
275  break;
276 
277  /* looks friendly, too, so lets take the long run */
278  case SIGHUP:
280  break;
281  default:
282  break;
283  }
284  },signalHandler,NULL);
285 
286  if(commandPluginDir.isSet())
287  {
288  listCommandPluginDirs.clear();
289  listCommandPluginDirs.push_back(commandPluginDir.getValue());
290  }
291 
292  if (additionalCommandPluginDirs.isSet())
293  {
294  listCommandPluginDirs.push_back(additionalCommandPluginDirs.getValue());
295  }
296 
297  if(routingPluginDir.isSet())
298  {
299  listRoutingPluginDirs.clear();
300  listRoutingPluginDirs.push_back(routingPluginDir.getValue());
301  }
302 
303  if (additionalRoutingPluginDirs.isSet())
304  {
305  listRoutingPluginDirs.push_back(additionalRoutingPluginDirs.getValue());
306  }
307 
308  //in this place, the plugins can get the gloval commandlineparser via CAmCommandLineSingleton::instance() and add their options to the commandline
309  //this must be done in the constructor.
310  //later when the plugins are started, the commandline is already parsed and the objects defined before can be used to get the neccesary information
311 
312  CAmDatabaseHandlerMap iDatabaseHandler;
313  IAmDatabaseHandler *pDatabaseHandler = dynamic_cast<IAmDatabaseHandler*>( &iDatabaseHandler );
314 
315  CAmRoutingSender iRoutingSender(listRoutingPluginDirs,pDatabaseHandler);
316  CAmCommandSender iCommandSender(listCommandPluginDirs, &iSocketHandler);
317  CAmControlSender iControlSender(controllerPlugin.getValue(),&iSocketHandler);
318 
319  try
320  {
321  //parse the commandline options
323  CAmCommandLineSingleton::instance()->parse(argc,argv);
324  if (currentSettings.getValue())
325  {
327  }
328  }
329  catch (TCLAP::ArgException &e) // catch any exceptions
330  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
331 
332  logInfo("The Audiomanager is started");
333  logInfo("The version of the Audiomanager", DAEMONVERSION);
334 
335 #ifdef WITH_CAPI_WRAPPER
336  //We instantiate a singleton with the current socket handler, which loads the common-api runtime.
337  CAmCommonAPIWrapper *pCAPIWrapper = CAmCommonAPIWrapper::instantiateOnce(&iSocketHandler, "AudioManager");
338 #endif /*WITH_CAPI_WRAPPER */
339 
340 #ifdef WITH_DBUS_WRAPPER
341  if (dbusWrapperTypeBool.getValue())
342  dbusWrapperType=DBUS_BUS_SYSTEM;
343  CAmDbusWrapper iDBusWrapper(&iSocketHandler,dbusWrapperType);
344 #endif /*WITH_DBUS_WRAPPER */
345 
346 #ifdef WITH_SYSTEMD_WATCHDOG
347  CAmWatchdog iWatchdog(&iSocketHandler);
348 #endif /*WITH_SYSTEMD_WATCHDOG*/
349 
350 CAmRouter iRouter(pDatabaseHandler, &iControlSender);
351 
352 #ifdef WITH_DBUS_WRAPPER
353  CAmCommandReceiver iCommandReceiver(pDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
354  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
355 #else /*WITH_DBUS_WRAPPER*/
356  CAmCommandReceiver iCommandReceiver(pDatabaseHandler,&iControlSender,&iSocketHandler);
357  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
358 #endif /*WITH_DBUS_WRAPPER*/
359 
360 CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
361 
362 iDatabaseHandler.registerObserver(&iRoutingSender);
363 iDatabaseHandler.registerObserver(&iCommandSender);
364 iDatabaseHandler.registerObserver(&iRouter);
365 //startup all the Plugins and Interfaces
366 //at this point, commandline arguments can be parsed
367 iControlSender.startupController(&iControlReceiver);
368 iCommandSender.startupInterfaces(&iCommandReceiver);
369 iRoutingSender.startupInterfaces(&iRoutingReceiver);
370 
371 //when the routingInterface is done, all plugins are loaded:
372 iControlSender.setControllerReady();
373 
374 #ifdef WITH_SYSTEMD_WATCHDOG
375  iWatchdog.startWatchdog();
376 #endif /*WITH_SYSTEMD_WATCHDOG*/
377 
378  //start the mainloop here....
379  iSocketHandler.start_listenting();
380 }
381 
388 int main(int argc, char *argv[], char** envp)
389 {
390  (void) envp;
391  listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
392  listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
393 
394  //critical signals are registered here:
395  struct sigaction signalAction;
396  memset(&signalAction, '\0', sizeof(signalAction));
397  signalAction.sa_sigaction = &signalHandler;
398  signalAction.sa_flags = SA_SIGINFO;
399  sigaction(SIGINT, &signalAction, NULL);
400  sigaction(SIGQUIT, &signalAction, NULL);
401 
402  //register new out of memory handler
403  std::set_new_handler(&OutOfMemoryHandler);
404 
405  sigset_t signal_mask;
406  sigemptyset(&signal_mask);
407  for (auto it : listOfSignalsFD)
408  {
409  sigaddset(&signal_mask, it);
410  }
411 
412  try
413  {
414  if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0)
415  {
416  throw std::runtime_error(std::string("Couldn't set mask for potential future threads"));
417  }
418 
419  //we do this to catch all exceptions and have a graceful ending just in case
420  mainProgram(argc,argv);
421  }
422 
423  catch (std::exception& exc)
424  {
425  logError("The AudioManager ended by throwing the exception", exc.what());
426  std::cerr<<"The AudioManager ended by throwing an exception "<<exc.what()<<std::endl;
427  exit(EXIT_FAILURE);
428  }
429 
430  close(fd0);
431  close(fd1);
432  close(fd2);
433  exit(0);
434 
435 }
436 
Implements the RoutingSendInterface.
int fd0
Definition: main.cpp:94
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")
void logWarning(T value, TArgs...args)
logs given values with warninglevel with the default context
A Common-API wrapper class, which loads the common-api runtime and instantiates all necessary objects...
am_Error_e startupInterfaces(CAmCommandReceiver *iCommandReceiver)
int main(int argc, char *argv[], char **envp)
main
Definition: main.cpp:388
void daemonize()
daemonizes the AudioManager
Definition: main.cpp:112
void logInfo(T value, TArgs...args)
logs given values with infolevel with the default context
Implements autorouting algorithm for connecting sinks and sources via different audio domains...
Definition: CAmRouter.h:159
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:162
#define AUDIOMANGER_APP_DESCRIPTION
Definition: main.cpp:68
uint16_t sh_pollHandle_t
this is a handle for a filedescriptor to be used with the SocketHandler
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
int fd2
Definition: main.cpp:94
Implements the Receiving side of the RoutingPlugins.
int fd1
Definition: main.cpp:94
SPDX license identifier: MPL-2.0.
SPDX license identifier: MPL-2.0.
void OutOfMemoryHandler()
the out of memory handler
Definition: main.cpp:103
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)
#define AUDIOMANGER_APP_ID
Definition: main.cpp:64
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.
bool registerObserver(IAmDatabaseObserver *iObserver)
std::vector< uint8_t > listOfSignalsFD
Definition: main.cpp:79
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::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:76
TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...", false)
This wraps dbus and provides everything needed to anyone who wants to use dbus (including plugins)...
SPDX license identifier: MPL-2.0.
no error - positive reply
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:75
void mainProgram(int argc, char *argv[])
Definition: main.cpp:216
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< std::string > controllerPlugin("c","controllerPlugin","use controllerPlugin full path with .so ending", false, CONTROLLER_PLUGIN_DIR,"string")