AudioManager  7.5.11
Native Application Runtime Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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  //register callback for Introspectio
110  mObjectPathVTable.message_function = CAmDbusWrapper::cbRootIntrospection;
111  dbus_connection_register_object_path(mpDbusConnection, objectPath.c_str(), &mObjectPathVTable, this);
112  int ret = dbus_bus_request_name(mpDbusConnection, prefix.c_str(), DBUS_NAME_FLAG_DO_NOT_QUEUE, &mDBusError);
113  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == ret)
114  {
115  logInfo("DBusWrapper::DBusWrapper We own", prefix);
116  }
117  else
118  {
119  std::ostringstream sserror("DBusWrapper::DBusWrapper ");
120  switch (ret)
121  {
122  case -1:
123  sserror << "Couldn't acquire name " << prefix << ". DBus message: " << mDBusError.message;
124  dbus_error_free(&mDBusError);
125  break;
126  case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
127  sserror << "We are queued for " << prefix;
128  break;
129  case DBUS_REQUEST_NAME_REPLY_EXISTS:
130  sserror << ":-( " << prefix << " already exists!";
131  break;
132  case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
133  sserror << "Eh? We already own " << prefix;
134  break;
135  default:
136  sserror << "Unknown result = " << ret;
137  break;
138  }
139 
140  logError(sserror.str());
141  throw std::runtime_error(sserror.str().c_str());
142  }
143 }
144 
146 {
147  //close the connection again
148  logInfo("DBusWrapper::~DBusWrapper Closing DBus connection");
149  dbus_connection_unref(mpDbusConnection);
150 
151  //clean up all timerhandles we created but did not delete before
152  std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
153  for (; it != mpListTimerhandles.end(); ++it)
154  {
155  delete *it;
156  }
157 }
158 
167 void CAmDbusWrapper::registerCallback(const DBusObjectPathVTable* vtable, const std::string& path, void* userdata, const std::string& prefix)
168 {
169  logInfo("DBusWrapper::registerCallback register callback:", path);
170 
171  std::string completePath = prefix + "/" + path;
172  dbus_error_init(&mDBusError);
173  mpDbusConnection = dbus_bus_get(mDbusType, &mDBusError);
174  dbus_connection_register_object_path(mpDbusConnection, completePath.c_str(), vtable, userdata);
175  if (dbus_error_is_set(&mDBusError))
176  {
177  logError("DBusWrapper::registerCallack error: ", mDBusError.message);
178  dbus_error_free(&mDBusError);
179  }
180  mListNodes.push_back(path);
181 }
182 
189 void CAmDbusWrapper::registerSignalWatch(DBusHandleMessageFunction handler, const std::string& rule, void* userdata)
190 {
191  logInfo("DBusWrapper::registerSignalWatch register callback:", rule);
192  dbus_error_init(&mDBusError);
193  mpDbusConnection = dbus_bus_get(mDbusType, &mDBusError);
194  dbus_bus_add_match(mpDbusConnection, rule.c_str(), &mDBusError);
195  dbus_connection_flush(mpDbusConnection);
196  dbus_connection_add_filter(mpDbusConnection, handler, userdata, 0);
197 
198  if (dbus_error_is_set(&mDBusError))
199  {
200  logError("DBusWrapper::registerCallack error: ", mDBusError.message);
201  dbus_error_free(&mDBusError);
202  }
203 }
211 DBusHandlerResult CAmDbusWrapper::cbRootIntrospection(DBusConnection *conn, DBusMessage *msg, void *reference)
212 {
213  //logInfo("DBusWrapper::~cbRootIntrospection called:");
214 
215  mpReference = (CAmDbusWrapper*) reference;
216  std::vector<std::string> nodesList = mpReference->mListNodes;
217  DBusMessage * reply;
218  DBusMessageIter args;
219  dbus_uint32_t serial = 0;
220  if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
221  {
222  std::vector<std::string>::iterator nodeIter = nodesList.begin();
223  const char *xml = ROOT_INTROSPECT_XML;
224  std::stringstream introspect;
225  introspect << std::string(xml);
226  for (; nodeIter != nodesList.end(); ++nodeIter)
227  {
228  introspect << "<node name='" << nodeIter->c_str() << "'/>";
229  }
230  introspect << "</node>";
231 
232  reply = dbus_message_new_method_return(msg);
233  std::string s = introspect.str();
234  const char* string = s.c_str();
235 
236  // add the arguments to the reply
237  dbus_message_iter_init_append(reply, &args);
238  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &string))
239  {
240  logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
241  }
242 
243  // send the reply && flush the connection
244  if (!dbus_connection_send(conn, reply, &serial))
245  {
246  logError("DBusWrapper::~cbRootIntrospection DBUS Out Of Memory!");
247  }
248  dbus_connection_flush(conn);
249  // free the reply
250  dbus_message_unref(reply);
251 
252  return (DBUS_HANDLER_RESULT_HANDLED);
253  }
254  else
255  {
256  return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
257  }
258 }
259 
264 void CAmDbusWrapper::getDBusConnection(DBusConnection *& connection) const
265 {
266  connection = mpDbusConnection;
267 }
268 
269 dbus_bool_t CAmDbusWrapper::addWatch(DBusWatch *watch, void *userData)
270 {
271  mpReference = (CAmDbusWrapper*) userData;
272  assert(mpReference!=0);
273  return (mpReference->addWatchDelegate(watch, userData));
274 }
275 
276 dbus_bool_t CAmDbusWrapper::addWatchDelegate(DBusWatch * watch, void* userData)
277 {
278  (void) userData;
279  int16_t event = 0;
280  sh_pollHandle_t handle = 0;
281  uint flags = dbus_watch_get_flags(watch);
282 
283  /* no watch flags for disabled watches */
284  if (dbus_watch_get_enabled(watch))
285  {
286  if (flags & DBUS_WATCH_READABLE)
287  event |= POLLIN;
288  if (flags & DBUS_WATCH_WRITABLE)
289  event |= POLLOUT;
290  }
291 
292  logInfo("DBusWrapper::addWatchDelegate entered new watch, fd=", dbus_watch_get_unix_fd(watch), "event flag=", event);
293  am_Error_e error = mpSocketHandler->addFDPoll(dbus_watch_get_unix_fd(watch), event, &pDbusPrepareCallback, &pDbusFireCallback, &pDbusCheckCallback, &pDbusDispatchCallback, watch, handle);
294 
295  //if everything is alright, add the watch and the handle to our map so we know this relationship
296  if (error == E_OK && handle != 0)
297  {
298  mMapHandleWatch.insert(std::make_pair(watch, handle));
299  return (true);
300  }
301  logError("DBusWrapper::addWatchDelegate entering watch failed");
302  return (true);
303 }
304 
305 void CAmDbusWrapper::removeWatch(DBusWatch *watch, void *userData)
306 {
307  mpReference = (CAmDbusWrapper*) userData;
308  assert(mpReference!=0);
309  mpReference->removeWatchDelegate(watch, userData);
310 }
311 
312 void CAmDbusWrapper::removeWatchDelegate(DBusWatch *watch, void *userData)
313 {
314  (void) userData;
315  std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
316  iterator = mMapHandleWatch.find(watch);
317  if (iterator != mMapHandleWatch.end())
318  {
319  mpSocketHandler->removeFDPoll(iterator->second);
320  logInfo("DBusWrapper::removeWatch removed watch with handle", iterator->second);
321  mMapHandleWatch.erase(iterator);
322  }
323  else
324  {
325  logError("DBusWrapper::removeWatch could not find handle !");
326  }
327 }
328 
329 void CAmDbusWrapper::toogleWatch(DBusWatch *watch, void *userData)
330 {
331  mpReference = (CAmDbusWrapper*) userData;
332  assert(mpReference!=0);
333  mpReference->toogleWatchDelegate(watch, userData);
334 }
335 
336 void CAmDbusWrapper::toogleWatchDelegate(DBusWatch *watch, void *userData)
337 {
338  (void) userData;
339  int16_t event = 0;
340  dbus_watch_get_unix_fd(watch);
341  uint flags = dbus_watch_get_flags(watch);
342  /* no watch flags for disabled watches */
343  if (dbus_watch_get_enabled(watch))
344  {
345  if (flags & DBUS_WATCH_READABLE)
346  event |= POLLIN;
347  if (flags & DBUS_WATCH_WRITABLE)
348  event |= POLLOUT;
349  }
350  std::map<DBusWatch*, sh_pollHandle_t>::iterator iterator = mMapHandleWatch.begin();
351  iterator = mMapHandleWatch.find(watch);
352  if (iterator != mMapHandleWatch.end())
353  mpSocketHandler->updateEventFlags(iterator->second, event);
354 }
355 
356 dbus_bool_t CAmDbusWrapper::addTimeout(DBusTimeout *timeout, void* userData)
357 {
358  mpReference = (CAmDbusWrapper*) userData;
359  assert(mpReference!=0);
360  return (mpReference->addTimeoutDelegate(timeout, userData));
361 }
362 
363 dbus_bool_t CAmDbusWrapper::addTimeoutDelegate(DBusTimeout *timeout, void* userData)
364 {
365  (void)userData;
366 
367  if (!dbus_timeout_get_enabled(timeout))
368  return (false);
369 
370  //calculate the timeout in timeval
371  timespec pollTimeout;
372  int localTimeout = dbus_timeout_get_interval(timeout);
373  pollTimeout.tv_sec = localTimeout / 1000;
374  pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
375 
376  //prepare handle and callback. new is eval, but there is no other choice because we need the pointer!
377  sh_timerHandle_t* handle = new sh_timerHandle_t;
378  mpListTimerhandles.push_back(handle);
379 
380  //add the timer to the pollLoop
381  mpSocketHandler->addTimer(pollTimeout, &pDbusTimerCallback, *handle, timeout);
382 
383  //save the handle with dbus context
384  dbus_timeout_set_data(timeout, handle, NULL);
385 
386  //save timeout in Socket context
387  userData = timeout;
388  return (true);
389 }
390 
391 void CAmDbusWrapper::removeTimeout(DBusTimeout *timeout, void* userData)
392 {
393  mpReference = (CAmDbusWrapper*) userData;
394  assert(mpReference!=0);
395  mpReference->removeTimeoutDelegate(timeout, userData);
396 }
397 
398 void CAmDbusWrapper::removeTimeoutDelegate(DBusTimeout *timeout, void* userData)
399 {
400  (void) userData;
401  //get the pointer to the handle and remove the timer
402  sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
403  mpSocketHandler->removeTimer(*handle);
404 
405  //now go throught the timerlist and remove the pointer, free memory
406  std::vector<sh_timerHandle_t*>::iterator it = mpListTimerhandles.begin();
407  for (; it != mpListTimerhandles.end(); ++it)
408  {
409  if (*it == handle)
410  {
411  mpListTimerhandles.erase(it);
412  break;
413  }
414  }
415  delete handle;
416  }
417 
418 void CAmDbusWrapper::toggleTimeout(DBusTimeout *timeout, void* userData)
419 {
420  mpReference = (CAmDbusWrapper*) userData;
421  assert(mpReference!=0);
422  mpReference->toggleTimeoutDelegate(timeout, userData);
423 }
424 
426 {
427  (void) handle;
428  (void) userData;
429  bool returnVal = true;
430  dbus_connection_ref(mpDbusConnection);
431  if (dbus_connection_dispatch(mpDbusConnection) == DBUS_DISPATCH_COMPLETE)
432  returnVal = false;
433  dbus_connection_unref(mpDbusConnection);
434  //logInfo("DBusWrapper::dbusDispatchCallback was called");
435  return (returnVal);
436 }
437 
438 bool am::CAmDbusWrapper::dbusCheckCallback(const sh_pollHandle_t handle, void *userData)
439 {
440  (void) handle;
441  (void) userData;
442  bool returnVal = false;
443  dbus_connection_ref(mpDbusConnection);
444  if (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
445  returnVal = true;
446  dbus_connection_unref(mpDbusConnection);
447  //logInfo("DBusWrapper::dbusCheckCallback was called");
448  return (returnVal);
449 }
450 
451 void am::CAmDbusWrapper::dbusFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
452 {
453  (void) handle;
454  (void) userData;
455  assert(userData!=NULL);
456  uint flags = 0;
457 
458  if (pollfd.revents & POLLIN)
459  flags |= DBUS_WATCH_READABLE;
460  if (pollfd.revents & POLLOUT)
461  flags |= DBUS_WATCH_WRITABLE;
462  if (pollfd.revents & POLLHUP)
463  flags |= DBUS_WATCH_HANGUP;
464  if (pollfd.revents & POLLERR)
465  flags |= DBUS_WATCH_ERROR;
466 
467  DBusWatch *watch = (DBusWatch*) userData;
468 
469  dbus_connection_ref(mpDbusConnection);
470  dbus_watch_handle(watch, flags);
471  dbus_connection_unref(mpDbusConnection);
472  //logInfo("DBusWrapper::dbusFireCallback was called");
473 }
474 
475 void CAmDbusWrapper::dbusPrepareCallback(const sh_pollHandle_t handle, void* userData)
476 {
477  (void) handle;
478  (void) userData;
479  dbus_connection_ref(mpDbusConnection);
480  while (dbus_connection_get_dispatch_status(mpDbusConnection) == DBUS_DISPATCH_DATA_REMAINS)
481  {
482  dbus_connection_dispatch(mpDbusConnection);
483  //logInfo("prepare was neccessary!");
484  }
485  dbus_connection_unref(mpDbusConnection);
486 }
487 
488 void CAmDbusWrapper::toggleTimeoutDelegate(DBusTimeout *timeout, void* userData)
489 {
490  (void) userData;
491  //get the pointer to the handle and remove the timer
492  sh_timerHandle_t* handle = (sh_timerHandle_t*) dbus_timeout_get_data(timeout);
493 
494  //stop or restart?
495  if (dbus_timeout_get_enabled(timeout))
496  {
497  //calculate the timeout in timeval
498  timespec pollTimeout;
499  int localTimeout = dbus_timeout_get_interval(timeout);
500  pollTimeout.tv_sec = localTimeout / 1000;
501  pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000;
502  mpSocketHandler->updateTimer(*handle, pollTimeout);
503  }
504  else
505  {
506  mpSocketHandler->stopTimer(*handle);
507  }
508 }
509 
511 {
512  assert(userData!=NULL);
513  if (dbus_timeout_get_enabled((DBusTimeout*) userData))
514  {
515  mpSocketHandler->restartTimer(handle);
516  }
517  dbus_timeout_handle((DBusTimeout*) userData);
518 }
519 }
520 
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.
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
am_Error_e addTimer(const timespec timeouts, IAmShTimerCallBack *callback, sh_timerHandle_t &handle, void *userData)
adds a timer to the list of timers.
SPDX license identifier: MPL-2.0.
am_Error_e removeFDPoll(const sh_pollHandle_t handle)
removes a filedescriptor from the poll loop
uint16_t sh_timerHandle_t
this is a handle for a timer to be used with the SocketHandler
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
am_Error_e addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t &handle)
Adds a filedescriptor to the polling loop.
static void toogleWatch(DBusWatch *watch, void *userData)
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 updateTimer(const sh_timerHandle_t handle, const timespec timeouts)
restarts a timer and updates with a new interva
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)