AudioManager  7.6.6
Native Application Runtime Environment
CAmDbusWrapper.cpp
Go to the documentation of this file.
1 
24 #include "CAmDbusWrapper.h"
25 #include <audiomanagerconfig.h>
26 #include <fstream>
27 #include <sstream>
28 #include <string>
29 #include <cassert>
30 #include <cstdlib>
31 #include <stdexcept>
32 #include "CAmDltWrapper.h"
33 #include "CAmSocketHandler.h"
34 
35 namespace am
36 {
37 
41 #define ROOT_INTROSPECT_XML \
42 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
43 "<node>" \
44 "<interface name='org.AudioManager.freedesktop.DBus.Introspectable'>" \
45 "<method name='Introspect'>" \
46 " <arg name='xml_data' type='s' direction='out'/>" \
47 "</method>" \
48 "</interface>" \
49 
50 CAmDbusWrapper* CAmDbusWrapper::mpReference = NULL;
51 
52 CAmDbusWrapper::CAmDbusWrapper(CAmSocketHandler* socketHandler, DBusBusType type, const std::string& prefix, const std::string& objectPath) :
53  pDbusPrepareCallback(this,&CAmDbusWrapper::dbusPrepareCallback), //
54  pDbusDispatchCallback(this, &CAmDbusWrapper::dbusDispatchCallback), //
55  pDbusFireCallback(this, &CAmDbusWrapper::dbusFireCallback), //
56  pDbusCheckCallback(this, &CAmDbusWrapper::dbusCheckCallback), //
57  pDbusTimerCallback(this, &CAmDbusWrapper::dbusTimerCallback), //
58  mpDbusConnection(0), //
59  mDBusError(), //
60  mListNodes(), //
61  mpListTimerhandles(), //
62  mpSocketHandler(socketHandler), //
63  mDbusType(type)
64 {
65  assert(mpSocketHandler!=0);
66 
67  dbus_error_init(&mDBusError);
68 
69  if (!dbus_threads_init_default())
70  logError("CAmDbusWrapper::CAmDbusWrapper threads init call failed");
71 
72  logInfo("DBusWrapper::DBusWrapper Opening DBus connection of:", prefix, objectPath);
73  mpDbusConnection = dbus_bus_get(mDbusType, &mDBusError);
74  if (dbus_error_is_set(&mDBusError))
75  {
76  logError("DBusWrapper::DBusWrapper Error while getting the DBus");
77  dbus_error_free(&mDBusError);
78  }
79  if (NULL == mpDbusConnection)
80  {
81  logError("DBusWrapper::DBusWrapper DBus Connection is null");
82  }
83  else
84  {
85  logInfo("DBusWrapper::DBusWrapper DBus Connection is", mpDbusConnection);
86  }
87 
88  //then we need to adopt the dbus to our mainloop:
89  //first, we are old enought to live longer then the connection:
90  dbus_connection_set_exit_on_disconnect(mpDbusConnection, FALSE);
91 
92  //we do not need the manual dispatching, since it is not allowed to call from a different thread. So leave it uncommented:
93  //dbus_connection_set_dispatch_status_function
94 
95  //add watch functions:
96  dbus_bool_t watch = dbus_connection_set_watch_functions(mpDbusConnection, addWatch, removeWatch, toogleWatch, this, NULL);
97  if (!watch)
98  {
99  logError("DBusWrapper::DBusWrapper Registering of watch functions failed");
100  }
101 
102  //add timer functions:
103  dbus_bool_t timer = dbus_connection_set_timeout_functions(mpDbusConnection, addTimeout, removeTimeout, toggleTimeout, this, NULL);
104  if (!timer)
105  {
106  logError("DBusWrapper::DBusWrapper Registering of timer functions failed");
107  }
108 
109  if (prefix.empty() && objectPath.empty())
110  {
111  logInfo("DBusWrapper::DBusWrapper We don't register a connection object!");
112  return;
113  }
114 
115  //register callback for Introspectio
116  mObjectPathVTable.message_function = CAmDbusWrapper::cbRootIntrospection;
117  dbus_connection_register_object_path(mpDbusConnection, objectPath.c_str(), &mObjectPathVTable, this);
118  int ret = dbus_bus_request_name(mpDbusConnection, prefix.c_str(), DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
119  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == ret)
120  {
121  logInfo("DBusWrapper::DBusWrapper We own", prefix);
122  }
123  else
124  {
125  std::ostringstream sserror("DBusWrapper::DBusWrapper ");
126  switch (ret)
127  {
128  case -1:
129  sserror << "Couldn't acquire name " << prefix << ". DBus message: " << mDBusError.message;
130  dbus_error_free(&mDBusError);
131  break;
132  case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
133  sserror << "We are queued for " << prefix;
134  break;
135  case DBUS_REQUEST_NAME_REPLY_EXISTS:
136  sserror << ":-( " << prefix << " already exists!";
137  break;
138  case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
139  sserror << "Eh? We already own " << prefix;
140  break;
141  default:
142  sserror << "Unknown result = " << ret;
143  break;
144  }
145 
146  logError(sserror.str());
147  throw std::runtime_error(sserror.str().c_str());
148  }
149 }
150 
152 {
153  //close the connection again
154  logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
155  dbus_connection_unref(mpDbusConnection);
156 
157  //clean up all timerhandles we created but did not delete before
158  std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
159  for (; it != mpListTimerhandles.end(); ++it)
160  {
161  delete *it;
162  }
163 }
164 
173 void CAmDbusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata, const std::string& prefix)
174 {
175  logInfo("DBusWrapper::registerCallback register callback:", path);
176 
177  std::string completePath = prefix + "/" + path;
178  dbus_error_init(&mDBusError);
179  dbus_connection_register_object_path(mpDbusConnection, completePath.c_str(), vtable, userdata);
180  if (dbus_error_is_set(&mDBusError))
181  {
182  logError("DBusWrapper::registerCallack error: ", mDBusError.message);
183  dbus_error_free(&mDBusError);
184  }
185  mListNodes.push_back(path);
186 }
187 
194 void CAmDbusWrapper::registerSignalWatch(DBusHandleMessageFunction handler, const std::string& rule, void* userdata)
195 {
196  logInfo("DBusWrapper::registerSignalWatch register callback:", rule);
197  dbus_error_init(&mDBusError);
198  dbus_bus_add_match(mpDbusConnection, rule.c_str(), &mDBusError);
199  dbus_connection_flush(mpDbusConnection);
200  dbus_connection_add_filter(mpDbusConnection, handler, userdata, 0);
201 
202  if (dbus_error_is_set(&mDBusError))
203  {
204  logError("DBusWrapper::registerCallack error: ", mDBusError.message);
205  dbus_error_free(&mDBusError);
206  }
207 }
215 DBusHandlerResult CAmDbusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
216 {
217  //logInfo("DBusWrapper::~cbRootIntrospection called:");
218 
219  mpReference = (CAmDbusWrapper*) reference;
220  std::vector<std::string> nodesList = mpReference->mListNodes;
221  DBusMessage * reply;
222  DBusMessageIter args;
223  dbus_uint32_t serial = 0;
224  if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
225  {
226  std::vector<std::string>::iterator nodeIter = nodesList.begin();
227  const char *xml = ROOT_INTROSPECT_XML;
228  std::stringstream introspect;
229  introspect << std::string(xml);
230  for (; nodeIter != nodesList.end(); ++nodeIter)
231  {
232  introspect << "<node name='" << nodeIter->c_str() << "'/>";
233  }
234  introspect << "</node>";
235 
236  reply = dbus_message_new_method_return(msg);
237  std::string s = introspect.str();
238  const char* string = s.c_str();
239 
240  // add the arguments to the reply
241  dbus_message_iter_init_append(reply, &args);
242  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
243  {
244  logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
245  }
246 
247  // send the reply && flush the connection
248  if (!dbus_connection_send(conn, reply, &serial))
249  {
250  logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
251  }
252  dbus_connection_flush(conn);
253  // free the reply
254  dbus_message_unref(reply);
255 
256  return (DBUS_HANDLER_RESULT_HANDLED);
257  }
258  else
259  {
260  return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
261  }
262 }
263 
268 void CAmDbusWrapper::getDBusConnection(DBusConnection *& connection) const
269 {
270  connection = mpDbusConnection;
271 }
272 
273 dbus_bool_t CAmDbusWrapper::addWatch(DBusWatch *watch, void *userData)
274 {
275  mpReference = (CAmDbusWrapper*) userData;
276  assert(mpReference!=0);
277  return (mpReference->addWatchDelegate(watch, userData));
278 }
279 
280 dbus_bool_t CAmDbusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
281 {
282  (void) userData;
283  int16_t event = 0;
284  sh_pollHandle_t handle = 0;
285  uint flags = dbus_watch_get_flags(watch);
286 
287  /* no watch flags for disabled watches */
288  if (dbus_watch_get_enabled(watch))
289  {
290  if (flags & DBUS_WATCH_READABLE)
291  event |= POLLIN;
292  if (flags & DBUS_WATCH_WRITABLE)
293  event |= POLLOUT;
294 
295  logInfo("DBusWrapper::addWatchDelegate entered new watch, fd=", dbus_watch_get_unix_fd(watch), "event flag=", event);
296  am_Error_e error = mpSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, &pDbusPrepareCallback, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
297 
298  //if everything is alright, add the watch and the handle to our map so we know this relationship
299  if (error == E_OK && handle != 0)
300  {
301  mMapHandleWatch.insert(std::make_pair(watch, handle));
302  return (true);
303  }
304  logError("DBusWrapper::addWatchDelegate entering watch failed");
305  }
306  return (true);
307 }
308 
309 void CAmDbusWrapper::removeWatch(DBusWatch *watch, void *userData)
310 {
311  mpReference = (CAmDbusWrapper*) userData;
312  assert(mpReference!=0);
313  mpReference->removeWatchDelegate(watch, userData);
314 }
315 
316 void CAmDbusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
317 {
318  (void) userData;
319  std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
320  iterator = mMapHandleWatch.find(watch);
321  if (iterator != mMapHandleWatch.end())
322  {
323  mpSocketHandler->removeFDPoll(iterator->second);
324  logInfo("DBusWrapper::removeWatch removed watch with handle", iterator->second);
325  mMapHandleWatch.erase(iterator);
326  }
327  else
328  {
329  logError("DBusWrapper::removeWatch could not find handle !");
330  }
331 }
332 
333 void CAmDbusWrapper::toogleWatch(DBusWatch *watch, void *userData)
334 {
335  mpReference = (CAmDbusWrapper*) userData;
336  assert(mpReference!=0);
337  mpReference->toogleWatchDelegate(watch, userData);
338 }
339 
340 void CAmDbusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
341 {
342  (void) userData;
343  int16_t event = 0;
344  dbus_watch_get_unix_fd(watch);
345  uint flags = dbus_watch_get_flags(watch);
346  /* no watch flags for disabled watches */
347  if (dbus_watch_get_enabled(watch))
348  {
349  if (flags & DBUS_WATCH_READABLE)
350  event |= POLLIN;
351  if (flags & DBUS_WATCH_WRITABLE)
352  event |= POLLOUT;
353  }
354  std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
355  iterator = mMapHandleWatch.find(watch);
356  if (iterator != mMapHandleWatch.end())
357  mpSocketHandler->updateEventFlags(iterator->second, event);
358 }
359 
360 dbus_bool_t CAmDbusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
361 {
362  mpReference = (CAmDbusWrapper*) userData;
363  assert(mpReference!=0);
364  return (mpReference->addTimeoutDelegate(timeout, userData));
365 }
366 
367 dbus_bool_t CAmDbusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
368 {
369  (void)userData;
370 
371  if (!dbus_timeout_get_enabled(timeout))
372  return (false);
373 
374  //calculate the timeout in timeval
375  timespec pollTimeout;
376  int localTimeout = dbus_timeout_get_interval(timeout);
377  pollTimeout.tv_sec = localTimeout / 1000;
378  pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
379 
380  //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
381  sh_timerHandle_t* handle = new sh_timerHandle_t;
382  mpListTimerhandles.push_back(handle);
383 
384  //add the timer to the pollLoop
385  mpSocketHandler->addTimer(pollTimeout, &pDbusTimerCallback, *handle, timeout);
386 
387  //save the handle with dbus context
388  dbus_timeout_set_data(timeout, handle, NULL);
389 
390  return (true);
391 }
392 
393 void CAmDbusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
394 {
395  mpReference = (CAmDbusWrapper*) userData;
396  assert(mpReference!=0);
397  mpReference->removeTimeoutDelegate(timeout, userData);
398 }
399 
400 void CAmDbusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
401 {
402  (void) userData;
403  //get the pointer to the handle and remove the timer
404  sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
405  mpSocketHandler->removeTimer(*handle);
406 
407  //now go throught the timerlist and remove the pointer, free memory
408  std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
409  for (; it != mpListTimerhandles.end(); ++it)
410  {
411  if (*it == handle)
412  {
413  mpListTimerhandles.erase(it);
414  break;
415  }
416  }
417  delete handle;
418  }
419 
420 void CAmDbusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
421 {
422  mpReference = (CAmDbusWrapper*) userData;
423  assert(mpReference!=0);
424  mpReference->toggleTimeoutDelegate(timeout, userData);
425 }
426 
428 {
429  (void) handle;
430  (void) userData;
431  bool returnVal = true;
432  dbus_connection_ref(mpDbusConnection);
433  if (dbus_connection_dispatch(mpDbusConnection) == DBUS_DISPATCH_COMPLETE)
434  returnVal = false;
435  dbus_connection_unref(mpDbusConnection);
436  //logInfo("DBusWrapper::dbusDispatchCallback was called");
437  return (returnVal);
438 }
439 
440 bool am::CAmDbusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
441 {
442  (void) handle;
443  (void) userData;
444  bool returnVal = false;
445  dbus_connection_ref(mpDbusConnection);
446  if (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
447  returnVal = true;
448  dbus_connection_unref(mpDbusConnection);
449  //logInfo("DBusWrapper::dbusCheckCallback was called");
450  return (returnVal);
451 }
452 
453 void am::CAmDbusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
454 {
455  (void) handle;
456  (void) userData;
457  assert(userData!=NULL);
458  uint flags = 0;
459 
460  if (pollfd.revents & POLLIN)
461  flags |= DBUS_WATCH_READABLE;
462  if (pollfd.revents & POLLOUT)
463  flags |= DBUS_WATCH_WRITABLE;
464  if (pollfd.revents & POLLHUP)
465  flags |= DBUS_WATCH_HANGUP;
466  if (pollfd.revents & POLLERR)
467  flags |= DBUS_WATCH_ERROR;
468 
469  DBusWatch *watch = (DBusWatch*) userData;
470 
471  dbus_connection_ref(mpDbusConnection);
472  dbus_watch_handle(watch, flags);
473  dbus_connection_unref(mpDbusConnection);
474  //logInfo("DBusWrapper::dbusFireCallback was called");
475 }
476 
477 void CAmDbusWrapper::dbusPrepareCallback(const sh_pollHandle_t handle, void* userData)
478 {
479  (void) handle;
480  (void) userData;
481  dbus_connection_ref(mpDbusConnection);
482  while (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
483  {
484  dbus_connection_dispatch(mpDbusConnection);
485  //logInfo("prepare was neccessary!");
486  }
487  dbus_connection_unref(mpDbusConnection);
488 }
489 
490 void CAmDbusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
491 {
492  (void) userData;
493  //get the pointer to the handle and remove the timer
494  sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
495 
496  //stop or restart?
497  if (dbus_timeout_get_enabled(timeout))
498  {
499  //calculate the timeout in timeval
500  timespec pollTimeout;
501  int localTimeout = dbus_timeout_get_interval(timeout);
502  pollTimeout.tv_sec = localTimeout / 1000;
503  pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
504  mpSocketHandler->updateTimer(*handle, pollTimeout);
505  }
506  else
507  {
508  mpSocketHandler->stopTimer(*handle);
509  }
510 }
511 
513 {
514  assert(userData!=NULL);
515  for (auto && timerHandle : mpListTimerhandles)
516  {
517  if (*timerHandle == handle)
518  {
519  if (dbus_timeout_get_enabled((DBusTimeout*) userData))
520  {
521  mpSocketHandler->restartTimer(handle);
522  }
523  dbus_timeout_handle((DBusTimeout*) userData);
524  return;
525  }
526  }
527  logWarning("CAmDbusWrapper::dbusTimerCallback Unknown timer handle");
528 }
529 }
530 
void logWarning(T value, TArgs...args)
logs given values with warninglevel with the default context
void registerCallback(const DBusObjectPathVTable *vtable, const std::string &path, void *userdata, const std::string &prefix=DBUS_SERVICE_OBJECT_PATH)
registers a callback that is entered as path below the main path.
A Common-API wrapper class, which loads the common-api runtime and instantiates all necessary objects...
TAmShTimerCallBack< CAmDbusWrapper > pDbusTimerCallback
am_Error_e
the errors of the audiomanager.
void logInfo(T value, TArgs...args)
logs given values with infolevel with the default context
bool dbusDispatchCallback(const sh_pollHandle_t handle, void *userData)
am_Error_e restartTimer(const sh_timerHandle_t handle)
restarts a timer with the original value
void dbusTimerCallback(sh_timerHandle_t handle, void *userData)
TAmShPollFired< CAmDbusWrapper > pDbusFireCallback
The am::CAmSocketHandler implements a mainloop for the AudioManager.
static void toggleTimeout(DBusTimeout *timeout, void *userData)
TAmShPollPrepare< CAmDbusWrapper > pDbusPrepareCallback
uint16_t sh_pollHandle_t
this is a handle for a filedescriptor to be used with the SocketHandler
SPDX license identifier: MPL-2.0.
am_Error_e removeFDPoll(const sh_pollHandle_t handle)
removes a filedescriptor from the poll loop
am_Error_e removeTimer(const sh_timerHandle_t handle)
removes a timer from the list of timers
am_Error_e stopTimer(const sh_timerHandle_t handle)
stops a timer
static void toogleWatch(DBusWatch *watch, void *userData)
am_Error_e updateTimer(const sh_timerHandle_t handle, const timespec &timeouts)
restarts a timer and updates with a new interva
CAmDbusWrapper(CAmSocketHandler *socketHandler, DBusBusType type=DBUS_BUS_SESSION, const std::string &prefix=DBUS_SERVICE_PREFIX, const std::string &objectPath=DBUS_SERVICE_OBJECT_PATH)
am_Error_e updateEventFlags(const sh_pollHandle_t handle, const short events)
updates the eventFlags of a poll
void registerSignalWatch(DBusHandleMessageFunction handler, const std::string &rule, void *userdata)
register signal watch callback to matching rule
TAmShPollDispatch< CAmDbusWrapper > pDbusDispatchCallback
am_Error_e addFDPoll(const int fd, const short event, std::function< void(const sh_pollHandle_t handle, void *userData)> prepare, std::function< void(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)> fired, std::function< bool(const sh_pollHandle_t handle, void *userData)> check, std::function< bool(const sh_pollHandle_t handle, void *userData)> dispatch, void *userData, sh_pollHandle_t &handle)
Adds a filedescriptor to the polling loop.
SPDX license identifier: MPL-2.0.
#define ROOT_INTROSPECT_XML
introspectio header
bool dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
void logError(T value, TArgs...args)
logs given values with errorlevel with the default context
static void removeWatch(DBusWatch *watch, void *userData)
This wraps dbus and provides everything needed to anyone who wants to use dbus (including plugins)...
no error - positive reply
static dbus_bool_t addTimeout(DBusTimeout *timeout, void *userData)
static dbus_bool_t addWatch(DBusWatch *watch, void *userData)
void dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
static void removeTimeout(DBusTimeout *timeout, void *userData)
void getDBusConnection(DBusConnection *&connection) const
returns the dbus connection
SPDX license identifier: MPL-2.0.
TAmShPollCheck< CAmDbusWrapper > pDbusCheckCallback
void dbusPrepareCallback(const sh_pollHandle_t handle, void *userData)
sh_pollHandle_t sh_timerHandle_t
this is a handle for a timer to be used with the SocketHandler
am_Error_e addTimer(const timespec &timeouts, IAmShTimerCallBack *callback, sh_timerHandle_t &handle, void *userData, const bool __attribute__((__unused__)) repeats=false)