Bug 872907 - Patch 2: Implement SendSinkMessage in BluetoothService, r=echou, r=mrbkap
authorGina Yeh <gyeh@mozilla.com>
Sat, 08 Jun 2013 23:25:18 +0800
changeset 145971 d9d5d7de3e2cf18b730c222f1d11d43f8734be90
parent 145970 72653e055a56da634250db2c5a5cb2bfb97359ed
child 145972 b659ff61bce829cfc62469f8420b3cebb1e8f05a
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou, mrbkap
bugs872907
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 872907 - Patch 2: Implement SendSinkMessage in BluetoothService, r=echou, r=mrbkap
dom/bluetooth/BluetoothService.h
dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.h
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -278,16 +278,20 @@ public:
   ConnectSco(BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   DisconnectSco(BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   IsScoConnected(BluetoothReplyRunnable* aRunnable) = 0;
 
+  virtual nsresult
+  SendSinkMessage(const nsAString& aDeviceAddresses,
+                  const nsAString& aMessage) = 0;
+
   bool
   IsEnabled() const
   {
     return mEnabled;
   }
 
   bool
   IsToggling() const;
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -398,8 +398,16 @@ BluetoothServiceChildProcess::IsEnabledI
 }
 
 bool
 BluetoothServiceChildProcess::IsConnected(uint16_t aProfileId)
 {
   MOZ_NOT_REACHED("This should never be called!");
   return false;
 }
+
+nsresult
+BluetoothServiceChildProcess::SendSinkMessage(const nsAString& aDeviceAddresses,
+                                              const nsAString& aMessage)
+{
+  MOZ_NOT_REACHED("This should never be called!");
+  return NS_ERROR_FAILURE;
+}
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -147,16 +147,20 @@ public:
   ConnectSco(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   DisconnectSco(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   IsScoConnected(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
+  virtual nsresult
+  SendSinkMessage(const nsAString& aDeviceAddresses,
+                  const nsAString& aMessage) MOZ_OVERRIDE;
+
 protected:
   BluetoothServiceChildProcess();
   virtual ~BluetoothServiceChildProcess();
 
   void
   NoteDeadActor();
 
   void
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -55,20 +55,21 @@
  *   after DBUS_HANDLER_RESULT_HANDLED is returned from the filter.
  */
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
 #define B2G_AGENT_CAPABILITIES "DisplayYesNo"
-#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
-#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
-#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
-#define DBUS_AGENT_IFACE BLUEZ_DBUS_BASE_IFC ".Agent"
+#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC  ".Manager"
+#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC  ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC   ".Device"
+#define DBUS_AGENT_IFACE BLUEZ_DBUS_BASE_IFC    ".Agent"
+#define DBUS_SINK_IFACE BLUEZ_DBUS_BASE_IFC     ".AudioSink"
 #define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
 #define BLUEZ_DBUS_BASE_IFC       "org.bluez"
 #define BLUEZ_ERROR_IFC           "org.bluez.Error"
 
 #define PROP_DEVICE_CONNECTED_TYPE "org.bluez.device.conn.type"
 
 typedef struct {
   const char* name;
@@ -143,16 +144,17 @@ static const char* sBluetoothDBusSignals
 static nsAutoPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sPairingReqTable;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sAuthorizeReqTable;
 static int32_t sIsPairing = 0;
 static nsString sAdapterPath;
 
 typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 typedef bool (*FilterFunc)(const BluetoothValue&);
+typedef void (*SinkCallback)(DBusMessage*, void*);
 
 class RemoveDeviceTask : public nsRunnable {
 public:
   RemoveDeviceTask(const nsACString& aDeviceObjectPath,
                    BluetoothReplyRunnable* aRunnable)
     : mDeviceObjectPath(aDeviceObjectPath)
     , mRunnable(aRunnable)
   {
@@ -215,17 +217,18 @@ GetPairedDevicesFilter(const BluetoothVa
     if (deviceProperties[p].name().EqualsLiteral("Paired")) {
       return deviceProperties[p].value().get_bool();
     }
   }
 
   return false;
 }
 
-class SendDiscoveryTask : public nsRunnable {
+class SendDiscoveryTask : public nsRunnable
+{
 public:
   SendDiscoveryTask(const char* aMessageName,
                     BluetoothReplyRunnable* aRunnable)
     : mMessageName(aMessageName)
     , mRunnable(aRunnable)
   {
     MOZ_ASSERT(aMessageName);
     MOZ_ASSERT(aRunnable);
@@ -252,18 +255,18 @@ public:
     return NS_OK;
   }
 
 private:
   const char* mMessageName;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
-class DistributeBluetoothSignalTask : public nsRunnable {
-  BluetoothSignal mSignal;
+class DistributeBluetoothSignalTask : public nsRunnable
+{
 public:
   DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
     mSignal(aSignal)
   {
   }
 
   NS_IMETHOD
   Run()
@@ -272,19 +275,23 @@ public:
     BluetoothService* bs = BluetoothService::Get();
     if (!bs) {
       NS_WARNING("BluetoothService not available!");
       return NS_ERROR_FAILURE;
     }
     bs->DistributeSignal(mSignal);
     return NS_OK;
   }
+
+private:
+  BluetoothSignal mSignal;
 };
 
-class PrepareAdapterTask : public nsRunnable {
+class PrepareAdapterTask : public nsRunnable
+{
 public:
   PrepareAdapterTask(const nsAString& aPath) :
     mPath(aPath)
   {
   }
 
   NS_IMETHOD
   Run()
@@ -889,17 +896,17 @@ public:
       return NS_ERROR_FAILURE;
     }
 
     NS_DispatchToMainThread(new PrepareProfileManagersRunnable());
     return NS_OK;
   }
 };
 
-void
+static void
 RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
                 UnpackFunc aFunc)
 {
 #ifdef MOZ_WIDGET_GONK
   // Due to the fact that we're running two dbus loops on desktop implicitly by
   // being gtk based, sometimes we'll get signals/reply coming in on the main
   // thread. There's not a lot we can do about that for the time being and it
   // (technically) shouldn't hurt anything. However, on gonk, die.
@@ -911,120 +918,125 @@ RunDBusCallback(DBusMessage* aMsg, void*
   NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
 
   nsAutoString replyError;
   BluetoothValue v;
   aFunc(aMsg, nullptr, v, replyError);
   DispatchBluetoothReply(replyRunnable, v, replyError);
 }
 
-void
+static void
 GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   if (sIsPairing) {
     RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                     UnpackObjectPathMessage);
     PR_AtomicDecrement(&sIsPairing);
   }
 }
 
-void
+static void
 UnpackVoidMessage(DBusMessage* aMsg, DBusError* aErr, BluetoothValue& aValue,
                   nsAString& aErrorStr)
 {
   DBusError err;
   dbus_error_init(&err);
   if (!IsDBusMessageError(aMsg, aErr, aErrorStr) &&
       dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
       !dbus_message_get_args(aMsg, &err, DBUS_TYPE_INVALID)) {
     if (dbus_error_is_set(&err)) {
       aErrorStr = NS_ConvertUTF8toUTF16(err.message);
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
-  // XXXbent Need to figure out something better than this here.
-  if (aErrorStr.IsEmpty()) {
-    aValue = true;
-  }
+  aValue = aErrorStr.IsEmpty();
 }
 
-void
+static void
 GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackVoidMessage);
 }
 
-void
+static void
 GetIntCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackIntMessage);
 }
 
-bool
+#ifdef DEBUG
+static void
+CheckForSinkError(bool aConnect, DBusMessage* aMsg, void *aParam)
+{
+  BluetoothValue v;
+  nsAutoString replyError;
+  UnpackVoidMessage(aMsg, nullptr, v, replyError);
+  if (!v.get_bool()) {
+    if (aConnect) {
+      BT_WARNING("Failed to connect sink.");
+      return;
+    }
+    BT_WARNING("Failed to disconnect sink.");
+  }
+}
+#endif
+
+static void
+SinkConnectCallback(DBusMessage* aMsg, void* aParam)
+{
+#ifdef DEBUG
+  CheckForSinkError(true, aMsg, aParam);
+#endif
+}
+
+static void
+SinkDisconnectCallback(DBusMessage* aMsg, void* aParam)
+{
+#ifdef DEBUG
+  CheckForSinkError(false, aMsg, aParam);
+#endif
+}
+
+static bool
 IsDeviceConnectedTypeBoolean()
 {
 #if defined(MOZ_WIDGET_GONK)
   char connProp[PROPERTY_VALUE_MAX];
 
   property_get(PROP_DEVICE_CONNECTED_TYPE, connProp, "boolean");
   if (strcmp(connProp, "boolean") == 0) {
     return true;
   }
   return false;
 #else
   // Assume it's always a boolean on desktop. Fixing someday in Bug 806457.
   return true;
 #endif
 }
 
-void
-CopyProperties(Properties* inProp, Properties* outProp, int aPropertyTypeLen)
-{
-  int i;
-
-  for (i = 0; i < aPropertyTypeLen; i++) {
-    outProp[i].name = inProp[i].name;
-    outProp[i].type = inProp[i].type;
-  }
-}
-
-int
-GetPropertyIndex(Properties* prop, const char* propertyName,
-                 int aPropertyTypeLen)
-{
-  int i;
-
-  for (i = 0; i < aPropertyTypeLen; i++) {
-    if (!strncmp(propertyName, prop[i].name, strlen(propertyName))) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-bool
+static bool
 HasAudioService(uint32_t aCodValue)
 {
   return ((aCodValue & 0x200000) == 0x200000);
 }
 
-bool
+static bool
 ContainsIcon(const InfallibleTArray<BluetoothNamedValue>& aProperties)
 {
   for (uint8_t i = 0; i < aProperties.Length(); i++) {
     if (aProperties[i].name().EqualsLiteral("Icon")) {
       return true;
     }
   }
   return false;
 }
 
-bool
+static bool
 GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
             int aPropertyTypeLen, int* aPropIndex,
             InfallibleTArray<BluetoothNamedValue>& aProperties)
 {
   DBusMessageIter prop_val, array_val_iter;
   char* property = NULL;
   uint32_t array_type;
   int i, expectedType, receivedType;
@@ -1140,17 +1152,17 @@ GetProperty(DBusMessageIter aIter, Prope
     bool b = propertyValue.get_ArrayOfuint8_t()[0];
     propertyValue = BluetoothValue(b);
   }
 
   aProperties.AppendElement(BluetoothNamedValue(propertyName, propertyValue));
   return true;
 }
 
-void
+static void
 ParseProperties(DBusMessageIter* aIter,
                 BluetoothValue& aValue,
                 nsAString& aErrorStr,
                 Properties* aPropertyTypes,
                 const int aPropertyTypeLen)
 {
   DBusMessageIter dict_entry, dict;
   int prop_index = -1;
@@ -1171,17 +1183,17 @@ ParseProperties(DBusMessageIter* aIter,
       NS_WARNING("Can't create property!");
       return;
     }
   } while (dbus_message_iter_next(&dict));
 
   aValue = props;
 }
 
-void
+static void
 UnpackPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
                         BluetoothValue& aValue, nsAString& aErrorStr,
                         Properties* aPropertyTypes,
                         const int aPropertyTypeLen)
 {
   if (!IsDBusMessageError(aMsg, aErr, aErrorStr) &&
       dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
     DBusMessageIter iter;
@@ -1189,61 +1201,61 @@ UnpackPropertiesMessage(DBusMessage* aMs
       aErrorStr.AssignLiteral("Cannot create dbus message iter!");
     } else {
       ParseProperties(&iter, aValue, aErrorStr, aPropertyTypes,
                       aPropertyTypeLen);
     }
   }
 }
 
-void
+static void
 UnpackAdapterPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
                                BluetoothValue& aValue,
                                nsAString& aErrorStr)
 {
   UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sAdapterProperties,
                           ArrayLength(sAdapterProperties));
 }
 
-void
+static void
 UnpackDevicePropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
                               BluetoothValue& aValue,
                               nsAString& aErrorStr)
 {
   UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sDeviceProperties,
                           ArrayLength(sDeviceProperties));
 }
 
-void
+static void
 UnpackManagerPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
                                BluetoothValue& aValue,
                                nsAString& aErrorStr)
 {
   UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sManagerProperties,
                           ArrayLength(sManagerProperties));
 }
 
-void
+static void
 GetManagerPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackManagerPropertiesMessage);
 }
 
-void
+static void
 GetAdapterPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackAdapterPropertiesMessage);
 }
 
-void
+static void
 GetDevicePropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackDevicePropertiesMessage);
 }
 
 static DBusCallback sBluetoothDBusPropCallbacks[] =
 {
@@ -1251,17 +1263,17 @@ static DBusCallback sBluetoothDBusPropCa
   GetAdapterPropertiesCallback,
   GetDevicePropertiesCallback
 };
 
 MOZ_STATIC_ASSERT(
   sizeof(sBluetoothDBusPropCallbacks) == sizeof(sBluetoothDBusIfaces),
   "DBus Property callback array and DBus interface array must be same size");
 
-void
+static void
 ParsePropertyChange(DBusMessage* aMsg, BluetoothValue& aValue,
                     nsAString& aErrorStr, Properties* aPropertyTypes,
                     const int aPropertyTypeLen)
 {
   DBusMessageIter iter;
   DBusError err;
   int prop_index = -1;
   InfallibleTArray<BluetoothNamedValue> props;
@@ -1276,17 +1288,17 @@ ParsePropertyChange(DBusMessage* aMsg, B
                    &prop_index, props)) {
     NS_WARNING("Can't get property!");
     aErrorStr.AssignLiteral("Can't get property!");
     return;
   }
   aValue = props;
 }
 
-bool
+static bool
 GetPropertiesInternal(const nsAString& aPath,
                       const char* aIface,
                       BluetoothValue& aValue)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   nsAutoString replyError;
   DBusError err;
@@ -1318,18 +1330,17 @@ GetPropertiesInternal(const nsAString& a
   if (msg) {
     dbus_message_unref(msg);
   }
   return true;
 }
 
 // Called by dbus during WaitForAndDispatchEventNative()
 // This function is called on the IOThread
-static
-DBusHandlerResult
+static DBusHandlerResult
 EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
 
   if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
     BT_WARNING("%s: event handler not interested in %s (not a signal).\n",
         __FUNCTION__, dbus_message_get_member(aMsg));
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -1819,16 +1830,49 @@ BluetoothDBusService::SendDiscoveryMessa
     NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
+BluetoothDBusService::SendSinkMessage(const nsAString& aDeviceAddress,
+                                      const nsAString& aMessage)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mConnection);
+
+  NS_ENSURE_TRUE(IsReady(), NS_ERROR_FAILURE);
+
+  SinkCallback callback;
+  if (aMessage.EqualsLiteral("Connect")) {
+    callback = SinkConnectCallback;
+  } else if (aMessage.EqualsLiteral("Disconnect")) {
+    callback = SinkDisconnectCallback;
+  } else {
+    BT_WARNING("Unknown sink message");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsString objectPath = GetObjectPathFromAddress(sAdapterPath, aDeviceAddress);
+  bool ret = dbus_func_args_async(mConnection,
+                                  -1,
+                                  callback,
+                                  nullptr,
+                                  NS_ConvertUTF16toUTF8(objectPath).get(),
+                                  DBUS_SINK_IFACE,
+                                  NS_ConvertUTF16toUTF8(aMessage).get(),
+                                  DBUS_TYPE_INVALID);
+
+  NS_ENSURE_TRUE(ret, NS_ERROR_FAILURE);
+  return NS_OK;
+}
+
+nsresult
 BluetoothDBusService::StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable)
 {
   return SendDiscoveryMessage("StopDiscovery", aRunnable);
 }
 
 nsresult
 BluetoothDBusService::StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable)
 {
@@ -2176,17 +2220,17 @@ bool
 BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath,
                                     const nsAString& aDeviceAddress,
                                     nsAString& aDevicePath)
 {
   aDevicePath = GetObjectPathFromAddress(aAdapterPath, aDeviceAddress);
   return true;
 }
 
-int
+static int
 GetDeviceServiceChannel(const nsAString& aObjectPath,
                         const nsAString& aPattern,
                         int aAttributeId)
 {
   // This is a blocking call, should not be run on main thread.
   MOZ_ASSERT(!NS_IsMainThread());
 
 #ifdef MOZ_WIDGET_GONK
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -151,16 +151,20 @@ public:
   ConnectSco(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   DisconnectSco(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   IsScoConnected(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
+  virtual nsresult
+  SendSinkMessage(const nsAString& aDeviceAddresses,
+                  const nsAString& aMessage) MOZ_OVERRIDE;
+
 private:
   nsresult SendGetPropertyMessage(const nsAString& aPath,
                                   const char* aInterface,
                                   void (*aCB)(DBusMessage *, void *),
                                   BluetoothReplyRunnable* aRunnable);
   nsresult SendDiscoveryMessage(const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
   nsresult SendSetPropertyMessage(const char* aInterface,