diff --git a/CLOBBER b/CLOBBER index d4cdfaff33de..9220f8255f4d 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Merge day clobber \ No newline at end of file +Bug 1061489: Updated moz.build requires CLOBBER diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index d773de2ffd6b..7f436d10e014 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 6163a8f3a311..c6a8cb1953d2 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index b863e1fa4119..5fb8555c43d7 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 9b746f7ca91d..9a55cd46ab14 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 6163a8f3a311..c6a8cb1953d2 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index c2c39ba45626..4be1ac7764d2 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 4eed4efd9a55..f55bedfb21d1 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 9580cde62437..7ca4c78c0363 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "d39431f7b119e5cac505e63375ba929ac72eb681", + "revision": "62c1693326443d61bfa405d41d95d05281053cfa", "repo_path": "/integration/gaia-central" } diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 92d706d507c6..362a0a4c7332 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index a5c2006a8959..83fbeeaf7271 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 6412839d65ff..78dd1c530bd5 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 64791cc1eda9..82cb97e650aa 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/dom/bluetooth/BluetoothInterface.cpp b/dom/bluetooth/BluetoothInterface.cpp new file mode 100644 index 000000000000..6dccf5fb4f54 --- /dev/null +++ b/dom/bluetooth/BluetoothInterface.cpp @@ -0,0 +1,109 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothInterface.h" +#ifdef MOZ_B2G_BT_BLUEDROID +#include "BluetoothHALInterface.h" +#endif + +BEGIN_BLUETOOTH_NAMESPACE + +// +// Socket Interface +// + +BluetoothSocketInterface::~BluetoothSocketInterface() +{ } + +// +// Handsfree Interface +// + +// Notification handling +// + +BluetoothHandsfreeNotificationHandler:: + ~BluetoothHandsfreeNotificationHandler() +{ } + +// Interface +// + +BluetoothHandsfreeInterface::BluetoothHandsfreeInterface() +{ } + +BluetoothHandsfreeInterface::~BluetoothHandsfreeInterface() +{ } + +// +// Bluetooth Advanced Audio Interface +// + +// Notification handling +// + +BluetoothA2dpNotificationHandler::~BluetoothA2dpNotificationHandler() +{ } + +// Interface +// + +BluetoothA2dpInterface::BluetoothA2dpInterface() +{ } + +BluetoothA2dpInterface::~BluetoothA2dpInterface() +{ } + +// +// Bluetooth AVRCP Interface +// + +// Notification handling +// + +BluetoothAvrcpNotificationHandler::~BluetoothAvrcpNotificationHandler() +{ } + +// Interface +// + +BluetoothAvrcpInterface::BluetoothAvrcpInterface() +{ } + +BluetoothAvrcpInterface::~BluetoothAvrcpInterface() +{ } + +// Notification handling +// + +BluetoothNotificationHandler::~BluetoothNotificationHandler() +{ } + +// Interface +// + +BluetoothInterface* +BluetoothInterface::GetInstance() +{ + /* Here's where we decide which implementation to use. Currently + * there is only Bluedroid, but others are possible. Having multiple + * interfaces built-in and selecting the correct one at runtime could + * also be an option. + */ +#ifdef MOZ_B2G_BT_BLUEDROID + return BluetoothHALInterface::GetInstance(); +#else + return nullptr; +#endif +} + +BluetoothInterface::BluetoothInterface() +{ } + +BluetoothInterface::~BluetoothInterface() +{ } + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothInterface.h b/dom/bluetooth/BluetoothInterface.h similarity index 53% rename from dom/bluetooth/bluedroid/BluetoothInterface.h rename to dom/bluetooth/BluetoothInterface.h index 6acfc20a2f8d..29b8138a5e7e 100644 --- a/dom/bluetooth/bluedroid/BluetoothInterface.h +++ b/dom/bluetooth/BluetoothInterface.h @@ -4,23 +4,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothinterface_h__ -#define mozilla_dom_bluetooth_bluedroid_bluetoothinterface_h__ +#ifndef mozilla_dom_bluetooth_bluetoothinterface_h__ +#define mozilla_dom_bluetooth_bluetoothinterface_h__ -#include -#include -#include -#include -#if ANDROID_VERSION >= 18 -#include -#endif #include "BluetoothCommon.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" BEGIN_BLUETOOTH_NAMESPACE -class BluetoothInterface; - // // Socket Interface // @@ -47,30 +38,24 @@ public: class BluetoothSocketInterface { public: - friend class BluetoothInterface; - // Init and Cleanup is handled by BluetoothInterface - void Listen(BluetoothSocketType aType, - const nsAString& aServiceName, - const uint8_t aServiceUuid[16], - int aChannel, bool aEncrypt, bool aAuth, - BluetoothSocketResultHandler* aRes); + virtual void Listen(BluetoothSocketType aType, + const nsAString& aServiceName, + const uint8_t aServiceUuid[16], + int aChannel, bool aEncrypt, bool aAuth, + BluetoothSocketResultHandler* aRes) = 0; - void Connect(const nsAString& aBdAddr, - BluetoothSocketType aType, - const uint8_t aUuid[16], - int aChannel, bool aEncrypt, bool aAuth, - BluetoothSocketResultHandler* aRes); + virtual void Connect(const nsAString& aBdAddr, + BluetoothSocketType aType, + const uint8_t aUuid[16], + int aChannel, bool aEncrypt, bool aAuth, + BluetoothSocketResultHandler* aRes) = 0; - void Accept(int aFd, BluetoothSocketResultHandler* aRes); + virtual void Accept(int aFd, BluetoothSocketResultHandler* aRes) = 0; protected: - BluetoothSocketInterface(const btsock_interface_t* aInterface); - ~BluetoothSocketInterface(); - -private: - const btsock_interface_t* mInterface; + virtual ~BluetoothSocketInterface(); }; // @@ -191,74 +176,70 @@ public: class BluetoothHandsfreeInterface { public: - friend class BluetoothInterface; - - void Init(BluetoothHandsfreeNotificationHandler* aNotificationHandler, - BluetoothHandsfreeResultHandler* aRes); - void Cleanup(BluetoothHandsfreeResultHandler* aRes); + virtual void Init( + BluetoothHandsfreeNotificationHandler* aNotificationHandler, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void Cleanup(BluetoothHandsfreeResultHandler* aRes) = 0; /* Connect / Disconnect */ - void Connect(const nsAString& aBdAddr, - BluetoothHandsfreeResultHandler* aRes); - void Disconnect(const nsAString& aBdAddr, - BluetoothHandsfreeResultHandler* aRes); - void ConnectAudio(const nsAString& aBdAddr, - BluetoothHandsfreeResultHandler* aRes); - void DisconnectAudio(const nsAString& aBdAddr, - BluetoothHandsfreeResultHandler* aRes); + virtual void Connect(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void Disconnect(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void ConnectAudio(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void DisconnectAudio(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes) = 0; /* Voice Recognition */ - void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes); - void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes); + virtual void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes) = 0; /* Volume */ - void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume, - BluetoothHandsfreeResultHandler* aRes); + virtual void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume, + BluetoothHandsfreeResultHandler* aRes) = 0; /* Device status */ - void DeviceStatusNotification(BluetoothHandsfreeNetworkState aNtkState, - BluetoothHandsfreeServiceType aSvcType, - int aSignal, int aBattChg, - BluetoothHandsfreeResultHandler* aRes); + virtual void DeviceStatusNotification( + BluetoothHandsfreeNetworkState aNtkState, + BluetoothHandsfreeServiceType aSvcType, + int aSignal, int aBattChg, BluetoothHandsfreeResultHandler* aRes) = 0; /* Responses */ - void CopsResponse(const char* aCops, - BluetoothHandsfreeResultHandler* aRes); - void CindResponse(int aSvc, int aNumActive, int aNumHeld, - BluetoothHandsfreeCallState aCallSetupState, int aSignal, - int aRoam, int aBattChg, - BluetoothHandsfreeResultHandler* aRes); - void FormattedAtResponse(const char* aRsp, - BluetoothHandsfreeResultHandler* aRes); - void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode, - BluetoothHandsfreeResultHandler* aRes); - void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir, - BluetoothHandsfreeCallState aState, - BluetoothHandsfreeCallMode aMode, - BluetoothHandsfreeCallMptyType aMpty, - const nsAString& aNumber, - BluetoothHandsfreeCallAddressType aType, - BluetoothHandsfreeResultHandler* aRes); + virtual void CopsResponse(const char* aCops, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void CindResponse(int aSvc, int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, + int aSignal, int aRoam, int aBattChg, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void FormattedAtResponse(const char* aRsp, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode, + BluetoothHandsfreeResultHandler* aRes) = 0; + virtual void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir, + BluetoothHandsfreeCallState aState, + BluetoothHandsfreeCallMode aMode, + BluetoothHandsfreeCallMptyType aMpty, + const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes) = 0; /* Phone State */ - void PhoneStateChange(int aNumActive, int aNumHeld, - BluetoothHandsfreeCallState aCallSetupState, - const nsAString& aNumber, - BluetoothHandsfreeCallAddressType aType, - BluetoothHandsfreeResultHandler* aRes); + virtual void PhoneStateChange(int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, + const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes) = 0; protected: - BluetoothHandsfreeInterface(const bthf_interface_t* aInterface); - ~BluetoothHandsfreeInterface(); - -private: - const bthf_interface_t* mInterface; + BluetoothHandsfreeInterface(); + virtual ~BluetoothHandsfreeInterface(); }; // @@ -306,23 +287,18 @@ public: class BluetoothA2dpInterface { public: - friend class BluetoothInterface; + virtual void Init(BluetoothA2dpNotificationHandler* aNotificationHandler, + BluetoothA2dpResultHandler* aRes) = 0; + virtual void Cleanup(BluetoothA2dpResultHandler* aRes) = 0; - void Init(BluetoothA2dpNotificationHandler* aNotificationHandler, - BluetoothA2dpResultHandler* aRes); - void Cleanup(BluetoothA2dpResultHandler* aRes); - - void Connect(const nsAString& aBdAddr, - BluetoothA2dpResultHandler* aRes); - void Disconnect(const nsAString& aBdAddr, - BluetoothA2dpResultHandler* aRes); + virtual void Connect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes) = 0; + virtual void Disconnect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes) = 0; protected: - BluetoothA2dpInterface(const btav_interface_t* aInterface); - ~BluetoothA2dpInterface(); - -private: - const btav_interface_t* mInterface; + BluetoothA2dpInterface(); + virtual ~BluetoothA2dpInterface(); }; // @@ -428,61 +404,50 @@ public: class BluetoothAvrcpInterface { public: - friend class BluetoothInterface; + virtual void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler, + BluetoothAvrcpResultHandler* aRes) = 0; + virtual void Cleanup(BluetoothAvrcpResultHandler* aRes) = 0; - void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler, - BluetoothAvrcpResultHandler* aRes); - void Cleanup(BluetoothAvrcpResultHandler* aRes); + virtual void GetPlayStatusRsp(ControlPlayStatus aPlayStatus, + uint32_t aSongLen, uint32_t aSongPos, + BluetoothAvrcpResultHandler* aRes) = 0; - void GetPlayStatusRsp(ControlPlayStatus aPlayStatus, - uint32_t aSongLen, uint32_t aSongPos, - BluetoothAvrcpResultHandler* aRes); - - void ListPlayerAppAttrRsp(int aNumAttr, - const BluetoothAvrcpPlayerAttribute* aPAttrs, - BluetoothAvrcpResultHandler* aRes); - void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals, - BluetoothAvrcpResultHandler* aRes); + virtual void ListPlayerAppAttrRsp( + int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs, + BluetoothAvrcpResultHandler* aRes) = 0; + virtual void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals, + BluetoothAvrcpResultHandler* aRes) = 0; /* TODO: redesign this interface once we actually use it */ - void GetPlayerAppValueRsp(uint8_t aNumAttrs, - const uint8_t* aIds, const uint8_t* aValues, - BluetoothAvrcpResultHandler* aRes); + virtual void GetPlayerAppValueRsp(uint8_t aNumAttrs, const uint8_t* aIds, + const uint8_t* aValues, + BluetoothAvrcpResultHandler* aRes) = 0; /* TODO: redesign this interface once we actually use it */ - void GetPlayerAppAttrTextRsp(int aNumAttr, - const uint8_t* aIds, const char** aTexts, - BluetoothAvrcpResultHandler* aRes); + virtual void GetPlayerAppAttrTextRsp(int aNumAttr, const uint8_t* aIds, + const char** aTexts, + BluetoothAvrcpResultHandler* aRes) = 0; /* TODO: redesign this interface once we actually use it */ - void GetPlayerAppValueTextRsp(int aNumVal, - const uint8_t* aIds, const char** aTexts, - BluetoothAvrcpResultHandler* aRes); + virtual void GetPlayerAppValueTextRsp(int aNumVal, const uint8_t* aIds, + const char** aTexts, + BluetoothAvrcpResultHandler* aRes) = 0; - void GetElementAttrRsp(uint8_t aNumAttr, - const BluetoothAvrcpElementAttribute* aAttr, - BluetoothAvrcpResultHandler* aRes); + virtual void GetElementAttrRsp(uint8_t aNumAttr, + const BluetoothAvrcpElementAttribute* aAttr, + BluetoothAvrcpResultHandler* aRes) = 0; - void SetPlayerAppValueRsp(BluetoothAvrcpStatus aRspStatus, - BluetoothAvrcpResultHandler* aRes); + virtual void SetPlayerAppValueRsp(BluetoothAvrcpStatus aRspStatus, + BluetoothAvrcpResultHandler* aRes) = 0; - void RegisterNotificationRsp(BluetoothAvrcpEvent aEvent, - BluetoothAvrcpNotification aType, - const BluetoothAvrcpNotificationParam& aParam, - BluetoothAvrcpResultHandler* aRes); + virtual void RegisterNotificationRsp( + BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType, + const BluetoothAvrcpNotificationParam& aParam, + BluetoothAvrcpResultHandler* aRes) = 0; - void SetVolume(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes); + virtual void SetVolume(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes) = 0; protected: - BluetoothAvrcpInterface( -#if ANDROID_VERSION >= 18 - const btrc_interface_t* aInterface -#endif - ); - ~BluetoothAvrcpInterface(); - -private: -#if ANDROID_VERSION >= 18 - const btrc_interface_t* mInterface; -#endif + BluetoothAvrcpInterface(); + virtual ~BluetoothAvrcpInterface(); }; // @@ -582,92 +547,86 @@ class BluetoothInterface public: static BluetoothInterface* GetInstance(); - void Init(BluetoothNotificationHandler* aNotificationHandler, - BluetoothResultHandler* aRes); - void Cleanup(BluetoothResultHandler* aRes); - - void Enable(BluetoothResultHandler* aRes); - void Disable(BluetoothResultHandler* aRes); + virtual void Init(BluetoothNotificationHandler* aNotificationHandler, + BluetoothResultHandler* aRes) = 0; + virtual void Cleanup(BluetoothResultHandler* aRes) = 0; + virtual void Enable(BluetoothResultHandler* aRes) = 0; + virtual void Disable(BluetoothResultHandler* aRes) = 0; /* Adapter Properties */ - void GetAdapterProperties(BluetoothResultHandler* aRes); - void GetAdapterProperty(const nsAString& aName, - BluetoothResultHandler* aRes); - void SetAdapterProperty(const BluetoothNamedValue& aProperty, - BluetoothResultHandler* aRes); + virtual void GetAdapterProperties(BluetoothResultHandler* aRes) = 0; + virtual void GetAdapterProperty(const nsAString& aName, + BluetoothResultHandler* aRes) = 0; + virtual void SetAdapterProperty(const BluetoothNamedValue& aProperty, + BluetoothResultHandler* aRes) = 0; /* Remote Device Properties */ - void GetRemoteDeviceProperties(const nsAString& aRemoteAddr, - BluetoothResultHandler* aRes); - void GetRemoteDeviceProperty(const nsAString& aRemoteAddr, - const nsAString& aName, - BluetoothResultHandler* aRes); - void SetRemoteDeviceProperty(const nsAString& aRemoteAddr, - const BluetoothNamedValue& aProperty, - BluetoothResultHandler* aRes); + virtual void GetRemoteDeviceProperties(const nsAString& aRemoteAddr, + BluetoothResultHandler* aRes) = 0; + virtual void GetRemoteDeviceProperty(const nsAString& aRemoteAddr, + const nsAString& aName, + BluetoothResultHandler* aRes) = 0; + virtual void SetRemoteDeviceProperty(const nsAString& aRemoteAddr, + const BluetoothNamedValue& aProperty, + BluetoothResultHandler* aRes) = 0; /* Remote Services */ - void GetRemoteServiceRecord(const nsAString& aRemoteAddr, - const uint8_t aUuid[16], - BluetoothResultHandler* aRes); - void GetRemoteServices(const nsAString& aRemoteAddr, - BluetoothResultHandler* aRes); + virtual void GetRemoteServiceRecord(const nsAString& aRemoteAddr, + const uint8_t aUuid[16], + BluetoothResultHandler* aRes) = 0; + virtual void GetRemoteServices(const nsAString& aRemoteAddr, + BluetoothResultHandler* aRes) = 0; /* Discovery */ - void StartDiscovery(BluetoothResultHandler* aRes); - void CancelDiscovery(BluetoothResultHandler* aRes); + virtual void StartDiscovery(BluetoothResultHandler* aRes) = 0; + virtual void CancelDiscovery(BluetoothResultHandler* aRes) = 0; /* Bonds */ - void CreateBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); - void RemoveBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); - void CancelBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); + virtual void CreateBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) = 0; + virtual void RemoveBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) = 0; + virtual void CancelBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) = 0; /* Authentication */ - void PinReply(const nsAString& aBdAddr, bool aAccept, - const nsAString& aPinCode, - BluetoothResultHandler* aRes); + virtual void PinReply(const nsAString& aBdAddr, bool aAccept, + const nsAString& aPinCode, + BluetoothResultHandler* aRes) = 0; - void SspReply(const nsAString& aBdAddr, const nsAString& aVariant, - bool aAccept, uint32_t aPasskey, - BluetoothResultHandler* aRes); + virtual void SspReply(const nsAString& aBdAddr, const nsAString& aVariant, + bool aAccept, uint32_t aPasskey, + BluetoothResultHandler* aRes) = 0; /* DUT Mode */ - void DutModeConfigure(bool aEnable, BluetoothResultHandler* aRes); - void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, - BluetoothResultHandler* aRes); + virtual void DutModeConfigure(bool aEnable, + BluetoothResultHandler* aRes) = 0; + virtual void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes) = 0; /* LE Mode */ - void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, - BluetoothResultHandler* aRes); + virtual void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes) = 0; /* Profile Interfaces */ - BluetoothSocketInterface* GetBluetoothSocketInterface(); - BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface(); - BluetoothA2dpInterface* GetBluetoothA2dpInterface(); - BluetoothAvrcpInterface* GetBluetoothAvrcpInterface(); + virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0; + virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0; + virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0; + virtual BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() = 0; protected: - BluetoothInterface(const bt_interface_t* aInterface); - ~BluetoothInterface(); - -private: - template - T* CreateProfileInterface(); - - template - T* GetProfileInterface(); - - const bt_interface_t* mInterface; + BluetoothInterface(); + virtual ~BluetoothInterface(); }; END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.cpp b/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.cpp new file mode 100644 index 000000000000..5bd82e7c893e --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.cpp @@ -0,0 +1,184 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothA2dpHALInterface.h" +#include "BluetoothHALHelpers.h" + +BEGIN_BLUETOOTH_NAMESPACE + +typedef + BluetoothHALInterfaceRunnable0 + BluetoothA2dpHALResultRunnable; + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothA2dpHALErrorRunnable; + +static nsresult +DispatchBluetoothA2dpHALResult( + BluetoothA2dpResultHandler* aRes, + void (BluetoothA2dpResultHandler::*aMethod)(), + BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothA2dpHALResultRunnable(aRes, aMethod); + } else { + runnable = new BluetoothA2dpHALErrorRunnable(aRes, + &BluetoothA2dpResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +// Notification handling +// + +static BluetoothA2dpNotificationHandler* sA2dpNotificationHandler; + +struct BluetoothA2dpHALCallback +{ + class A2dpNotificationHandlerWrapper + { + public: + typedef BluetoothA2dpNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sA2dpNotificationHandler; + } + }; + + // Notifications + + typedef BluetoothNotificationHALRunnable2< + A2dpNotificationHandlerWrapper, void, + BluetoothA2dpConnectionState, nsString, + BluetoothA2dpConnectionState, const nsAString&> + ConnectionStateNotification; + + typedef BluetoothNotificationHALRunnable2< + A2dpNotificationHandlerWrapper, void, + BluetoothA2dpAudioState, nsString, + BluetoothA2dpAudioState, const nsAString&> + AudioStateNotification; + + // Bluedroid A2DP callbacks + + static void + ConnectionState(btav_connection_state_t aState, bt_bdaddr_t* aBdAddr) + { + ConnectionStateNotification::Dispatch( + &BluetoothA2dpNotificationHandler::ConnectionStateNotification, + aState, aBdAddr); + } + + static void + AudioState(btav_audio_state_t aState, bt_bdaddr_t* aBdAddr) + { + AudioStateNotification::Dispatch( + &BluetoothA2dpNotificationHandler::AudioStateNotification, + aState, aBdAddr); + } +}; + +// Interface +// + +BluetoothA2dpHALInterface::BluetoothA2dpHALInterface( + const btav_interface_t* aInterface) +: mInterface(aInterface) +{ + MOZ_ASSERT(mInterface); +} + +BluetoothA2dpHALInterface::~BluetoothA2dpHALInterface() +{ } + +void +BluetoothA2dpHALInterface::Init( + BluetoothA2dpNotificationHandler* aNotificationHandler, + BluetoothA2dpResultHandler* aRes) +{ + static btav_callbacks_t sCallbacks = { + sizeof(sCallbacks), + BluetoothA2dpHALCallback::ConnectionState, + BluetoothA2dpHALCallback::AudioState + }; + + sA2dpNotificationHandler = aNotificationHandler; + + bt_status_t status = mInterface->init(&sCallbacks); + + if (aRes) { + DispatchBluetoothA2dpHALResult(aRes, + &BluetoothA2dpResultHandler::Init, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothA2dpHALInterface::Cleanup(BluetoothA2dpResultHandler* aRes) +{ + mInterface->cleanup(); + + if (aRes) { + DispatchBluetoothA2dpHALResult(aRes, + &BluetoothA2dpResultHandler::Cleanup, + STATUS_SUCCESS); + } +} + +void +BluetoothA2dpHALInterface::Connect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->connect(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothA2dpHALResult( + aRes, &BluetoothA2dpResultHandler::Connect, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothA2dpHALInterface::Disconnect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->disconnect(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothA2dpHALResult( + aRes, &BluetoothA2dpResultHandler::Disconnect, + ConvertDefault(status, STATUS_FAIL)); + } +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.h b/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.h new file mode 100644 index 000000000000..84b1108bf3fa --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.h @@ -0,0 +1,44 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetootha2dphalinterface_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetootha2dphalinterface_h__ + +#include +#include +#include "BluetoothCommon.h" +#include "BluetoothInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothHALInterface; + +class BluetoothA2dpHALInterface MOZ_FINAL + : public BluetoothA2dpInterface +{ +public: + friend class BluetoothHALInterface; + + void Init(BluetoothA2dpNotificationHandler* aNotificationHandler, + BluetoothA2dpResultHandler* aRes); + void Cleanup(BluetoothA2dpResultHandler* aRes); + + void Connect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes); + void Disconnect(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes); + +protected: + BluetoothA2dpHALInterface(const btav_interface_t* aInterface); + ~BluetoothA2dpHALInterface(); + +private: + const btav_interface_t* mInterface; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.cpp b/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.cpp new file mode 100644 index 000000000000..3b9f1e8bae9d --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.cpp @@ -0,0 +1,593 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothAvrcpHALInterface.h" +#include "BluetoothHALHelpers.h" + +BEGIN_BLUETOOTH_NAMESPACE + +typedef + BluetoothHALInterfaceRunnable0 + BluetoothAvrcpHALResultRunnable; + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothAvrcpHALErrorRunnable; + +static nsresult +DispatchBluetoothAvrcpHALResult( + BluetoothAvrcpResultHandler* aRes, + void (BluetoothAvrcpResultHandler::*aMethod)(), + BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothAvrcpHALResultRunnable(aRes, aMethod); + } else { + runnable = new BluetoothAvrcpHALErrorRunnable(aRes, + &BluetoothAvrcpResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +// Notification handling +// + +static BluetoothAvrcpNotificationHandler* sAvrcpNotificationHandler; + +struct BluetoothAvrcpCallback +{ + class AvrcpNotificationHandlerWrapper + { + public: + typedef BluetoothAvrcpNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sAvrcpNotificationHandler; + } + }; + + // Notifications + + typedef BluetoothNotificationHALRunnable0 + GetPlayStatusNotification; + + typedef BluetoothNotificationHALRunnable0 + ListPlayerAppAttrNotification; + + typedef BluetoothNotificationHALRunnable1 + ListPlayerAppValuesNotification; + + typedef BluetoothNotificationHALRunnable2, + uint8_t, const BluetoothAvrcpPlayerAttribute*> + GetPlayerAppValueNotification; + + typedef BluetoothNotificationHALRunnable2, + uint8_t, const BluetoothAvrcpPlayerAttribute*> + GetPlayerAppAttrsTextNotification; + + typedef BluetoothNotificationHALRunnable3, + uint8_t, uint8_t, const uint8_t*> + GetPlayerAppValuesTextNotification; + + typedef BluetoothNotificationHALRunnable1 + SetPlayerAppValueNotification; + + typedef BluetoothNotificationHALRunnable2, + uint8_t, const BluetoothAvrcpMediaAttribute*> + GetElementAttrNotification; + + typedef BluetoothNotificationHALRunnable2 + RegisterNotificationNotification; + + typedef BluetoothNotificationHALRunnable2 + RemoteFeatureNotification; + + typedef BluetoothNotificationHALRunnable2 + VolumeChangeNotification; + + typedef BluetoothNotificationHALRunnable2 + PassthroughCmdNotification; + + // Bluedroid AVRCP callbacks + +#if ANDROID_VERSION >= 18 + static void + GetPlayStatus() + { + GetPlayStatusNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::GetPlayStatusNotification); + } + + static void + ListPlayerAppAttr() + { + ListPlayerAppAttrNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::ListPlayerAppAttrNotification); + } + + static void + ListPlayerAppValues(btrc_player_attr_t aAttrId) + { + ListPlayerAppValuesNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::ListPlayerAppValuesNotification, + aAttrId); + } + + static void + GetPlayerAppValue(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs) + { + GetPlayerAppValueNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::GetPlayerAppValueNotification, + aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); + } + + static void + GetPlayerAppAttrsText(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs) + { + GetPlayerAppAttrsTextNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::GetPlayerAppAttrsTextNotification, + aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); + } + + static void + GetPlayerAppValuesText(uint8_t aAttrId, uint8_t aNumVals, uint8_t* aVals) + { + GetPlayerAppValuesTextNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::GetPlayerAppValuesTextNotification, + aAttrId, aNumVals, ConvertArray(aVals, aNumVals)); + } + + static void + SetPlayerAppValue(btrc_player_settings_t* aVals) + { + SetPlayerAppValueNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::SetPlayerAppValueNotification, + *aVals); + } + + static void + GetElementAttr(uint8_t aNumAttrs, btrc_media_attr_t* aAttrs) + { + GetElementAttrNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::GetElementAttrNotification, + aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); + } + + static void + RegisterNotification(btrc_event_id_t aEvent, uint32_t aParam) + { + RegisterNotificationNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::RegisterNotificationNotification, + aEvent, aParam); + } +#endif // ANDROID_VERSION >= 18 + +#if ANDROID_VERSION >= 19 + static void + RemoteFeature(bt_bdaddr_t* aBdAddr, btrc_remote_features_t aFeatures) + { + RemoteFeatureNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::RemoteFeatureNotification, + aBdAddr, aFeatures); + } + + static void + VolumeChange(uint8_t aVolume, uint8_t aCType) + { + VolumeChangeNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::VolumeChangeNotification, + aVolume, aCType); + } + + static void + PassthroughCmd(int aId, int aKeyState) + { + PassthroughCmdNotification::Dispatch( + &BluetoothAvrcpNotificationHandler::PassthroughCmdNotification, + aId, aKeyState); + } +#endif // ANDROID_VERSION >= 19 +}; + +// Interface +// + +BluetoothAvrcpHALInterface::BluetoothAvrcpHALInterface( +#if ANDROID_VERSION >= 18 + const btrc_interface_t* aInterface +#endif + ) +#if ANDROID_VERSION >= 18 +: mInterface(aInterface) +#endif +{ +#if ANDROID_VERSION >= 18 + MOZ_ASSERT(mInterface); +#endif +} + +BluetoothAvrcpHALInterface::~BluetoothAvrcpHALInterface() +{ } + +void +BluetoothAvrcpHALInterface::Init( + BluetoothAvrcpNotificationHandler* aNotificationHandler, + BluetoothAvrcpResultHandler* aRes) +{ +#if ANDROID_VERSION >= 18 + static btrc_callbacks_t sCallbacks = { + sizeof(sCallbacks), +#if ANDROID_VERSION >= 19 + BluetoothAvrcpCallback::RemoteFeature, +#endif + BluetoothAvrcpCallback::GetPlayStatus, + BluetoothAvrcpCallback::ListPlayerAppAttr, + BluetoothAvrcpCallback::ListPlayerAppValues, + BluetoothAvrcpCallback::GetPlayerAppValue, + BluetoothAvrcpCallback::GetPlayerAppAttrsText, + BluetoothAvrcpCallback::GetPlayerAppValuesText, + BluetoothAvrcpCallback::SetPlayerAppValue, + BluetoothAvrcpCallback::GetElementAttr, + BluetoothAvrcpCallback::RegisterNotification +#if ANDROID_VERSION >= 19 + , + BluetoothAvrcpCallback::VolumeChange, + BluetoothAvrcpCallback::PassthroughCmd +#endif + }; +#endif // ANDROID_VERSION >= 18 + + sAvrcpNotificationHandler = aNotificationHandler; + +#if ANDROID_VERSION >= 18 + bt_status_t status = mInterface->init(&sCallbacks); +#else + bt_status_t status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult(aRes, &BluetoothAvrcpResultHandler::Init, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::Cleanup(BluetoothAvrcpResultHandler* aRes) +{ +#if ANDROID_VERSION >= 18 + mInterface->cleanup(); +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult(aRes, + &BluetoothAvrcpResultHandler::Cleanup, STATUS_SUCCESS); + } +} + +void +BluetoothAvrcpHALInterface::GetPlayStatusRsp( + ControlPlayStatus aPlayStatus, uint32_t aSongLen, uint32_t aSongPos, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + btrc_play_status_t playStatus = BTRC_PLAYSTATE_STOPPED; + + if (!(NS_FAILED(Convert(aPlayStatus, playStatus)))) { + status = mInterface->get_play_status_rsp(playStatus, aSongLen, aSongPos); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::ListPlayerAppAttrRsp( + int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + ConvertArray pAttrsArray(aPAttrs, aNumAttr); + nsAutoArrayPtr pAttrs; + + if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) { + status = mInterface->list_player_app_attr_rsp(aNumAttr, pAttrs); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::ListPlayerAppValueRsp( + int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes) +{ +#if ANDROID_VERSION >= 18 + bt_status_t status = mInterface->list_player_app_value_rsp(aNumVal, aPVals); +#else + bt_status_t status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::GetPlayerAppValueRsp( + uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + btrc_player_settings_t pVals; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (false /* TODO: we don't support any player app values currently */) { + status = mInterface->get_player_app_value_rsp(&pVals); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::GetPlayerAppAttrTextRsp( + int aNumAttr, const uint8_t* aIds, const char** aTexts, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + btrc_player_setting_text_t* aPAttrs; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (false /* TODO: we don't support any attributes currently */) { + status = mInterface->get_player_app_attr_text_rsp(aNumAttr, aPAttrs); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::GetPlayerAppValueTextRsp( + int aNumVal, const uint8_t* aIds, const char** aTexts, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + btrc_player_setting_text_t* pVals; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (false /* TODO: we don't support any values currently */) { + status = mInterface->get_player_app_value_text_rsp(aNumVal, pVals); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::GetElementAttrRsp( + uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttrs, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + ConvertArray pAttrsArray(aAttrs, aNumAttr); + nsAutoArrayPtr pAttrs; + + if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) { + status = mInterface->get_element_attr_rsp(aNumAttr, pAttrs); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::SetPlayerAppValueRsp( + BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + btrc_status_t rspStatus = BTRC_STS_BAD_CMD; // silences compiler warning + + if (NS_SUCCEEDED(Convert(aRspStatus, rspStatus))) { + status = mInterface->set_player_app_value_rsp(rspStatus); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::RegisterNotificationRsp( + BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType, + const BluetoothAvrcpNotificationParam& aParam, + BluetoothAvrcpResultHandler* aRes) +{ + bt_status_t status; + +#if ANDROID_VERSION >= 18 + nsresult rv; + btrc_event_id_t event = { }; + btrc_notification_type_t type = BTRC_NOTIFICATION_TYPE_INTERIM; + btrc_register_notification_t param; + + switch (aEvent) { + case AVRCP_EVENT_PLAY_STATUS_CHANGED: + rv = Convert(aParam.mPlayStatus, param.play_status); + break; + case AVRCP_EVENT_TRACK_CHANGE: + MOZ_ASSERT(sizeof(aParam.mTrack) == sizeof(param.track)); + memcpy(param.track, aParam.mTrack, sizeof(param.track)); + rv = NS_OK; + break; + case AVRCP_EVENT_TRACK_REACHED_END: + NS_NOTREACHED("Unknown conversion"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + case AVRCP_EVENT_TRACK_REACHED_START: + NS_NOTREACHED("Unknown conversion"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + case AVRCP_EVENT_PLAY_POS_CHANGED: + param.song_pos = aParam.mSongPos; + rv = NS_OK; + break; + case AVRCP_EVENT_APP_SETTINGS_CHANGED: + NS_NOTREACHED("Unknown conversion"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + default: + NS_NOTREACHED("Unknown conversion"); + rv = NS_ERROR_ILLEGAL_VALUE; + break; + } + + if (NS_SUCCEEDED(rv) && + NS_SUCCEEDED(Convert(aEvent, event)) && + NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->register_notification_rsp(event, type, ¶m); + } else { + status = BT_STATUS_PARM_INVALID; + } +#else + status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothAvrcpHALInterface::SetVolume(uint8_t aVolume, + BluetoothAvrcpResultHandler* aRes) +{ +#if ANDROID_VERSION >= 19 + bt_status_t status = mInterface->set_volume(aVolume); +#else + bt_status_t status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothAvrcpHALResult( + aRes, &BluetoothAvrcpResultHandler::SetVolume, + ConvertDefault(status, STATUS_FAIL)); + } +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.h b/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.h new file mode 100644 index 000000000000..8dcd54fc6bc5 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothAvrcpHALInterface.h @@ -0,0 +1,84 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothavrcphalinterface_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetoothavrcphalinterface_h__ + +#include +#if ANDROID_VERSION >= 18 +#include +#endif +#include "BluetoothCommon.h" +#include "BluetoothInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothHALInterface; + +class BluetoothAvrcpHALInterface MOZ_FINAL + : public BluetoothAvrcpInterface +{ +public: + friend class BluetoothHALInterface; + + void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler, + BluetoothAvrcpResultHandler* aRes); + void Cleanup(BluetoothAvrcpResultHandler* aRes); + + void GetPlayStatusRsp(ControlPlayStatus aPlayStatus, + uint32_t aSongLen, uint32_t aSongPos, + BluetoothAvrcpResultHandler* aRes); + + void ListPlayerAppAttrRsp(int aNumAttr, + const BluetoothAvrcpPlayerAttribute* aPAttrs, + BluetoothAvrcpResultHandler* aRes); + void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals, + BluetoothAvrcpResultHandler* aRes); + + /* TODO: redesign this interface once we actually use it */ + void GetPlayerAppValueRsp(uint8_t aNumAttrs, + const uint8_t* aIds, const uint8_t* aValues, + BluetoothAvrcpResultHandler* aRes); + /* TODO: redesign this interface once we actually use it */ + void GetPlayerAppAttrTextRsp(int aNumAttr, + const uint8_t* aIds, const char** aTexts, + BluetoothAvrcpResultHandler* aRes); + /* TODO: redesign this interface once we actually use it */ + void GetPlayerAppValueTextRsp(int aNumVal, + const uint8_t* aIds, const char** aTexts, + BluetoothAvrcpResultHandler* aRes); + + void GetElementAttrRsp(uint8_t aNumAttr, + const BluetoothAvrcpElementAttribute* aAttr, + BluetoothAvrcpResultHandler* aRes); + + void SetPlayerAppValueRsp(BluetoothAvrcpStatus aRspStatus, + BluetoothAvrcpResultHandler* aRes); + + void RegisterNotificationRsp(BluetoothAvrcpEvent aEvent, + BluetoothAvrcpNotification aType, + const BluetoothAvrcpNotificationParam& aParam, + BluetoothAvrcpResultHandler* aRes); + + void SetVolume(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes); + +protected: + BluetoothAvrcpHALInterface( +#if ANDROID_VERSION >= 18 + const btrc_interface_t* aInterface +#endif + ); + ~BluetoothAvrcpHALInterface(); + +private: +#if ANDROID_VERSION >= 18 + const btrc_interface_t* mInterface; +#endif +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothHALHelpers.cpp b/dom/bluetooth/bluedroid/BluetoothHALHelpers.cpp new file mode 100644 index 000000000000..f0163b26084d --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHALHelpers.cpp @@ -0,0 +1,298 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothHALHelpers.h" + +#define MAX_UUID_SIZE 16 + +BEGIN_BLUETOOTH_NAMESPACE + +// +// Conversion +// + +nsresult +Convert(const nsAString& aIn, bt_property_type_t& aOut) +{ + if (aIn.EqualsLiteral("Name")) { + aOut = BT_PROPERTY_BDNAME; + } else if (aIn.EqualsLiteral("Discoverable")) { + aOut = BT_PROPERTY_ADAPTER_SCAN_MODE; + } else if (aIn.EqualsLiteral("DiscoverableTimeout")) { + aOut = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT; + } else { + BT_LOGR("Invalid property name: %s", NS_ConvertUTF16toUTF8(aIn).get()); + return NS_ERROR_ILLEGAL_VALUE; + } + return NS_OK; +} + +nsresult +Convert(ConvertNamedValue& aIn, bt_property_t& aOut) +{ + nsresult rv = Convert(aIn.mNamedValue.name(), aOut.type); + if (NS_FAILED(rv)) { + return rv; + } + + if (aIn.mNamedValue.value().type() == BluetoothValue::Tuint32_t) { + // Set discoverable timeout + aOut.val = + reinterpret_cast(aIn.mNamedValue.value().get_uint32_t()); + } else if (aIn.mNamedValue.value().type() == BluetoothValue::TnsString) { + // Set name + aIn.mStringValue = + NS_ConvertUTF16toUTF8(aIn.mNamedValue.value().get_nsString()); + aOut.val = + const_cast(static_cast(aIn.mStringValue.get())); + aOut.len = strlen(static_cast(aOut.val)); + } else if (aIn.mNamedValue.value().type() == BluetoothValue::Tbool) { + // Set scan mode + rv = Convert(aIn.mNamedValue.value().get_bool(), aIn.mScanMode); + if (NS_FAILED(rv)) { + return rv; + } + aOut.val = &aIn.mScanMode; + aOut.len = sizeof(aIn.mScanMode); + } else { + BT_LOGR("Invalid property value type"); + return NS_ERROR_ILLEGAL_VALUE; + } + + return NS_OK; +} + +nsresult +Convert(const nsAString& aIn, bt_bdaddr_t& aOut) +{ + NS_ConvertUTF16toUTF8 bdAddressUTF8(aIn); + const char* str = bdAddressUTF8.get(); + + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aOut.address); ++i, ++str) { + aOut.address[i] = + static_cast(strtoul(str, const_cast(&str), 16)); + } + + return NS_OK; +} + +nsresult +Convert(const nsAString& aIn, bt_ssp_variant_t& aOut) +{ + if (aIn.EqualsLiteral("PasskeyConfirmation")) { + aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION; + } else if (aIn.EqualsLiteral("PasskeyEntry")) { + aOut = BT_SSP_VARIANT_PASSKEY_ENTRY; + } else if (aIn.EqualsLiteral("Consent")) { + aOut = BT_SSP_VARIANT_CONSENT; + } else if (aIn.EqualsLiteral("PasskeyNotification")) { + aOut = BT_SSP_VARIANT_PASSKEY_NOTIFICATION; + } else { + BT_LOGR("Invalid SSP variant name: %s", NS_ConvertUTF16toUTF8(aIn).get()); + aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning + return NS_ERROR_ILLEGAL_VALUE; + } + return NS_OK; +} + +nsresult +Convert(const uint8_t aIn[16], bt_uuid_t& aOut) +{ + if (sizeof(aOut.uu) != 16) { + return NS_ERROR_ILLEGAL_VALUE; + } + + memcpy(aOut.uu, aIn, sizeof(aOut.uu)); + + return NS_OK; +} + +nsresult +Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut) +{ + if (sizeof(aIn.uu) != sizeof(aOut.mUuid)) { + return NS_ERROR_ILLEGAL_VALUE; + } + + memcpy(aOut.mUuid, aIn.uu, sizeof(aOut.mUuid)); + + return NS_OK; +} + +nsresult +Convert(const nsAString& aIn, bt_pin_code_t& aOut) +{ + if (aIn.Length() > MOZ_ARRAY_LENGTH(aOut.pin)) { + return NS_ERROR_ILLEGAL_VALUE; + } + + NS_ConvertUTF16toUTF8 pinCodeUTF8(aIn); + const char* str = pinCodeUTF8.get(); + + nsAString::size_type i; + + // Fill pin into aOut + for (i = 0; i < aIn.Length(); ++i, ++str) { + aOut.pin[i] = static_cast(*str); + } + + // Clear remaining bytes in aOut + size_t ntrailing = + (MOZ_ARRAY_LENGTH(aOut.pin) - aIn.Length()) * sizeof(aOut.pin[0]); + memset(aOut.pin + aIn.Length(), 0, ntrailing); + + return NS_OK; +} + +nsresult +Convert(const bt_bdaddr_t& aIn, nsAString& aOut) +{ + char str[BLUETOOTH_ADDRESS_LENGTH + 1]; + + int res = snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", + static_cast(aIn.address[0]), + static_cast(aIn.address[1]), + static_cast(aIn.address[2]), + static_cast(aIn.address[3]), + static_cast(aIn.address[4]), + static_cast(aIn.address[5])); + if (res < 0) { + return NS_ERROR_ILLEGAL_VALUE; + } else if ((size_t)res >= sizeof(str)) { + return NS_ERROR_OUT_OF_MEMORY; /* string buffer too small */ + } + + aOut = NS_ConvertUTF8toUTF16(str); + + return NS_OK; +} + +nsresult +Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut) +{ + nsresult rv = Convert(aIn.uuid, aOut.mUuid); + if (NS_FAILED(rv)) { + return rv; + } + + aOut.mChannel = aIn.channel; + + MOZ_ASSERT(sizeof(aIn.name) == sizeof(aOut.mName)); + memcpy(aOut.mName, aIn.name, sizeof(aOut.mName)); + + return NS_OK; +} + +#if ANDROID_VERSION >= 18 +nsresult +Convert(const BluetoothAvrcpElementAttribute& aIn, btrc_element_attr_val_t& aOut) +{ + const NS_ConvertUTF16toUTF8 value(aIn.mValue); + size_t len = std::min(strlen(value.get()), sizeof(aOut.text) - 1); + + memcpy(aOut.text, value.get(), len); + aOut.text[len] = '\0'; + aOut.attr_id = aIn.mId; + + return NS_OK; +} + +nsresult +Convert(const btrc_player_settings_t& aIn, BluetoothAvrcpPlayerSettings& aOut) +{ + aOut.mNumAttr = aIn.num_attr; + memcpy(aOut.mIds, aIn.attr_ids, aIn.num_attr); + memcpy(aOut.mValues, aIn.attr_values, aIn.num_attr); + + return NS_OK; +} +#endif // ANDROID_VERSION >= 18 + +nsresult +Convert(const bt_property_t& aIn, BluetoothProperty& aOut) +{ + /* type conversion */ + + nsresult rv = Convert(aIn.type, aOut.mType); + if (NS_FAILED(rv)) { + return rv; + } + + /* value conversion */ + + switch (aOut.mType) { + case PROPERTY_BDNAME: + /* fall through */ + case PROPERTY_REMOTE_FRIENDLY_NAME: + { + // We construct an nsCString here because bdname + // returned from Bluedroid is not 0-terminated. + aOut.mString = NS_ConvertUTF8toUTF16( + nsCString(static_cast(aIn.val), aIn.len)); + } + break; + case PROPERTY_BDADDR: + rv = Convert(*static_cast(aIn.val), aOut.mString); + break; + case PROPERTY_UUIDS: + { + size_t numUuids = aIn.len / MAX_UUID_SIZE; + ConvertArray array( + static_cast(aIn.val), numUuids); + aOut.mUuidArray.SetLength(numUuids); + rv = Convert(array, aOut.mUuidArray); + } + break; + case PROPERTY_CLASS_OF_DEVICE: + /* fall through */ + case PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: + aOut.mUint32 = *static_cast(aIn.val); + break; + case PROPERTY_TYPE_OF_DEVICE: + rv = Convert(*static_cast(aIn.val), + aOut.mDeviceType); + break; + case PROPERTY_SERVICE_RECORD: + rv = Convert(*static_cast(aIn.val), + aOut.mServiceRecord); + break; + case PROPERTY_ADAPTER_SCAN_MODE: + rv = Convert(*static_cast(aIn.val), + aOut.mScanMode); + break; + case PROPERTY_ADAPTER_BONDED_DEVICES: + { + size_t numAddresses = aIn.len / BLUETOOTH_ADDRESS_BYTES; + ConvertArray array( + static_cast(aIn.val), numAddresses); + aOut.mStringArray.SetLength(numAddresses); + rv = Convert(array, aOut.mStringArray); + } + break; + case PROPERTY_REMOTE_RSSI: + aOut.mInt32 = *static_cast(aIn.val); + break; +#if ANDROID_VERSION >= 18 + case PROPERTY_REMOTE_VERSION_INFO: + rv = Convert(*static_cast(aIn.val), + aOut.mRemoteInfo); + break; +#endif + case PROPERTY_REMOTE_DEVICE_TIMESTAMP: + /* nothing to do */ + break; + default: + /* mismatch with type conversion */ + NS_NOTREACHED("Unhandled property type"); + break; + } + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothHALHelpers.h b/dom/bluetooth/bluedroid/BluetoothHALHelpers.h new file mode 100644 index 000000000000..a3db9504fa5b --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHALHelpers.h @@ -0,0 +1,1439 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothhalhelpers_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetoothhalhelpers_h__ + +#include +#include +#include +#include +#if ANDROID_VERSION >= 18 +#include +#endif +#include "BluetoothCommon.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/dom/bluetooth/BluetoothTypes.h" +#include "nsThreadUtils.h" + +#if MOZ_IS_GCC && MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) +/* use designated array initializers if supported */ +#define CONVERT(in_, out_) \ + [in_] = out_ +#else +/* otherwise init array element by position */ +#define CONVERT(in_, out_) \ + out_ +#endif + +BEGIN_BLUETOOTH_NAMESPACE + +// +// Conversion +// + +inline nsresult +Convert(bt_status_t aIn, BluetoothStatus& aOut) +{ + static const BluetoothStatus sStatus[] = { + CONVERT(BT_STATUS_SUCCESS, STATUS_SUCCESS), + CONVERT(BT_STATUS_FAIL, STATUS_FAIL), + CONVERT(BT_STATUS_NOT_READY, STATUS_NOT_READY), + CONVERT(BT_STATUS_NOMEM, STATUS_NOMEM), + CONVERT(BT_STATUS_BUSY, STATUS_BUSY), + CONVERT(BT_STATUS_DONE, STATUS_DONE), + CONVERT(BT_STATUS_UNSUPPORTED, STATUS_UNSUPPORTED), + CONVERT(BT_STATUS_PARM_INVALID, STATUS_PARM_INVALID), + CONVERT(BT_STATUS_UNHANDLED, STATUS_UNHANDLED), + CONVERT(BT_STATUS_AUTH_FAILURE, STATUS_AUTH_FAILURE), + CONVERT(BT_STATUS_RMT_DEV_DOWN, STATUS_RMT_DEV_DOWN) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sStatus)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sStatus[aIn]; + return NS_OK; +} + +inline nsresult +Convert(int aIn, BluetoothStatus& aOut) +{ + return Convert(static_cast(aIn), aOut); +} + +nsresult +Convert(const nsAString& aIn, bt_property_type_t& aOut); + +inline nsresult +Convert(bool aIn, bt_scan_mode_t& aOut) +{ + static const bt_scan_mode_t sScanMode[] = { + CONVERT(false, BT_SCAN_MODE_CONNECTABLE), + CONVERT(true, BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sScanMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sScanMode[aIn]; + return NS_OK; +} + + +inline nsresult +Convert(bt_scan_mode_t aIn, BluetoothScanMode& aOut) +{ + static const BluetoothScanMode sScanMode[] = { + CONVERT(BT_SCAN_MODE_NONE, SCAN_MODE_NONE), + CONVERT(BT_SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE), + CONVERT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE, + SCAN_MODE_CONNECTABLE_DISCOVERABLE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sScanMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sScanMode[aIn]; + return NS_OK; +} + +struct ConvertNamedValue +{ + ConvertNamedValue(const BluetoothNamedValue& aNamedValue) + : mNamedValue(aNamedValue) + { } + + const BluetoothNamedValue& mNamedValue; + + // temporary fields + nsCString mStringValue; + bt_scan_mode_t mScanMode; +}; + +nsresult +Convert(ConvertNamedValue& aIn, bt_property_t& aOut); + +nsresult +Convert(const nsAString& aIn, bt_bdaddr_t& aOut); + +nsresult +Convert(const nsAString& aIn, bt_ssp_variant_t& aOut); + +inline nsresult +Convert(const bt_ssp_variant_t& aIn, nsAString& aOut) +{ + static const char * const sSspVariant[] = { + CONVERT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION, "PasskeyConfirmation"), + CONVERT(BT_SSP_VARIANT_PASSKEY_ENTRY, "PasskeyEntry"), + CONVERT(BT_SSP_VARIANT_CONSENT, "Consent"), + CONVERT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION, "PasskeyNotification") + }; + if (aIn >= MOZ_ARRAY_LENGTH(sSspVariant)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = NS_ConvertUTF8toUTF16(sSspVariant[aIn]); + return NS_OK; +} + +inline nsresult +Convert(const bool& aIn, uint8_t& aOut) +{ + // casting converts true/false to either 1 or 0 + aOut = static_cast(aIn); + return NS_OK; +} + +nsresult +Convert(const uint8_t aIn[16], bt_uuid_t& aOut); + +nsresult +Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut); + +nsresult +Convert(const nsAString& aIn, bt_pin_code_t& aOut); + +nsresult +Convert(const bt_bdaddr_t& aIn, nsAString& aOut); + +inline nsresult +Convert(const bt_bdaddr_t* aIn, nsAString& aOut) +{ + if (!aIn) { + aOut.AssignLiteral(BLUETOOTH_ADDRESS_NONE); + return NS_OK; + } + return Convert(*aIn, aOut); +} + +inline nsresult +Convert(bt_state_t aIn, bool& aOut) +{ + static const bool sState[] = { + CONVERT(BT_STATE_OFF, false), + CONVERT(BT_STATE_ON, true) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bt_property_type_t aIn, BluetoothPropertyType& aOut) +{ + static const BluetoothPropertyType sPropertyType[] = { + CONVERT(0, static_cast(0)), // invalid, required by gcc + CONVERT(BT_PROPERTY_BDNAME, PROPERTY_BDNAME), + CONVERT(BT_PROPERTY_BDADDR, PROPERTY_BDADDR), + CONVERT(BT_PROPERTY_UUIDS, PROPERTY_UUIDS), + CONVERT(BT_PROPERTY_CLASS_OF_DEVICE, PROPERTY_CLASS_OF_DEVICE), + CONVERT(BT_PROPERTY_TYPE_OF_DEVICE, PROPERTY_TYPE_OF_DEVICE), + CONVERT(BT_PROPERTY_SERVICE_RECORD, PROPERTY_SERVICE_RECORD), + CONVERT(BT_PROPERTY_ADAPTER_SCAN_MODE, PROPERTY_ADAPTER_SCAN_MODE), + CONVERT(BT_PROPERTY_ADAPTER_BONDED_DEVICES, + PROPERTY_ADAPTER_BONDED_DEVICES), + CONVERT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, + PROPERTY_ADAPTER_DISCOVERY_TIMEOUT), + CONVERT(BT_PROPERTY_REMOTE_FRIENDLY_NAME, PROPERTY_REMOTE_FRIENDLY_NAME), + CONVERT(BT_PROPERTY_REMOTE_RSSI, PROPERTY_REMOTE_RSSI), + CONVERT(BT_PROPERTY_REMOTE_VERSION_INFO,PROPERTY_REMOTE_VERSION_INFO) + }; + if (aIn == BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP) { + /* This case is handled separately to not populate + * |sPropertyType| with empty entries. */ + aOut = PROPERTY_REMOTE_DEVICE_TIMESTAMP; + return NS_OK; + } + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPropertyType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sPropertyType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bt_discovery_state_t aIn, bool& aOut) +{ + static const bool sDiscoveryState[] = { + CONVERT(BT_DISCOVERY_STOPPED, false), + CONVERT(BT_DISCOVERY_STARTED, true) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sDiscoveryState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sDiscoveryState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(const char* aIn, nsACString& aOut) +{ + aOut.Assign(aIn); + + return NS_OK; +} + +inline nsresult +Convert(const char* aIn, nsAString& aOut) +{ + aOut = NS_ConvertUTF8toUTF16(aIn); + + return NS_OK; +} + +inline nsresult +Convert(const bt_bdname_t& aIn, nsAString& aOut) +{ + return Convert(reinterpret_cast(aIn.name), aOut); +} + +inline nsresult +Convert(const bt_bdname_t* aIn, nsAString& aOut) +{ + if (!aIn) { + aOut.Truncate(); + return NS_OK; + } + return Convert(*aIn, aOut); +} + +inline nsresult +Convert(bt_bond_state_t aIn, BluetoothBondState& aOut) +{ + static const BluetoothBondState sBondState[] = { + CONVERT(BT_BOND_STATE_NONE, BOND_STATE_NONE), + CONVERT(BT_BOND_STATE_BONDING, BOND_STATE_BONDING), + CONVERT(BT_BOND_STATE_BONDED, BOND_STATE_BONDED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sBondState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sBondState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bt_acl_state_t aIn, bool& aOut) +{ + static const bool sAclState[] = { + CONVERT(BT_ACL_STATE_CONNECTED, true), + CONVERT(BT_ACL_STATE_DISCONNECTED, false) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sAclState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sAclState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bt_device_type_t aIn, BluetoothDeviceType& aOut) +{ + static const BluetoothDeviceType sDeviceType[] = { + CONVERT(0, static_cast(0)), // invalid, required by gcc + CONVERT(BT_DEVICE_DEVTYPE_BREDR, DEVICE_TYPE_BREDR), + CONVERT(BT_DEVICE_DEVTYPE_BLE, DEVICE_TYPE_BLE), + CONVERT(BT_DEVICE_DEVTYPE_DUAL, DEVICE_TYPE_DUAL) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sDeviceType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sDeviceType[aIn]; + return NS_OK; +} + +nsresult +Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut); + +inline nsresult +Convert(BluetoothSocketType aIn, btsock_type_t& aOut) +{ + // FIXME: Array member [0] is currently invalid, but required + // by gcc. Start values in |BluetoothSocketType| at index + // 0 to fix this problem. + static const btsock_type_t sSocketType[] = { + CONVERT(0, static_cast(0)), // invalid, [0] required by gcc + CONVERT(BluetoothSocketType::RFCOMM, BTSOCK_RFCOMM), + CONVERT(BluetoothSocketType::SCO, BTSOCK_SCO), + CONVERT(BluetoothSocketType::L2CAP, BTSOCK_L2CAP), + // EL2CAP is not supported by Bluedroid + }; + if (aIn == BluetoothSocketType::EL2CAP || + aIn >= MOZ_ARRAY_LENGTH(sSocketType) || !sSocketType[aIn]) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sSocketType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeAtResponse aIn, bthf_at_response_t& aOut) +{ + static const bthf_at_response_t sAtResponse[] = { + CONVERT(HFP_AT_RESPONSE_ERROR, BTHF_AT_RESPONSE_ERROR), + CONVERT(HFP_AT_RESPONSE_OK, BTHF_AT_RESPONSE_OK) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sAtResponse)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sAtResponse[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeCallAddressType aIn, bthf_call_addrtype_t& aOut) +{ + static const bthf_call_addrtype_t sCallAddressType[] = { + CONVERT(HFP_CALL_ADDRESS_TYPE_UNKNOWN, BTHF_CALL_ADDRTYPE_UNKNOWN), + CONVERT(HFP_CALL_ADDRESS_TYPE_INTERNATIONAL, + BTHF_CALL_ADDRTYPE_INTERNATIONAL) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallAddressType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallAddressType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeCallDirection aIn, bthf_call_direction_t& aOut) +{ + static const bthf_call_direction_t sCallDirection[] = { + CONVERT(HFP_CALL_DIRECTION_OUTGOING, BTHF_CALL_DIRECTION_OUTGOING), + CONVERT(HFP_CALL_DIRECTION_INCOMING, BTHF_CALL_DIRECTION_INCOMING) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallDirection)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallDirection[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeCallMode aIn, bthf_call_mode_t& aOut) +{ + static const bthf_call_mode_t sCallMode[] = { + CONVERT(HFP_CALL_MODE_VOICE, BTHF_CALL_TYPE_VOICE), + CONVERT(HFP_CALL_MODE_DATA, BTHF_CALL_TYPE_DATA), + CONVERT(HFP_CALL_MODE_FAX, BTHF_CALL_TYPE_FAX) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallMode[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeCallMptyType aIn, bthf_call_mpty_type_t& aOut) +{ + static const bthf_call_mpty_type_t sCallMptyType[] = { + CONVERT(HFP_CALL_MPTY_TYPE_SINGLE, BTHF_CALL_MPTY_TYPE_SINGLE), + CONVERT(HFP_CALL_MPTY_TYPE_MULTI, BTHF_CALL_MPTY_TYPE_MULTI) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallMptyType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallMptyType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeCallState aIn, bthf_call_state_t& aOut) +{ + static const bthf_call_state_t sCallState[] = { + CONVERT(HFP_CALL_STATE_ACTIVE, BTHF_CALL_STATE_ACTIVE), + CONVERT(HFP_CALL_STATE_HELD, BTHF_CALL_STATE_HELD), + CONVERT(HFP_CALL_STATE_DIALING, BTHF_CALL_STATE_DIALING), + CONVERT(HFP_CALL_STATE_ALERTING, BTHF_CALL_STATE_ALERTING), + CONVERT(HFP_CALL_STATE_INCOMING, BTHF_CALL_STATE_INCOMING), + CONVERT(HFP_CALL_STATE_WAITING, BTHF_CALL_STATE_WAITING), + CONVERT(HFP_CALL_STATE_IDLE, BTHF_CALL_STATE_IDLE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeNetworkState aIn, bthf_network_state_t& aOut) +{ + static const bthf_network_state_t sNetworkState[] = { + CONVERT(HFP_NETWORK_STATE_NOT_AVAILABLE, BTHF_NETWORK_STATE_NOT_AVAILABLE), + CONVERT(HFP_NETWORK_STATE_AVAILABLE, BTHF_NETWORK_STATE_AVAILABLE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sNetworkState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sNetworkState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeServiceType aIn, bthf_service_type_t& aOut) +{ + static const bthf_service_type_t sServiceType[] = { + CONVERT(HFP_SERVICE_TYPE_HOME, BTHF_SERVICE_TYPE_HOME), + CONVERT(HFP_SERVICE_TYPE_ROAMING, BTHF_SERVICE_TYPE_ROAMING) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sServiceType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sServiceType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(BluetoothHandsfreeVolumeType aIn, bthf_volume_type_t& aOut) +{ + static const bthf_volume_type_t sVolumeType[] = { + CONVERT(HFP_VOLUME_TYPE_SPEAKER, BTHF_VOLUME_TYPE_SPK), + CONVERT(HFP_VOLUME_TYPE_MICROPHONE, BTHF_VOLUME_TYPE_MIC) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sVolumeType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_audio_state_t aIn, BluetoothHandsfreeAudioState& aOut) +{ + static const BluetoothHandsfreeAudioState sAudioState[] = { + CONVERT(BTHF_AUDIO_STATE_DISCONNECTED, HFP_AUDIO_STATE_DISCONNECTED), + CONVERT(BTHF_AUDIO_STATE_CONNECTING, HFP_AUDIO_STATE_CONNECTING), + CONVERT(BTHF_AUDIO_STATE_CONNECTED, HFP_AUDIO_STATE_CONNECTED), + CONVERT(BTHF_AUDIO_STATE_DISCONNECTING, HFP_AUDIO_STATE_DISCONNECTING) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sAudioState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_chld_type_t aIn, BluetoothHandsfreeCallHoldType& aOut) +{ + static const BluetoothHandsfreeCallHoldType sCallHoldType[] = { + CONVERT(BTHF_CHLD_TYPE_RELEASEHELD, HFP_CALL_HOLD_RELEASEHELD), + CONVERT(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD, + HFP_CALL_HOLD_RELEASEACTIVE_ACCEPTHELD), + CONVERT(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD, + HFP_CALL_HOLD_HOLDACTIVE_ACCEPTHELD), + CONVERT(BTHF_CHLD_TYPE_ADDHELDTOCONF, HFP_CALL_HOLD_ADDHELDTOCONF) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sCallHoldType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sCallHoldType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_connection_state_t aIn, BluetoothHandsfreeConnectionState& aOut) +{ + static const BluetoothHandsfreeConnectionState sConnectionState[] = { + CONVERT(BTHF_CONNECTION_STATE_DISCONNECTED, + HFP_CONNECTION_STATE_DISCONNECTED), + CONVERT(BTHF_CONNECTION_STATE_CONNECTING, HFP_CONNECTION_STATE_CONNECTING), + CONVERT(BTHF_CONNECTION_STATE_CONNECTED, HFP_CONNECTION_STATE_CONNECTED), + CONVERT(BTHF_CONNECTION_STATE_SLC_CONNECTED, + HFP_CONNECTION_STATE_SLC_CONNECTED), + CONVERT(BTHF_CONNECTION_STATE_DISCONNECTING, + HFP_CONNECTION_STATE_DISCONNECTING) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sConnectionState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_nrec_t aIn, BluetoothHandsfreeNRECState& aOut) +{ + static const BluetoothHandsfreeNRECState sNRECState[] = { + CONVERT(BTHF_NREC_STOP, HFP_NREC_STOPPED), + CONVERT(BTHF_NREC_START, HFP_NREC_STARTED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sNRECState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sNRECState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_vr_state_t aIn, BluetoothHandsfreeVoiceRecognitionState& aOut) +{ + static const BluetoothHandsfreeVoiceRecognitionState + sVoiceRecognitionState[] = { + CONVERT(BTHF_VR_STATE_STOPPED, HFP_VOICE_RECOGNITION_STOPPED), + CONVERT(BTHF_VR_STATE_STARTED, HFP_VOICE_RECOGNITION_STARTED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sVoiceRecognitionState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sVoiceRecognitionState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(bthf_volume_type_t aIn, BluetoothHandsfreeVolumeType& aOut) +{ + static const BluetoothHandsfreeVolumeType sVolumeType[] = { + CONVERT(BTHF_VOLUME_TYPE_SPK, HFP_VOLUME_TYPE_SPEAKER), + CONVERT(BTHF_VOLUME_TYPE_MIC, HFP_VOLUME_TYPE_MICROPHONE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sVolumeType[aIn]; + return NS_OK; +} + +inline nsresult +Convert(btav_connection_state_t aIn, BluetoothA2dpConnectionState& aOut) +{ + static const BluetoothA2dpConnectionState sConnectionState[] = { + CONVERT(BTAV_CONNECTION_STATE_DISCONNECTED, + A2DP_CONNECTION_STATE_DISCONNECTED), + CONVERT(BTAV_CONNECTION_STATE_CONNECTING, + A2DP_CONNECTION_STATE_CONNECTING), + CONVERT(BTAV_CONNECTION_STATE_CONNECTED, + A2DP_CONNECTION_STATE_CONNECTED), + CONVERT(BTAV_CONNECTION_STATE_DISCONNECTING, + A2DP_CONNECTION_STATE_DISCONNECTING), + }; + if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sConnectionState[aIn]; + return NS_OK; +} + +inline nsresult +Convert(btav_audio_state_t aIn, BluetoothA2dpAudioState& aOut) +{ + static const BluetoothA2dpAudioState sAudioState[] = { + CONVERT(BTAV_AUDIO_STATE_REMOTE_SUSPEND, A2DP_AUDIO_STATE_REMOTE_SUSPEND), + CONVERT(BTAV_AUDIO_STATE_STOPPED, A2DP_AUDIO_STATE_STOPPED), + CONVERT(BTAV_AUDIO_STATE_STARTED, A2DP_AUDIO_STATE_STARTED), + }; + if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sAudioState[aIn]; + return NS_OK; +} + +#if ANDROID_VERSION >= 18 +inline nsresult +Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut) +{ + aOut.mVerMajor = aIn.version; + aOut.mVerMinor = aIn.sub_ver; + aOut.mManufacturer = aIn.manufacturer; + + return NS_OK; +} + +inline nsresult +Convert(ControlPlayStatus aIn, btrc_play_status_t& aOut) +{ + static const btrc_play_status_t sPlayStatus[] = { + CONVERT(PLAYSTATUS_STOPPED, BTRC_PLAYSTATE_STOPPED), + CONVERT(PLAYSTATUS_PLAYING, BTRC_PLAYSTATE_PLAYING), + CONVERT(PLAYSTATUS_PAUSED, BTRC_PLAYSTATE_PAUSED), + CONVERT(PLAYSTATUS_FWD_SEEK, BTRC_PLAYSTATE_FWD_SEEK), + CONVERT(PLAYSTATUS_REV_SEEK, BTRC_PLAYSTATE_REV_SEEK) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sPlayStatus)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sPlayStatus[aIn]; + return NS_OK; +} + +inline nsresult +Convert(enum BluetoothAvrcpPlayerAttribute aIn, btrc_player_attr_t& aOut) +{ + static const btrc_player_attr_t sPlayerAttr[] = { + CONVERT(AVRCP_PLAYER_ATTRIBUTE_EQUALIZER, BTRC_PLAYER_ATTR_EQUALIZER), + CONVERT(AVRCP_PLAYER_ATTRIBUTE_REPEAT, BTRC_PLAYER_ATTR_REPEAT), + CONVERT(AVRCP_PLAYER_ATTRIBUTE_SHUFFLE, BTRC_PLAYER_ATTR_SHUFFLE), + CONVERT(AVRCP_PLAYER_ATTRIBUTE_SCAN, BTRC_PLAYER_ATTR_SCAN) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sPlayerAttr[aIn]; + return NS_OK; +} + +inline nsresult +Convert(btrc_player_attr_t aIn, enum BluetoothAvrcpPlayerAttribute& aOut) +{ + static const BluetoothAvrcpPlayerAttribute sPlayerAttr[] = { + CONVERT(0, static_cast(0)), // invalid, [0] required by gcc + CONVERT(BTRC_PLAYER_ATTR_EQUALIZER, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER), + CONVERT(BTRC_PLAYER_ATTR_REPEAT, AVRCP_PLAYER_ATTRIBUTE_REPEAT), + CONVERT(BTRC_PLAYER_ATTR_SHUFFLE, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE), + CONVERT(BTRC_PLAYER_ATTR_SCAN, AVRCP_PLAYER_ATTRIBUTE_SCAN) + }; + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sPlayerAttr[aIn]; + return NS_OK; +} + +inline nsresult +Convert(enum BluetoothAvrcpStatus aIn, btrc_status_t& aOut) +{ + static const btrc_status_t sStatus[] = { + CONVERT(AVRCP_STATUS_BAD_COMMAND, BTRC_STS_BAD_CMD), + CONVERT(AVRCP_STATUS_BAD_PARAMETER, BTRC_STS_BAD_PARAM), + CONVERT(AVRCP_STATUS_NOT_FOUND, BTRC_STS_NOT_FOUND), + CONVERT(AVRCP_STATUS_INTERNAL_ERROR, BTRC_STS_INTERNAL_ERR), + CONVERT(AVRCP_STATUS_SUCCESS, BTRC_STS_NO_ERROR) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sStatus)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sStatus[aIn]; + return NS_OK; +} + +inline nsresult +Convert(enum BluetoothAvrcpEvent aIn, btrc_event_id_t& aOut) +{ + static const btrc_event_id_t sEventId[] = { + CONVERT(AVRCP_EVENT_PLAY_STATUS_CHANGED, BTRC_EVT_PLAY_STATUS_CHANGED), + CONVERT(AVRCP_EVENT_TRACK_CHANGE, BTRC_EVT_TRACK_CHANGE), + CONVERT(AVRCP_EVENT_TRACK_REACHED_END, BTRC_EVT_TRACK_REACHED_END), + CONVERT(AVRCP_EVENT_TRACK_REACHED_START, BTRC_EVT_TRACK_REACHED_START), + CONVERT(AVRCP_EVENT_PLAY_POS_CHANGED, BTRC_EVT_PLAY_POS_CHANGED), + CONVERT(AVRCP_EVENT_APP_SETTINGS_CHANGED, BTRC_EVT_APP_SETTINGS_CHANGED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sEventId)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sEventId[aIn]; + return NS_OK; +} + +inline nsresult +Convert(btrc_event_id_t aIn, enum BluetoothAvrcpEvent& aOut) +{ + static const BluetoothAvrcpEvent sEventId[] = { + CONVERT(0, static_cast(0)), // invalid, [0] required by gcc + CONVERT(BTRC_EVT_PLAY_STATUS_CHANGED, AVRCP_EVENT_PLAY_STATUS_CHANGED), + CONVERT(BTRC_EVT_TRACK_CHANGE, AVRCP_EVENT_TRACK_CHANGE), + CONVERT(BTRC_EVT_TRACK_REACHED_END, AVRCP_EVENT_TRACK_REACHED_END), + CONVERT(BTRC_EVT_TRACK_REACHED_START, AVRCP_EVENT_TRACK_REACHED_START), + CONVERT(BTRC_EVT_PLAY_POS_CHANGED, AVRCP_EVENT_PLAY_POS_CHANGED), + CONVERT(6, static_cast(0)), // invalid, [6] required by gcc + CONVERT(7, static_cast(0)), // invalid, [7] required by gcc + CONVERT(BTRC_EVT_APP_SETTINGS_CHANGED, AVRCP_EVENT_APP_SETTINGS_CHANGED) + }; + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sEventId[aIn]; + return NS_OK; +} + +inline nsresult +Convert(btrc_media_attr_t aIn, enum BluetoothAvrcpMediaAttribute& aOut) +{ + static const BluetoothAvrcpMediaAttribute sEventId[] = { + CONVERT(0, static_cast(0)), // invalid, [0] required by gcc + CONVERT(BTRC_MEDIA_ATTR_TITLE, AVRCP_MEDIA_ATTRIBUTE_TITLE), + CONVERT(BTRC_MEDIA_ATTR_ARTIST, AVRCP_MEDIA_ATTRIBUTE_ARTIST), + CONVERT(BTRC_MEDIA_ATTR_ALBUM, AVRCP_MEDIA_ATTRIBUTE_ALBUM), + CONVERT(BTRC_MEDIA_ATTR_TRACK_NUM, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM), + CONVERT(BTRC_MEDIA_ATTR_NUM_TRACKS, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS), + CONVERT(BTRC_MEDIA_ATTR_GENRE, AVRCP_MEDIA_ATTRIBUTE_GENRE), + CONVERT(BTRC_MEDIA_ATTR_PLAYING_TIME, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME) + }; + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sEventId[aIn]; + return NS_OK; +} + +inline nsresult +Convert(enum BluetoothAvrcpNotification aIn, btrc_notification_type_t& aOut) +{ + static const btrc_notification_type_t sNotificationType[] = { + CONVERT(AVRCP_NTF_INTERIM, BTRC_NOTIFICATION_TYPE_INTERIM), + CONVERT(AVRCP_NTF_CHANGED, BTRC_NOTIFICATION_TYPE_CHANGED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sNotificationType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sNotificationType[aIn]; + return NS_OK; +} + +nsresult +Convert(const BluetoothAvrcpElementAttribute& aIn, btrc_element_attr_val_t& aOut); + +nsresult +Convert(const btrc_player_settings_t& aIn, BluetoothAvrcpPlayerSettings& aOut); +#endif // ANDROID_VERSION >= 18 + +#if ANDROID_VERSION >= 19 +inline nsresult +Convert(btrc_remote_features_t aIn, unsigned long& aOut) +{ + /* The input type's name is misleading. The converted value is + * actually a bitmask. + */ + aOut = static_cast(aIn); + return NS_OK; +} +#endif // ANDROID_VERSION >= 19 + +/* |ConvertArray| is a helper for converting arrays. Pass an + * instance of this structure as the first argument to |Convert| + * to convert an array. The output type has to support the array + * subscript operator. + */ +template +struct ConvertArray +{ + ConvertArray(const T* aData, unsigned long aLength) + : mData(aData) + , mLength(aLength) + { } + + const T* mData; + unsigned long mLength; +}; + +/* This implementation of |Convert| converts the elements of an + * array one-by-one. The result data structures must have enough + * memory allocated. + */ +template +inline nsresult +Convert(const ConvertArray& aIn, Tout& aOut) +{ + for (unsigned long i = 0; i < aIn.mLength; ++i) { + nsresult rv = Convert(aIn.mData[i], aOut[i]); + if (NS_FAILED(rv)) { + return rv; + } + } + return NS_OK; +} + +/* This implementation of |Convert| is a helper that automatically + * allocates enough memory to hold the conversion results. The + * actual conversion is performed by the array-conversion helper + * above. + */ +template +inline nsresult +Convert(const ConvertArray& aIn, nsAutoArrayPtr& aOut) +{ + aOut = new Tout[aIn.mLength]; + Tout* out = aOut.get(); + + return Convert(aIn, out); +} + +/* |ConvertDefault| is a helper function to return the result of a + * conversion or a default value if the conversion fails. + */ +template +inline Tout +ConvertDefault(const Tin& aIn, const Tout& aDefault) +{ + Tout out = aDefault; // assignment silences compiler warning + if (NS_FAILED(Convert(aIn, out))) { + return aDefault; + } + return out; +} + +/* This implementation of |Convert| is a helper for copying the + * input value into the output value. It handles all cases that + * need no conversion. + */ +template +inline nsresult +Convert(const T& aIn, T& aOut) +{ + aOut = aIn; + + return NS_OK; +} + +nsresult +Convert(const bt_property_t& aIn, BluetoothProperty& aOut); + +// +// Result handling +// + +template +class BluetoothHALInterfaceRunnable0 : public nsRunnable +{ +public: + BluetoothHALInterfaceRunnable0(Obj* aObj, Res (Obj::*aMethod)()) + : mObj(aObj) + , mMethod(aMethod) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(); + return NS_OK; + } + +private: + nsRefPtr mObj; + void (Obj::*mMethod)(); +}; + +template +class BluetoothHALInterfaceRunnable1 : public nsRunnable +{ +public: + BluetoothHALInterfaceRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1), + const Arg1& aArg1) + : mObj(aObj) + , mMethod(aMethod) + , mArg1(aArg1) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(mArg1); + return NS_OK; + } + +private: + nsRefPtr mObj; + Res (Obj::*mMethod)(Arg1); + Tin1 mArg1; +}; + +template +class BluetoothHALInterfaceRunnable3 : public nsRunnable +{ +public: + BluetoothHALInterfaceRunnable3(Obj* aObj, + Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + const Arg1& aArg1, const Arg2& aArg2, + const Arg3& aArg3) + : mObj(aObj) + , mMethod(aMethod) + , mArg1(aArg1) + , mArg2(aArg2) + , mArg3(aArg3) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(mArg1, mArg2, mArg3); + return NS_OK; + } + +private: + nsRefPtr mObj; + Res (Obj::*mMethod)(Arg1, Arg2, Arg3); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; +}; + +// +// Notification handling +// + +template +class BluetoothNotificationHALRunnable0 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable0 SelfType; + + static already_AddRefed Create(Res (ObjectType::*aMethod)()) + { + nsRefPtr runnable(new SelfType(aMethod)); + + return runnable.forget(); + } + + static void + Dispatch(Res (ObjectType::*aMethod)()) + { + nsRefPtr runnable = Create(aMethod); + + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable0::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable0(Res (ObjectType::*aMethod)()) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + Res (ObjectType::*mMethod)(); +}; + +template +class BluetoothNotificationHALRunnable1 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable1 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1), const T1& aIn1) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED(runnable->ConvertAndSet(aIn1))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1), const T1& aIn1) + { + nsRefPtr runnable = Create(aMethod, aIn1); + + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable1::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable1(Res (ObjectType::*aMethod)(Arg1)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + ConvertAndSet(const T1& aIn1) + { + nsresult rv = Convert(aIn1, mArg1); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)(Arg1); + Tin1 mArg1; +}; + +template +class BluetoothNotificationHALRunnable2 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable2 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2), const T1& aIn1, const T2& aIn2) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), + const T1& aIn1, const T2& aIn2) + { + nsRefPtr runnable = Create(aMethod, aIn1, aIn2); + + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable2::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable2( + Res (ObjectType::*aMethod)(Arg1, Arg2)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + ConvertAndSet(const T1& aIn1, const T2& aIn2) + { + nsresult rv = Convert(aIn1, mArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn2, mArg2); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)(Arg1, Arg2); + Tin1 mArg1; + Tin2 mArg2; +}; + +template +class BluetoothNotificationHALRunnable3 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable3 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), + const T1& aIn1, const T2& aIn2, const T3& aIn3) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), + const T1& aIn1, const T2& aIn2, const T3& aIn3) + { + nsRefPtr runnable = Create(aMethod, aIn1, aIn2, aIn3); + + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable3::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable3( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + ConvertAndSet(const T1& aIn1, const T2& aIn2, const T3& aIn3) + { + nsresult rv = Convert(aIn1, mArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn2, mArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn3, mArg3); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; +}; + +template +class BluetoothNotificationHALRunnable4 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable4 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3, aIn4))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4) + { + nsRefPtr runnable = Create(aMethod, aIn1, aIn2, aIn3, aIn4); + + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable4::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable4( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + ConvertAndSet(const T1& aIn1, const T2& aIn2, + const T3& aIn3, const T4& aIn4) + { + nsresult rv = Convert(aIn1, mArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn2, mArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn3, mArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn4, mArg4); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; + Tin4 mArg4; +}; + +template +class BluetoothNotificationHALRunnable5 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothNotificationHALRunnable5 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + const T1& aIn1, const T2& aIn2, const T3& aIn3, + const T4& aIn4, const T5& aIn5) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3, aIn4, aIn5))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + const T1& aIn1, const T2& aIn2, const T3& aIn3, + const T4& aIn4, const T5& aIn5) + { + nsRefPtr runnable = Create(aMethod, + aIn1, aIn2, aIn3, aIn4, aIn5); + if (!runnable) { + BT_WARNING("BluetoothNotificationHALRunnable5::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4, mArg5); + } + return NS_OK; + } + +private: + BluetoothNotificationHALRunnable5( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + ConvertAndSet(const T1& aIn1, const T2& aIn2, const T3& aIn3, + const T4& aIn4, const T5& aIn5) + { + nsresult rv = Convert(aIn1, mArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn2, mArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn3, mArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn4, mArg4); + if (NS_FAILED(rv)) { + return rv; + } + rv = Convert(aIn5, mArg5); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; + Tin4 mArg4; + Tin5 mArg5; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothHALInterface.cpp b/dom/bluetooth/bluedroid/BluetoothHALInterface.cpp new file mode 100644 index 000000000000..e7527181e2e7 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHALInterface.cpp @@ -0,0 +1,913 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothHALInterface.h" +#include "BluetoothHALHelpers.h" +#include "BluetoothA2dpHALInterface.h" +#include "BluetoothAvrcpHALInterface.h" +#include "BluetoothHandsfreeHALInterface.h" +#include "BluetoothSocketHALInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +template +struct interface_traits +{ }; + +template<> +struct interface_traits +{ + typedef const btsock_interface_t const_interface_type; + + static const char* profile_id() + { + return BT_PROFILE_SOCKETS_ID; + } +}; + +template<> +struct interface_traits +{ + typedef const bthf_interface_t const_interface_type; + + static const char* profile_id() + { + return BT_PROFILE_HANDSFREE_ID; + } +}; + +template<> +struct interface_traits +{ + typedef const btav_interface_t const_interface_type; + + static const char* profile_id() + { + return BT_PROFILE_ADVANCED_AUDIO_ID; + } +}; + +#if ANDROID_VERSION >= 18 +template<> +struct interface_traits +{ + typedef const btrc_interface_t const_interface_type; + + static const char* profile_id() + { + return BT_PROFILE_AV_RC_ID; + } +}; +#endif + +typedef + BluetoothHALInterfaceRunnable0 + BluetoothHALResultRunnable; + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothHALErrorRunnable; + +static nsresult +DispatchBluetoothHALResult(BluetoothResultHandler* aRes, + void (BluetoothResultHandler::*aMethod)(), + BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothHALResultRunnable(aRes, aMethod); + } else { + runnable = new BluetoothHALErrorRunnable( + aRes, &BluetoothResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +// Notification handling +// + +static BluetoothNotificationHandler* sNotificationHandler; + +struct BluetoothCallback +{ + class NotificationHandlerWrapper + { + public: + typedef BluetoothNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sNotificationHandler; + } + }; + + // Notifications + + typedef BluetoothNotificationHALRunnable1 + AdapterStateChangedNotification; + + typedef BluetoothNotificationHALRunnable3, + BluetoothStatus, int, + const BluetoothProperty*> + AdapterPropertiesNotification; + + typedef BluetoothNotificationHALRunnable4, + BluetoothStatus, const nsAString&, + int, const BluetoothProperty*> + RemoteDevicePropertiesNotification; + + typedef BluetoothNotificationHALRunnable2, + int, const BluetoothProperty*> + DeviceFoundNotification; + + typedef BluetoothNotificationHALRunnable1 + DiscoveryStateChangedNotification; + + typedef BluetoothNotificationHALRunnable3 + PinRequestNotification; + + typedef BluetoothNotificationHALRunnable5 + SspRequestNotification; + + typedef BluetoothNotificationHALRunnable3 + BondStateChangedNotification; + + typedef BluetoothNotificationHALRunnable3 + AclStateChangedNotification; + + typedef BluetoothNotificationHALRunnable3, + uint8_t, uint16_t, const uint8_t*> + DutModeRecvNotification; + + typedef BluetoothNotificationHALRunnable2 + LeTestModeNotification; + + // Bluedroid callbacks + + static const bt_property_t* + AlignedProperties(bt_property_t* aProperties, size_t aNumProperties, + nsAutoArrayPtr& aPropertiesArray) + { + // See Bug 989976: consider aProperties address is not aligned. If + // it is aligned, we return the pointer directly; otherwise we make + // an aligned copy. The argument |aPropertiesArray| keeps track of + // the memory buffer. + if (!(reinterpret_cast(aProperties) % sizeof(void*))) { + return aProperties; + } + + bt_property_t* properties = new bt_property_t[aNumProperties]; + memcpy(properties, aProperties, aNumProperties * sizeof(*properties)); + aPropertiesArray = properties; + + return properties; + } + + static void + AdapterStateChanged(bt_state_t aStatus) + { + AdapterStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::AdapterStateChangedNotification, + aStatus); + } + + static void + AdapterProperties(bt_status_t aStatus, int aNumProperties, + bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + AdapterPropertiesNotification::Dispatch( + &BluetoothNotificationHandler::AdapterPropertiesNotification, + ConvertDefault(aStatus, STATUS_FAIL), aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + RemoteDeviceProperties(bt_status_t aStatus, bt_bdaddr_t* aBdAddress, + int aNumProperties, bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + RemoteDevicePropertiesNotification::Dispatch( + &BluetoothNotificationHandler::RemoteDevicePropertiesNotification, + ConvertDefault(aStatus, STATUS_FAIL), aBdAddress, aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + DeviceFound(int aNumProperties, bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + DeviceFoundNotification::Dispatch( + &BluetoothNotificationHandler::DeviceFoundNotification, + aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + DiscoveryStateChanged(bt_discovery_state_t aState) + { + DiscoveryStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::DiscoveryStateChangedNotification, + aState); + } + + static void + PinRequest(bt_bdaddr_t* aRemoteBdAddress, + bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass) + { + PinRequestNotification::Dispatch( + &BluetoothNotificationHandler::PinRequestNotification, + aRemoteBdAddress, aRemoteBdName, aRemoteClass); + } + + static void + SspRequest(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName, + uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant, + uint32_t aPasskey) + { + SspRequestNotification::Dispatch( + &BluetoothNotificationHandler::SspRequestNotification, + aRemoteBdAddress, aRemoteBdName, aRemoteClass, + aPairingVariant, aPasskey); + } + + static void + BondStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, + bt_bond_state_t aState) + { + BondStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::BondStateChangedNotification, + aStatus, aRemoteBdAddress, aState); + } + + static void + AclStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, + bt_acl_state_t aState) + { + AclStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::AclStateChangedNotification, + aStatus, aRemoteBdAddress, aState); + } + + static void + ThreadEvt(bt_cb_thread_evt evt) + { + // This callback maintains internal state and is not exported. + } + + static void + DutModeRecv(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen) + { + DutModeRecvNotification::Dispatch( + &BluetoothNotificationHandler::DutModeRecvNotification, + aOpcode, ConvertArray(aBuf, aLen), aLen); + } + + static void + LeTestMode(bt_status_t aStatus, uint16_t aNumPackets) + { + LeTestModeNotification::Dispatch( + &BluetoothNotificationHandler::LeTestModeNotification, + aStatus, aNumPackets); + } +}; + +// Interface +// + +/* returns the container structure of a variable; _t is the container's + * type, _v the name of the variable, and _m is _v's field within _t + */ +#define container(_t, _v, _m) \ + ( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) ) + +BluetoothHALInterface* +BluetoothHALInterface::GetInstance() +{ + static BluetoothHALInterface* sBluetoothInterface; + + if (sBluetoothInterface) { + return sBluetoothInterface; + } + + /* get driver module */ + + const hw_module_t* module; + int err = hw_get_module(BT_HARDWARE_MODULE_ID, &module); + if (err) { + BT_WARNING("hw_get_module failed: %s", strerror(err)); + return nullptr; + } + + /* get device */ + + hw_device_t* device; + err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); + if (err) { + BT_WARNING("open failed: %s", strerror(err)); + return nullptr; + } + + const bluetooth_device_t* bt_device = + container(bluetooth_device_t, device, common); + + /* get interface */ + + const bt_interface_t* bt_interface = bt_device->get_bluetooth_interface(); + if (!bt_interface) { + BT_WARNING("get_bluetooth_interface failed"); + goto err_get_bluetooth_interface; + } + + if (bt_interface->size != sizeof(*bt_interface)) { + BT_WARNING("interface of incorrect size"); + goto err_bt_interface_size; + } + + sBluetoothInterface = new BluetoothHALInterface(bt_interface); + + return sBluetoothInterface; + +err_bt_interface_size: +err_get_bluetooth_interface: + err = device->close(device); + if (err) { + BT_WARNING("close failed: %s", strerror(err)); + } + return nullptr; +} + +BluetoothHALInterface::BluetoothHALInterface( + const bt_interface_t* aInterface) +: mInterface(aInterface) +{ + MOZ_ASSERT(mInterface); +} + +BluetoothHALInterface::~BluetoothHALInterface() +{ } + +void +BluetoothHALInterface::Init( + BluetoothNotificationHandler* aNotificationHandler, + BluetoothResultHandler* aRes) +{ + static bt_callbacks_t sBluetoothCallbacks = { + sizeof(sBluetoothCallbacks), + BluetoothCallback::AdapterStateChanged, + BluetoothCallback::AdapterProperties, + BluetoothCallback::RemoteDeviceProperties, + BluetoothCallback::DeviceFound, + BluetoothCallback::DiscoveryStateChanged, + BluetoothCallback::PinRequest, + BluetoothCallback::SspRequest, + BluetoothCallback::BondStateChanged, + BluetoothCallback::AclStateChanged, + BluetoothCallback::ThreadEvt, + BluetoothCallback::DutModeRecv, +#if ANDROID_VERSION >= 18 + BluetoothCallback::LeTestMode +#endif + }; + + sNotificationHandler = aNotificationHandler; + + int status = mInterface->init(&sBluetoothCallbacks); + + if (aRes) { + DispatchBluetoothHALResult(aRes, &BluetoothResultHandler::Init, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::Cleanup(BluetoothResultHandler* aRes) +{ + mInterface->cleanup(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, &BluetoothResultHandler::Cleanup, + STATUS_SUCCESS); + } + + sNotificationHandler = nullptr; +} + +void +BluetoothHALInterface::Enable(BluetoothResultHandler* aRes) +{ + int status = mInterface->enable(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, &BluetoothResultHandler::Enable, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::Disable(BluetoothResultHandler* aRes) +{ + int status = mInterface->disable(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, &BluetoothResultHandler::Disable, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Adapter Properties */ + +void +BluetoothHALInterface::GetAdapterProperties(BluetoothResultHandler* aRes) +{ + int status = mInterface->get_adapter_properties(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetAdapterProperties, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::GetAdapterProperty(const nsAString& aName, + BluetoothResultHandler* aRes) +{ + int status; + bt_property_type_t type; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (false /* TODO: we don't support any values for aName currently */) { + status = mInterface->get_adapter_property(type); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetAdapterProperties, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::SetAdapterProperty( + const BluetoothNamedValue& aProperty, BluetoothResultHandler* aRes) +{ + int status; + ConvertNamedValue convertProperty(aProperty); + bt_property_t property; + + if (NS_SUCCEEDED(Convert(convertProperty, property))) { + status = mInterface->set_adapter_property(&property); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::SetAdapterProperty, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Remote Device Properties */ + +void +BluetoothHALInterface::GetRemoteDeviceProperties( + const nsAString& aRemoteAddr, BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t addr; + + if (NS_SUCCEEDED(Convert(aRemoteAddr, addr))) { + status = mInterface->get_remote_device_properties(&addr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetRemoteDeviceProperties, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::GetRemoteDeviceProperty( + const nsAString& aRemoteAddr, const nsAString& aName, + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t remoteAddr; + bt_property_type_t name; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && + false /* TODO: we don't support any values for aName currently */) { + status = mInterface->get_remote_device_property(&remoteAddr, name); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetRemoteDeviceProperty, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::SetRemoteDeviceProperty( + const nsAString& aRemoteAddr, const BluetoothNamedValue& aProperty, + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t remoteAddr; + bt_property_t property; + + /* FIXME: you need to implement the missing conversion functions */ + NS_NOTREACHED("Conversion function missing"); + + if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && + false /* TODO: we don't support any values for aProperty currently */) { + status = mInterface->set_remote_device_property(&remoteAddr, &property); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::SetRemoteDeviceProperty, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Remote Services */ + +void +BluetoothHALInterface::GetRemoteServiceRecord(const nsAString& aRemoteAddr, + const uint8_t aUuid[16], + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t remoteAddr; + bt_uuid_t uuid; + + if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && + NS_SUCCEEDED(Convert(aUuid, uuid))) { + status = mInterface->get_remote_service_record(&remoteAddr, &uuid); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetRemoteServiceRecord, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::GetRemoteServices(const nsAString& aRemoteAddr, + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t remoteAddr; + + if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr))) { + status = mInterface->get_remote_services(&remoteAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::GetRemoteServices, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Discovery */ + +void +BluetoothHALInterface::StartDiscovery(BluetoothResultHandler* aRes) +{ + int status = mInterface->start_discovery(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::StartDiscovery, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::CancelDiscovery(BluetoothResultHandler* aRes) +{ + int status = mInterface->cancel_discovery(); + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::CancelDiscovery, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Bonds */ + +void +BluetoothHALInterface::CreateBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) +{ + bt_bdaddr_t bdAddr; + int status; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->create_bond(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::CreateBond, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::RemoveBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) +{ + bt_bdaddr_t bdAddr; + int status; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->remove_bond(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::RemoveBond, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::CancelBond(const nsAString& aBdAddr, + BluetoothResultHandler* aRes) +{ + bt_bdaddr_t bdAddr; + int status; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->cancel_bond(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::CancelBond, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Authentication */ + +void +BluetoothHALInterface::PinReply(const nsAString& aBdAddr, bool aAccept, + const nsAString& aPinCode, + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t bdAddr; + uint8_t accept; + bt_pin_code_t pinCode; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && + NS_SUCCEEDED(Convert(aAccept, accept)) && + NS_SUCCEEDED(Convert(aPinCode, pinCode))) { + status = mInterface->pin_reply(&bdAddr, accept, aPinCode.Length(), + &pinCode); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::PinReply, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::SspReply(const nsAString& aBdAddr, + const nsAString& aVariant, + bool aAccept, uint32_t aPasskey, + BluetoothResultHandler* aRes) +{ + int status; + bt_bdaddr_t bdAddr; + bt_ssp_variant_t variant; + uint8_t accept; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && + NS_SUCCEEDED(Convert(aVariant, variant)) && + NS_SUCCEEDED(Convert(aAccept, accept))) { + status = mInterface->ssp_reply(&bdAddr, variant, accept, aPasskey); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::SspReply, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* DUT Mode */ + +void +BluetoothHALInterface::DutModeConfigure(bool aEnable, + BluetoothResultHandler* aRes) +{ + int status; + uint8_t enable; + + if (NS_SUCCEEDED(Convert(aEnable, enable))) { + status = mInterface->dut_mode_configure(enable); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::DutModeConfigure, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHALInterface::DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes) +{ + int status = mInterface->dut_mode_send(aOpcode, aBuf, aLen); + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::DutModeSend, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* LE Mode */ + +void +BluetoothHALInterface::LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes) +{ +#if ANDROID_VERSION >= 18 + int status = mInterface->le_test_mode(aOpcode, aBuf, aLen); +#else + int status = BT_STATUS_UNSUPPORTED; +#endif + + if (aRes) { + DispatchBluetoothHALResult(aRes, + &BluetoothResultHandler::LeTestMode, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Profile Interfaces */ + +template +T* +BluetoothHALInterface::CreateProfileInterface() +{ + typename interface_traits::const_interface_type* interface = + reinterpret_cast::const_interface_type*>( + mInterface->get_profile_interface(interface_traits::profile_id())); + + if (!interface) { + BT_WARNING("Bluetooth profile '%s' is not supported", + interface_traits::profile_id()); + return nullptr; + } + + if (interface->size != sizeof(*interface)) { + BT_WARNING("interface of incorrect size"); + return nullptr; + } + + return new T(interface); +} + +#if ANDROID_VERSION < 18 +/* + * Bluedroid versions that don't support AVRCP will call this function + * to create an AVRCP interface. All interface methods will fail with + * the error constant STATUS_UNSUPPORTED. + */ +template <> +BluetoothAvrcpHALInterface* +BluetoothHALInterface::CreateProfileInterface() +{ + BT_WARNING("Bluetooth profile 'avrcp' is not supported"); + + return new BluetoothAvrcpHALInterface(); +} +#endif + +template +T* +BluetoothHALInterface::GetProfileInterface() +{ + static T* sBluetoothProfileInterface; + + if (sBluetoothProfileInterface) { + return sBluetoothProfileInterface; + } + + sBluetoothProfileInterface = CreateProfileInterface(); + + return sBluetoothProfileInterface; +} + +BluetoothSocketInterface* +BluetoothHALInterface::GetBluetoothSocketInterface() +{ + return GetProfileInterface(); +} + +BluetoothHandsfreeInterface* +BluetoothHALInterface::GetBluetoothHandsfreeInterface() +{ + return GetProfileInterface(); +} + +BluetoothA2dpInterface* +BluetoothHALInterface::GetBluetoothA2dpInterface() +{ + return GetProfileInterface(); +} + +BluetoothAvrcpInterface* +BluetoothHALInterface::GetBluetoothAvrcpInterface() +{ + return GetProfileInterface(); +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothHALInterface.h b/dom/bluetooth/bluedroid/BluetoothHALInterface.h new file mode 100644 index 000000000000..9c81eab79c7a --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHALInterface.h @@ -0,0 +1,110 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothhalinterface_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetoothhalinterface_h__ + +#include +#include "BluetoothInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothHALInterface MOZ_FINAL : public BluetoothInterface +{ +public: + static BluetoothHALInterface* GetInstance(); + + void Init(BluetoothNotificationHandler* aNotificationHandler, + BluetoothResultHandler* aRes); + void Cleanup(BluetoothResultHandler* aRes); + + void Enable(BluetoothResultHandler* aRes); + void Disable(BluetoothResultHandler* aRes); + + + /* Adapter Properties */ + + void GetAdapterProperties(BluetoothResultHandler* aRes); + void GetAdapterProperty(const nsAString& aName, + BluetoothResultHandler* aRes); + void SetAdapterProperty(const BluetoothNamedValue& aProperty, + BluetoothResultHandler* aRes); + + /* Remote Device Properties */ + + void GetRemoteDeviceProperties(const nsAString& aRemoteAddr, + BluetoothResultHandler* aRes); + void GetRemoteDeviceProperty(const nsAString& aRemoteAddr, + const nsAString& aName, + BluetoothResultHandler* aRes); + void SetRemoteDeviceProperty(const nsAString& aRemoteAddr, + const BluetoothNamedValue& aProperty, + BluetoothResultHandler* aRes); + + /* Remote Services */ + + void GetRemoteServiceRecord(const nsAString& aRemoteAddr, + const uint8_t aUuid[16], + BluetoothResultHandler* aRes); + void GetRemoteServices(const nsAString& aRemoteAddr, + BluetoothResultHandler* aRes); + + /* Discovery */ + + void StartDiscovery(BluetoothResultHandler* aRes); + void CancelDiscovery(BluetoothResultHandler* aRes); + + /* Bonds */ + + void CreateBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); + void RemoveBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); + void CancelBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes); + + /* Authentication */ + + void PinReply(const nsAString& aBdAddr, bool aAccept, + const nsAString& aPinCode, + BluetoothResultHandler* aRes); + + void SspReply(const nsAString& aBdAddr, const nsAString& aVariant, + bool aAccept, uint32_t aPasskey, + BluetoothResultHandler* aRes); + + /* DUT Mode */ + + void DutModeConfigure(bool aEnable, BluetoothResultHandler* aRes); + void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes); + + /* LE Mode */ + + void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, + BluetoothResultHandler* aRes); + + /* Profile Interfaces */ + + BluetoothSocketInterface* GetBluetoothSocketInterface(); + BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface(); + BluetoothA2dpInterface* GetBluetoothA2dpInterface(); + BluetoothAvrcpInterface* GetBluetoothAvrcpInterface(); + +protected: + BluetoothHALInterface(const bt_interface_t* aInterface); + ~BluetoothHALInterface(); + +private: + template + T* CreateProfileInterface(); + + template + T* GetProfileInterface(); + + const bt_interface_t* mInterface; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.cpp b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.cpp new file mode 100644 index 000000000000..b996363d59b8 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.cpp @@ -0,0 +1,616 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothHandsfreeHALInterface.h" +#include "BluetoothHALHelpers.h" + +BEGIN_BLUETOOTH_NAMESPACE + +typedef + BluetoothHALInterfaceRunnable0 + BluetoothHandsfreeHALResultRunnable; + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothHandsfreeHALErrorRunnable; + +static nsresult +DispatchBluetoothHandsfreeHALResult( + BluetoothHandsfreeResultHandler* aRes, + void (BluetoothHandsfreeResultHandler::*aMethod)(), + BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothHandsfreeHALResultRunnable(aRes, aMethod); + } else { + runnable = new BluetoothHandsfreeHALErrorRunnable(aRes, + &BluetoothHandsfreeResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +// Notification handling +// + +static BluetoothHandsfreeNotificationHandler* sHandsfreeNotificationHandler; + +struct BluetoothHandsfreeHALCallback +{ + class HandsfreeNotificationHandlerWrapper + { + public: + typedef BluetoothHandsfreeNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sHandsfreeNotificationHandler; + } + }; + + // Notifications + + typedef BluetoothNotificationHALRunnable2< + HandsfreeNotificationHandlerWrapper, void, + BluetoothHandsfreeConnectionState, nsString, + BluetoothHandsfreeConnectionState, const nsAString&> + ConnectionStateNotification; + + typedef BluetoothNotificationHALRunnable2< + HandsfreeNotificationHandlerWrapper, void, + BluetoothHandsfreeAudioState, nsString, + BluetoothHandsfreeAudioState, const nsAString&> + AudioStateNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, + BluetoothHandsfreeVoiceRecognitionState> + VoiceRecognitionNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + AnswerCallNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + HangupCallNotification; + + typedef BluetoothNotificationHALRunnable2< + HandsfreeNotificationHandlerWrapper, void, + BluetoothHandsfreeVolumeType, int> + VolumeNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, nsString, const nsAString&> + DialCallNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, char> + DtmfNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, BluetoothHandsfreeNRECState> + NRECNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, BluetoothHandsfreeCallHoldType> + CallHoldNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + CnumNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + CindNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + CopsNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + ClccNotification; + + typedef BluetoothNotificationHALRunnable1< + HandsfreeNotificationHandlerWrapper, void, nsCString, const nsACString&> + UnknownAtNotification; + + typedef BluetoothNotificationHALRunnable0< + HandsfreeNotificationHandlerWrapper, void> + KeyPressedNotification; + + // Bluedroid Handsfree callbacks + + static void + ConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddr) + { + ConnectionStateNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::ConnectionStateNotification, + aState, aBdAddr); + } + + static void + AudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddr) + { + AudioStateNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::AudioStateNotification, + aState, aBdAddr); + } + + static void + VoiceRecognition(bthf_vr_state_t aState) + { + VoiceRecognitionNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification, + aState); + } + + static void + AnswerCall() + { + AnswerCallNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::AnswerCallNotification); + } + + static void + HangupCall() + { + HangupCallNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::HangupCallNotification); + } + + static void + Volume(bthf_volume_type_t aType, int aVolume) + { + VolumeNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::VolumeNotification, + aType, aVolume); + } + + static void + DialCall(char* aNumber) + { + DialCallNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::DialCallNotification, aNumber); + } + + static void + Dtmf(char aDtmf) + { + DtmfNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::DtmfNotification, aDtmf); + } + + static void + NoiseReductionEchoCancellation(bthf_nrec_t aNrec) + { + NRECNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::NRECNotification, aNrec); + } + + static void + CallHold(bthf_chld_type_t aChld) + { + CallHoldNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::CallHoldNotification, aChld); + } + + static void + Cnum() + { + CnumNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::CnumNotification); + } + + static void + Cind() + { + CindNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::CindNotification); + } + + static void + Cops() + { + CopsNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::CopsNotification); + } + + static void + Clcc() + { + ClccNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::ClccNotification); + } + + static void + UnknownAt(char* aAtString) + { + UnknownAtNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::UnknownAtNotification, + aAtString); + } + + static void + KeyPressed() + { + KeyPressedNotification::Dispatch( + &BluetoothHandsfreeNotificationHandler::KeyPressedNotification); + } +}; + +// Interface +// + +BluetoothHandsfreeHALInterface::BluetoothHandsfreeHALInterface( + const bthf_interface_t* aInterface) +: mInterface(aInterface) +{ + MOZ_ASSERT(mInterface); +} + +BluetoothHandsfreeHALInterface::~BluetoothHandsfreeHALInterface() +{ } + +void +BluetoothHandsfreeHALInterface::Init( + BluetoothHandsfreeNotificationHandler* aNotificationHandler, + BluetoothHandsfreeResultHandler* aRes) +{ + static bthf_callbacks_t sCallbacks = { + sizeof(sCallbacks), + BluetoothHandsfreeHALCallback::ConnectionState, + BluetoothHandsfreeHALCallback::AudioState, + BluetoothHandsfreeHALCallback::VoiceRecognition, + BluetoothHandsfreeHALCallback::AnswerCall, + BluetoothHandsfreeHALCallback::HangupCall, + BluetoothHandsfreeHALCallback::Volume, + BluetoothHandsfreeHALCallback::DialCall, + BluetoothHandsfreeHALCallback::Dtmf, + BluetoothHandsfreeHALCallback::NoiseReductionEchoCancellation, + BluetoothHandsfreeHALCallback::CallHold, + BluetoothHandsfreeHALCallback::Cnum, + BluetoothHandsfreeHALCallback::Cind, + BluetoothHandsfreeHALCallback::Cops, + BluetoothHandsfreeHALCallback::Clcc, + BluetoothHandsfreeHALCallback::UnknownAt, + BluetoothHandsfreeHALCallback::KeyPressed + }; + + sHandsfreeNotificationHandler = aNotificationHandler; + + bt_status_t status = mInterface->init(&sCallbacks); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::Init, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::Cleanup( + BluetoothHandsfreeResultHandler* aRes) +{ + mInterface->cleanup(); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::Cleanup, STATUS_SUCCESS); + } +} + +/* Connect / Disconnect */ + +void +BluetoothHandsfreeHALInterface::Connect( + const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->connect(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::Connect, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::Disconnect( + const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->disconnect(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::Disconnect, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::ConnectAudio( + const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->connect_audio(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::ConnectAudio, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::DisconnectAudio( + const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bt_bdaddr_t bdAddr; + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { + status = mInterface->disconnect_audio(&bdAddr); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::DisconnectAudio, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Voice Recognition */ + +void +BluetoothHandsfreeHALInterface::StartVoiceRecognition( + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status = mInterface->start_voice_recognition(); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::StartVoiceRecognition, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::StopVoiceRecognition( + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status = mInterface->stop_voice_recognition(); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::StopVoiceRecognition, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Volume */ + +void +BluetoothHandsfreeHALInterface::VolumeControl( + BluetoothHandsfreeVolumeType aType, int aVolume, + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_volume_type_t type = BTHF_VOLUME_TYPE_SPK; + + if (NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->volume_control(type, aVolume); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::VolumeControl, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Device status */ + +void +BluetoothHandsfreeHALInterface::DeviceStatusNotification( + BluetoothHandsfreeNetworkState aNtkState, + BluetoothHandsfreeServiceType aSvcType, int aSignal, + int aBattChg, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_network_state_t ntkState = BTHF_NETWORK_STATE_NOT_AVAILABLE; + bthf_service_type_t svcType = BTHF_SERVICE_TYPE_HOME; + + if (NS_SUCCEEDED(Convert(aNtkState, ntkState)) && + NS_SUCCEEDED(Convert(aSvcType, svcType))) { + status = mInterface->device_status_notification(ntkState, svcType, + aSignal, aBattChg); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::DeviceStatusNotification, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Responses */ + +void +BluetoothHandsfreeHALInterface::CopsResponse( + const char* aCops, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status = mInterface->cops_response(aCops); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::CopsResponse, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::CindResponse( + int aSvc, int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, + int aSignal, int aRoam, int aBattChg, + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_call_state_t callSetupState = BTHF_CALL_STATE_ACTIVE; + + if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState))) { + status = mInterface->cind_response(aSvc, aNumActive, aNumHeld, + callSetupState, aSignal, + aRoam, aBattChg); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::CindResponse, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::FormattedAtResponse( + const char* aRsp, BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status = mInterface->formatted_at_response(aRsp); + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::FormattedAtResponse, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::AtResponse( + BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode, + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_at_response_t responseCode = BTHF_AT_RESPONSE_ERROR; + + if (NS_SUCCEEDED(Convert(aResponseCode, responseCode))) { + status = mInterface->at_response(responseCode, aErrorCode); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::AtResponse, + ConvertDefault(status, STATUS_FAIL)); + } +} + +void +BluetoothHandsfreeHALInterface::ClccResponse( + int aIndex, + BluetoothHandsfreeCallDirection aDir, + BluetoothHandsfreeCallState aState, + BluetoothHandsfreeCallMode aMode, + BluetoothHandsfreeCallMptyType aMpty, + const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_call_direction_t dir = BTHF_CALL_DIRECTION_OUTGOING; + bthf_call_state_t state = BTHF_CALL_STATE_ACTIVE; + bthf_call_mode_t mode = BTHF_CALL_TYPE_VOICE; + bthf_call_mpty_type_t mpty = BTHF_CALL_MPTY_TYPE_SINGLE; + bthf_call_addrtype_t type = BTHF_CALL_ADDRTYPE_UNKNOWN; + + if (NS_SUCCEEDED(Convert(aDir, dir)) && + NS_SUCCEEDED(Convert(aState, state)) && + NS_SUCCEEDED(Convert(aMode, mode)) && + NS_SUCCEEDED(Convert(aMpty, mpty)) && + NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->clcc_response(aIndex, dir, state, mode, mpty, + NS_ConvertUTF16toUTF8(aNumber).get(), + type); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::ClccResponse, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Phone State */ + +void +BluetoothHandsfreeHALInterface::PhoneStateChange(int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes) +{ + bt_status_t status; + bthf_call_state_t callSetupState = BTHF_CALL_STATE_ACTIVE; + bthf_call_addrtype_t type = BTHF_CALL_ADDRTYPE_UNKNOWN; + + if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState)) && + NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->phone_state_change( + aNumActive, aNumHeld, callSetupState, + NS_ConvertUTF16toUTF8(aNumber).get(), type); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothHandsfreeHALResult( + aRes, &BluetoothHandsfreeResultHandler::PhoneStateChange, + ConvertDefault(status, STATUS_FAIL)); + } +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.h b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.h new file mode 100644 index 000000000000..f53d4251fb65 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.h @@ -0,0 +1,95 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothhandsfreehalinterface_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetoothhandsfreehalinterface_h__ + +#include +#include +#include "BluetoothCommon.h" +#include "BluetoothInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothHALInterface; + +class BluetoothHandsfreeHALInterface MOZ_FINAL + : public BluetoothHandsfreeInterface +{ +public: + friend class BluetoothHALInterface; + + void Init(BluetoothHandsfreeNotificationHandler* aNotificationHandler, + BluetoothHandsfreeResultHandler* aRes); + void Cleanup(BluetoothHandsfreeResultHandler* aRes); + + /* Connect / Disconnect */ + + void Connect(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes); + void Disconnect(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes); + void ConnectAudio(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes); + void DisconnectAudio(const nsAString& aBdAddr, + BluetoothHandsfreeResultHandler* aRes); + + /* Voice Recognition */ + + void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes); + void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes); + + /* Volume */ + + void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume, + BluetoothHandsfreeResultHandler* aRes); + + /* Device status */ + + void DeviceStatusNotification(BluetoothHandsfreeNetworkState aNtkState, + BluetoothHandsfreeServiceType aSvcType, + int aSignal, int aBattChg, + BluetoothHandsfreeResultHandler* aRes); + + /* Responses */ + + void CopsResponse(const char* aCops, + BluetoothHandsfreeResultHandler* aRes); + void CindResponse(int aSvc, int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, int aSignal, + int aRoam, int aBattChg, + BluetoothHandsfreeResultHandler* aRes); + void FormattedAtResponse(const char* aRsp, + BluetoothHandsfreeResultHandler* aRes); + void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode, + BluetoothHandsfreeResultHandler* aRes); + void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir, + BluetoothHandsfreeCallState aState, + BluetoothHandsfreeCallMode aMode, + BluetoothHandsfreeCallMptyType aMpty, + const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes); + + /* Phone State */ + + void PhoneStateChange(int aNumActive, int aNumHeld, + BluetoothHandsfreeCallState aCallSetupState, + const nsAString& aNumber, + BluetoothHandsfreeCallAddressType aType, + BluetoothHandsfreeResultHandler* aRes); + +protected: + BluetoothHandsfreeHALInterface(const bthf_interface_t* aInterface); + ~BluetoothHandsfreeHALInterface(); + +private: + const bthf_interface_t* mInterface; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothInterface.cpp b/dom/bluetooth/bluedroid/BluetoothInterface.cpp deleted file mode 100644 index 17e8feeb6985..000000000000 --- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp +++ /dev/null @@ -1,4427 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "BluetoothInterface.h" -#include -#include -#include -#include "base/message_loop.h" -#include "nsAutoPtr.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" - -#if MOZ_IS_GCC && MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) -/* use designated array initializers if supported */ -#define CONVERT(in_, out_) \ - [in_] = out_ -#else -/* otherwise init array element by position */ -#define CONVERT(in_, out_) \ - out_ -#endif - -#define MAX_UUID_SIZE 16 - -BEGIN_BLUETOOTH_NAMESPACE - -template -struct interface_traits -{ }; - -// -// Conversion -// - -static nsresult -Convert(bt_status_t aIn, BluetoothStatus& aOut) -{ - static const BluetoothStatus sStatus[] = { - CONVERT(BT_STATUS_SUCCESS, STATUS_SUCCESS), - CONVERT(BT_STATUS_FAIL, STATUS_FAIL), - CONVERT(BT_STATUS_NOT_READY, STATUS_NOT_READY), - CONVERT(BT_STATUS_NOMEM, STATUS_NOMEM), - CONVERT(BT_STATUS_BUSY, STATUS_BUSY), - CONVERT(BT_STATUS_DONE, STATUS_DONE), - CONVERT(BT_STATUS_UNSUPPORTED, STATUS_UNSUPPORTED), - CONVERT(BT_STATUS_PARM_INVALID, STATUS_PARM_INVALID), - CONVERT(BT_STATUS_UNHANDLED, STATUS_UNHANDLED), - CONVERT(BT_STATUS_AUTH_FAILURE, STATUS_AUTH_FAILURE), - CONVERT(BT_STATUS_RMT_DEV_DOWN, STATUS_RMT_DEV_DOWN) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sStatus)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sStatus[aIn]; - return NS_OK; -} - -static nsresult -Convert(int aIn, BluetoothStatus& aOut) -{ - return Convert(static_cast(aIn), aOut); -} - -static nsresult -Convert(const nsAString& aIn, bt_property_type_t& aOut) -{ - if (aIn.EqualsLiteral("Name")) { - aOut = BT_PROPERTY_BDNAME; - } else if (aIn.EqualsLiteral("Discoverable")) { - aOut = BT_PROPERTY_ADAPTER_SCAN_MODE; - } else if (aIn.EqualsLiteral("DiscoverableTimeout")) { - aOut = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT; - } else { - BT_LOGR("Invalid property name: %s", NS_ConvertUTF16toUTF8(aIn).get()); - return NS_ERROR_ILLEGAL_VALUE; - } - return NS_OK; -} - -static nsresult -Convert(bool aIn, bt_scan_mode_t& aOut) -{ - static const bt_scan_mode_t sScanMode[] = { - CONVERT(false, BT_SCAN_MODE_CONNECTABLE), - CONVERT(true, BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sScanMode)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sScanMode[aIn]; - return NS_OK; -} - - -static nsresult -Convert(bt_scan_mode_t aIn, BluetoothScanMode& aOut) -{ - static const BluetoothScanMode sScanMode[] = { - CONVERT(BT_SCAN_MODE_NONE, SCAN_MODE_NONE), - CONVERT(BT_SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE), - CONVERT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE, - SCAN_MODE_CONNECTABLE_DISCOVERABLE) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sScanMode)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sScanMode[aIn]; - return NS_OK; -} - -struct ConvertNamedValue -{ - ConvertNamedValue(const BluetoothNamedValue& aNamedValue) - : mNamedValue(aNamedValue) - { } - - const BluetoothNamedValue& mNamedValue; - - // temporary fields - nsCString mStringValue; - bt_scan_mode_t mScanMode; -}; - -static nsresult -Convert(ConvertNamedValue& aIn, bt_property_t& aOut) -{ - nsresult rv = Convert(aIn.mNamedValue.name(), aOut.type); - if (NS_FAILED(rv)) { - return rv; - } - - if (aIn.mNamedValue.value().type() == BluetoothValue::Tuint32_t) { - // Set discoverable timeout - aOut.val = - reinterpret_cast(aIn.mNamedValue.value().get_uint32_t()); - } else if (aIn.mNamedValue.value().type() == BluetoothValue::TnsString) { - // Set name - aIn.mStringValue = - NS_ConvertUTF16toUTF8(aIn.mNamedValue.value().get_nsString()); - aOut.val = - const_cast(static_cast(aIn.mStringValue.get())); - aOut.len = strlen(static_cast(aOut.val)); - } else if (aIn.mNamedValue.value().type() == BluetoothValue::Tbool) { - // Set scan mode - rv = Convert(aIn.mNamedValue.value().get_bool(), aIn.mScanMode); - if (NS_FAILED(rv)) { - return rv; - } - aOut.val = &aIn.mScanMode; - aOut.len = sizeof(aIn.mScanMode); - } else { - BT_LOGR("Invalid property value type"); - return NS_ERROR_ILLEGAL_VALUE; - } - - return NS_OK; -} - -static nsresult -Convert(const nsAString& aIn, bt_bdaddr_t& aOut) -{ - NS_ConvertUTF16toUTF8 bdAddressUTF8(aIn); - const char* str = bdAddressUTF8.get(); - - for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aOut.address); ++i, ++str) { - aOut.address[i] = - static_cast(strtoul(str, const_cast(&str), 16)); - } - - return NS_OK; -} - -static nsresult -Convert(const nsAString& aIn, bt_ssp_variant_t& aOut) -{ - if (aIn.EqualsLiteral("PasskeyConfirmation")) { - aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION; - } else if (aIn.EqualsLiteral("PasskeyEntry")) { - aOut = BT_SSP_VARIANT_PASSKEY_ENTRY; - } else if (aIn.EqualsLiteral("Consent")) { - aOut = BT_SSP_VARIANT_CONSENT; - } else if (aIn.EqualsLiteral("PasskeyNotification")) { - aOut = BT_SSP_VARIANT_PASSKEY_NOTIFICATION; - } else { - BT_LOGR("Invalid SSP variant name: %s", NS_ConvertUTF16toUTF8(aIn).get()); - aOut = BT_SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning - return NS_ERROR_ILLEGAL_VALUE; - } - return NS_OK; -} - -static nsresult -Convert(const bt_ssp_variant_t& aIn, nsAString& aOut) -{ - static const char * const sSspVariant[] = { - CONVERT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION, "PasskeyConfirmation"), - CONVERT(BT_SSP_VARIANT_PASSKEY_ENTRY, "PasskeyEntry"), - CONVERT(BT_SSP_VARIANT_CONSENT, "Consent"), - CONVERT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION, "PasskeyNotification") - }; - if (aIn >= MOZ_ARRAY_LENGTH(sSspVariant)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = NS_ConvertUTF8toUTF16(sSspVariant[aIn]); - return NS_OK; -} - -static nsresult -Convert(const bool& aIn, uint8_t& aOut) -{ - // casting converts true/false to either 1 or 0 - aOut = static_cast(aIn); - return NS_OK; -} - -static nsresult -Convert(const uint8_t aIn[16], bt_uuid_t& aOut) -{ - if (sizeof(aOut.uu) != 16) { - return NS_ERROR_ILLEGAL_VALUE; - } - - memcpy(aOut.uu, aIn, sizeof(aOut.uu)); - - return NS_OK; -} - -static nsresult -Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut) -{ - if (sizeof(aIn.uu) != sizeof(aOut.mUuid)) { - return NS_ERROR_ILLEGAL_VALUE; - } - - memcpy(aOut.mUuid, aIn.uu, sizeof(aOut.mUuid)); - - return NS_OK; -} - -static nsresult -Convert(const nsAString& aIn, bt_pin_code_t& aOut) -{ - if (aIn.Length() > MOZ_ARRAY_LENGTH(aOut.pin)) { - return NS_ERROR_ILLEGAL_VALUE; - } - - NS_ConvertUTF16toUTF8 pinCodeUTF8(aIn); - const char* str = pinCodeUTF8.get(); - - nsAString::size_type i; - - // Fill pin into aOut - for (i = 0; i < aIn.Length(); ++i, ++str) { - aOut.pin[i] = static_cast(*str); - } - - // Clear remaining bytes in aOut - size_t ntrailing = - (MOZ_ARRAY_LENGTH(aOut.pin) - aIn.Length()) * sizeof(aOut.pin[0]); - memset(aOut.pin + aIn.Length(), 0, ntrailing); - - return NS_OK; -} - -static nsresult -Convert(const bt_bdaddr_t& aIn, nsAString& aOut) -{ - char str[BLUETOOTH_ADDRESS_LENGTH + 1]; - - int res = snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", - static_cast(aIn.address[0]), - static_cast(aIn.address[1]), - static_cast(aIn.address[2]), - static_cast(aIn.address[3]), - static_cast(aIn.address[4]), - static_cast(aIn.address[5])); - if (res < 0) { - return NS_ERROR_ILLEGAL_VALUE; - } else if ((size_t)res >= sizeof(str)) { - return NS_ERROR_OUT_OF_MEMORY; /* string buffer too small */ - } - - aOut = NS_ConvertUTF8toUTF16(str); - - return NS_OK; -} - -static nsresult -Convert(const bt_bdaddr_t* aIn, nsAString& aOut) -{ - if (!aIn) { - aOut.AssignLiteral(BLUETOOTH_ADDRESS_NONE); - return NS_OK; - } - return Convert(*aIn, aOut); -} - -static nsresult -Convert(bt_state_t aIn, bool& aOut) -{ - static const bool sState[] = { - CONVERT(BT_STATE_OFF, false), - CONVERT(BT_STATE_ON, true) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bt_property_type_t aIn, BluetoothPropertyType& aOut) -{ - static const BluetoothPropertyType sPropertyType[] = { - CONVERT(0, static_cast(0)), // invalid, required by gcc - CONVERT(BT_PROPERTY_BDNAME, PROPERTY_BDNAME), - CONVERT(BT_PROPERTY_BDADDR, PROPERTY_BDADDR), - CONVERT(BT_PROPERTY_UUIDS, PROPERTY_UUIDS), - CONVERT(BT_PROPERTY_CLASS_OF_DEVICE, PROPERTY_CLASS_OF_DEVICE), - CONVERT(BT_PROPERTY_TYPE_OF_DEVICE, PROPERTY_TYPE_OF_DEVICE), - CONVERT(BT_PROPERTY_SERVICE_RECORD, PROPERTY_SERVICE_RECORD), - CONVERT(BT_PROPERTY_ADAPTER_SCAN_MODE, PROPERTY_ADAPTER_SCAN_MODE), - CONVERT(BT_PROPERTY_ADAPTER_BONDED_DEVICES, - PROPERTY_ADAPTER_BONDED_DEVICES), - CONVERT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, - PROPERTY_ADAPTER_DISCOVERY_TIMEOUT), - CONVERT(BT_PROPERTY_REMOTE_FRIENDLY_NAME, PROPERTY_REMOTE_FRIENDLY_NAME), - CONVERT(BT_PROPERTY_REMOTE_RSSI, PROPERTY_REMOTE_RSSI), - CONVERT(BT_PROPERTY_REMOTE_VERSION_INFO,PROPERTY_REMOTE_VERSION_INFO) - }; - if (aIn == BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP) { - /* This case is handled separately to not populate - * |sPropertyType| with empty entries. */ - aOut = PROPERTY_REMOTE_DEVICE_TIMESTAMP; - return NS_OK; - } - if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPropertyType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sPropertyType[aIn]; - return NS_OK; -} - -static nsresult -Convert(bt_discovery_state_t aIn, bool& aOut) -{ - static const bool sDiscoveryState[] = { - CONVERT(BT_DISCOVERY_STOPPED, false), - CONVERT(BT_DISCOVERY_STARTED, true) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sDiscoveryState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sDiscoveryState[aIn]; - return NS_OK; -} - -static nsresult -Convert(const char* aIn, nsACString& aOut) -{ - aOut.Assign(aIn); - - return NS_OK; -} - -static nsresult -Convert(const char* aIn, nsAString& aOut) -{ - aOut = NS_ConvertUTF8toUTF16(aIn); - - return NS_OK; -} - -static nsresult -Convert(const bt_bdname_t& aIn, nsAString& aOut) -{ - return Convert(reinterpret_cast(aIn.name), aOut); -} - -static nsresult -Convert(const bt_bdname_t* aIn, nsAString& aOut) -{ - if (!aIn) { - aOut.Truncate(); - return NS_OK; - } - return Convert(*aIn, aOut); -} - -static nsresult -Convert(bt_bond_state_t aIn, BluetoothBondState& aOut) -{ - static const BluetoothBondState sBondState[] = { - CONVERT(BT_BOND_STATE_NONE, BOND_STATE_NONE), - CONVERT(BT_BOND_STATE_BONDING, BOND_STATE_BONDING), - CONVERT(BT_BOND_STATE_BONDED, BOND_STATE_BONDED) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sBondState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sBondState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bt_acl_state_t aIn, bool& aOut) -{ - static const bool sAclState[] = { - CONVERT(BT_ACL_STATE_CONNECTED, true), - CONVERT(BT_ACL_STATE_DISCONNECTED, false) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sAclState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sAclState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bt_device_type_t aIn, BluetoothDeviceType& aOut) -{ - static const BluetoothDeviceType sDeviceType[] = { - CONVERT(0, static_cast(0)), // invalid, required by gcc - CONVERT(BT_DEVICE_DEVTYPE_BREDR, DEVICE_TYPE_BREDR), - CONVERT(BT_DEVICE_DEVTYPE_BLE, DEVICE_TYPE_BLE), - CONVERT(BT_DEVICE_DEVTYPE_DUAL, DEVICE_TYPE_DUAL) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sDeviceType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sDeviceType[aIn]; - return NS_OK; -} - -static nsresult -Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut) -{ - nsresult rv = Convert(aIn.uuid, aOut.mUuid); - if (NS_FAILED(rv)) { - return rv; - } - - aOut.mChannel = aIn.channel; - - MOZ_ASSERT(sizeof(aIn.name) == sizeof(aOut.mName)); - memcpy(aOut.mName, aIn.name, sizeof(aOut.mName)); - - return NS_OK; -} - -static nsresult -Convert(BluetoothSocketType aIn, btsock_type_t& aOut) -{ - // FIXME: Array member [0] is currently invalid, but required - // by gcc. Start values in |BluetoothSocketType| at index - // 0 to fix this problem. - static const btsock_type_t sSocketType[] = { - CONVERT(0, static_cast(0)), // invalid, [0] required by gcc - CONVERT(BluetoothSocketType::RFCOMM, BTSOCK_RFCOMM), - CONVERT(BluetoothSocketType::SCO, BTSOCK_SCO), - CONVERT(BluetoothSocketType::L2CAP, BTSOCK_L2CAP), - // EL2CAP is not supported by Bluedroid - }; - if (aIn == BluetoothSocketType::EL2CAP || - aIn >= MOZ_ARRAY_LENGTH(sSocketType) || !sSocketType[aIn]) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sSocketType[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeAtResponse aIn, bthf_at_response_t& aOut) -{ - static const bthf_at_response_t sAtResponse[] = { - CONVERT(HFP_AT_RESPONSE_ERROR, BTHF_AT_RESPONSE_ERROR), - CONVERT(HFP_AT_RESPONSE_OK, BTHF_AT_RESPONSE_OK) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sAtResponse)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sAtResponse[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeCallAddressType aIn, bthf_call_addrtype_t& aOut) -{ - static const bthf_call_addrtype_t sCallAddressType[] = { - CONVERT(HFP_CALL_ADDRESS_TYPE_UNKNOWN, BTHF_CALL_ADDRTYPE_UNKNOWN), - CONVERT(HFP_CALL_ADDRESS_TYPE_INTERNATIONAL, - BTHF_CALL_ADDRTYPE_INTERNATIONAL) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallAddressType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallAddressType[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeCallDirection aIn, bthf_call_direction_t& aOut) -{ - static const bthf_call_direction_t sCallDirection[] = { - CONVERT(HFP_CALL_DIRECTION_OUTGOING, BTHF_CALL_DIRECTION_OUTGOING), - CONVERT(HFP_CALL_DIRECTION_INCOMING, BTHF_CALL_DIRECTION_INCOMING) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallDirection)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallDirection[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeCallMode aIn, bthf_call_mode_t& aOut) -{ - static const bthf_call_mode_t sCallMode[] = { - CONVERT(HFP_CALL_MODE_VOICE, BTHF_CALL_TYPE_VOICE), - CONVERT(HFP_CALL_MODE_DATA, BTHF_CALL_TYPE_DATA), - CONVERT(HFP_CALL_MODE_FAX, BTHF_CALL_TYPE_FAX) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallMode)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallMode[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeCallMptyType aIn, bthf_call_mpty_type_t& aOut) -{ - static const bthf_call_mpty_type_t sCallMptyType[] = { - CONVERT(HFP_CALL_MPTY_TYPE_SINGLE, BTHF_CALL_MPTY_TYPE_SINGLE), - CONVERT(HFP_CALL_MPTY_TYPE_MULTI, BTHF_CALL_MPTY_TYPE_MULTI) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallMptyType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallMptyType[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeCallState aIn, bthf_call_state_t& aOut) -{ - static const bthf_call_state_t sCallState[] = { - CONVERT(HFP_CALL_STATE_ACTIVE, BTHF_CALL_STATE_ACTIVE), - CONVERT(HFP_CALL_STATE_HELD, BTHF_CALL_STATE_HELD), - CONVERT(HFP_CALL_STATE_DIALING, BTHF_CALL_STATE_DIALING), - CONVERT(HFP_CALL_STATE_ALERTING, BTHF_CALL_STATE_ALERTING), - CONVERT(HFP_CALL_STATE_INCOMING, BTHF_CALL_STATE_INCOMING), - CONVERT(HFP_CALL_STATE_WAITING, BTHF_CALL_STATE_WAITING), - CONVERT(HFP_CALL_STATE_IDLE, BTHF_CALL_STATE_IDLE) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallState[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeNetworkState aIn, bthf_network_state_t& aOut) -{ - static const bthf_network_state_t sNetworkState[] = { - CONVERT(HFP_NETWORK_STATE_NOT_AVAILABLE, BTHF_NETWORK_STATE_NOT_AVAILABLE), - CONVERT(HFP_NETWORK_STATE_AVAILABLE, BTHF_NETWORK_STATE_AVAILABLE) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sNetworkState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sNetworkState[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeServiceType aIn, bthf_service_type_t& aOut) -{ - static const bthf_service_type_t sServiceType[] = { - CONVERT(HFP_SERVICE_TYPE_HOME, BTHF_SERVICE_TYPE_HOME), - CONVERT(HFP_SERVICE_TYPE_ROAMING, BTHF_SERVICE_TYPE_ROAMING) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sServiceType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sServiceType[aIn]; - return NS_OK; -} - -static nsresult -Convert(BluetoothHandsfreeVolumeType aIn, bthf_volume_type_t& aOut) -{ - static const bthf_volume_type_t sVolumeType[] = { - CONVERT(HFP_VOLUME_TYPE_SPEAKER, BTHF_VOLUME_TYPE_SPK), - CONVERT(HFP_VOLUME_TYPE_MICROPHONE, BTHF_VOLUME_TYPE_MIC) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sVolumeType[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_audio_state_t aIn, BluetoothHandsfreeAudioState& aOut) -{ - static const BluetoothHandsfreeAudioState sAudioState[] = { - CONVERT(BTHF_AUDIO_STATE_DISCONNECTED, HFP_AUDIO_STATE_DISCONNECTED), - CONVERT(BTHF_AUDIO_STATE_CONNECTING, HFP_AUDIO_STATE_CONNECTING), - CONVERT(BTHF_AUDIO_STATE_CONNECTED, HFP_AUDIO_STATE_CONNECTED), - CONVERT(BTHF_AUDIO_STATE_DISCONNECTING, HFP_AUDIO_STATE_DISCONNECTING) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sAudioState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_chld_type_t aIn, BluetoothHandsfreeCallHoldType& aOut) -{ - static const BluetoothHandsfreeCallHoldType sCallHoldType[] = { - CONVERT(BTHF_CHLD_TYPE_RELEASEHELD, HFP_CALL_HOLD_RELEASEHELD), - CONVERT(BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD, - HFP_CALL_HOLD_RELEASEACTIVE_ACCEPTHELD), - CONVERT(BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD, - HFP_CALL_HOLD_HOLDACTIVE_ACCEPTHELD), - CONVERT(BTHF_CHLD_TYPE_ADDHELDTOCONF, HFP_CALL_HOLD_ADDHELDTOCONF) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sCallHoldType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sCallHoldType[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_connection_state_t aIn, BluetoothHandsfreeConnectionState& aOut) -{ - static const BluetoothHandsfreeConnectionState sConnectionState[] = { - CONVERT(BTHF_CONNECTION_STATE_DISCONNECTED, - HFP_CONNECTION_STATE_DISCONNECTED), - CONVERT(BTHF_CONNECTION_STATE_CONNECTING, HFP_CONNECTION_STATE_CONNECTING), - CONVERT(BTHF_CONNECTION_STATE_CONNECTED, HFP_CONNECTION_STATE_CONNECTED), - CONVERT(BTHF_CONNECTION_STATE_SLC_CONNECTED, - HFP_CONNECTION_STATE_SLC_CONNECTED), - CONVERT(BTHF_CONNECTION_STATE_DISCONNECTING, - HFP_CONNECTION_STATE_DISCONNECTING) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sConnectionState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_nrec_t aIn, BluetoothHandsfreeNRECState& aOut) -{ - static const BluetoothHandsfreeNRECState sNRECState[] = { - CONVERT(BTHF_NREC_STOP, HFP_NREC_STOPPED), - CONVERT(BTHF_NREC_START, HFP_NREC_STARTED) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sNRECState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sNRECState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_vr_state_t aIn, BluetoothHandsfreeVoiceRecognitionState& aOut) -{ - static const BluetoothHandsfreeVoiceRecognitionState - sVoiceRecognitionState[] = { - CONVERT(BTHF_VR_STATE_STOPPED, HFP_VOICE_RECOGNITION_STOPPED), - CONVERT(BTHF_VR_STATE_STARTED, HFP_VOICE_RECOGNITION_STARTED) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sVoiceRecognitionState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sVoiceRecognitionState[aIn]; - return NS_OK; -} - -static nsresult -Convert(bthf_volume_type_t aIn, BluetoothHandsfreeVolumeType& aOut) -{ - static const BluetoothHandsfreeVolumeType sVolumeType[] = { - CONVERT(BTHF_VOLUME_TYPE_SPK, HFP_VOLUME_TYPE_SPEAKER), - CONVERT(BTHF_VOLUME_TYPE_MIC, HFP_VOLUME_TYPE_MICROPHONE) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sVolumeType[aIn]; - return NS_OK; -} - -static nsresult -Convert(btav_connection_state_t aIn, BluetoothA2dpConnectionState& aOut) -{ - static const BluetoothA2dpConnectionState sConnectionState[] = { - CONVERT(BTAV_CONNECTION_STATE_DISCONNECTED, - A2DP_CONNECTION_STATE_DISCONNECTED), - CONVERT(BTAV_CONNECTION_STATE_CONNECTING, - A2DP_CONNECTION_STATE_CONNECTING), - CONVERT(BTAV_CONNECTION_STATE_CONNECTED, - A2DP_CONNECTION_STATE_CONNECTED), - CONVERT(BTAV_CONNECTION_STATE_DISCONNECTING, - A2DP_CONNECTION_STATE_DISCONNECTING), - }; - if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sConnectionState[aIn]; - return NS_OK; -} - -static nsresult -Convert(btav_audio_state_t aIn, BluetoothA2dpAudioState& aOut) -{ - static const BluetoothA2dpAudioState sAudioState[] = { - CONVERT(BTAV_AUDIO_STATE_REMOTE_SUSPEND, A2DP_AUDIO_STATE_REMOTE_SUSPEND), - CONVERT(BTAV_AUDIO_STATE_STOPPED, A2DP_AUDIO_STATE_STOPPED), - CONVERT(BTAV_AUDIO_STATE_STARTED, A2DP_AUDIO_STATE_STARTED), - }; - if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sAudioState[aIn]; - return NS_OK; -} - -#if ANDROID_VERSION >= 18 -static nsresult -Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut) -{ - aOut.mVerMajor = aIn.version; - aOut.mVerMinor = aIn.sub_ver; - aOut.mManufacturer = aIn.manufacturer; - - return NS_OK; -} - -static nsresult -Convert(ControlPlayStatus aIn, btrc_play_status_t& aOut) -{ - static const btrc_play_status_t sPlayStatus[] = { - CONVERT(PLAYSTATUS_STOPPED, BTRC_PLAYSTATE_STOPPED), - CONVERT(PLAYSTATUS_PLAYING, BTRC_PLAYSTATE_PLAYING), - CONVERT(PLAYSTATUS_PAUSED, BTRC_PLAYSTATE_PAUSED), - CONVERT(PLAYSTATUS_FWD_SEEK, BTRC_PLAYSTATE_FWD_SEEK), - CONVERT(PLAYSTATUS_REV_SEEK, BTRC_PLAYSTATE_REV_SEEK) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sPlayStatus)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sPlayStatus[aIn]; - return NS_OK; -} - -static nsresult -Convert(enum BluetoothAvrcpPlayerAttribute aIn, btrc_player_attr_t& aOut) -{ - static const btrc_player_attr_t sPlayerAttr[] = { - CONVERT(AVRCP_PLAYER_ATTRIBUTE_EQUALIZER, BTRC_PLAYER_ATTR_EQUALIZER), - CONVERT(AVRCP_PLAYER_ATTRIBUTE_REPEAT, BTRC_PLAYER_ATTR_REPEAT), - CONVERT(AVRCP_PLAYER_ATTRIBUTE_SHUFFLE, BTRC_PLAYER_ATTR_SHUFFLE), - CONVERT(AVRCP_PLAYER_ATTRIBUTE_SCAN, BTRC_PLAYER_ATTR_SCAN) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sPlayerAttr[aIn]; - return NS_OK; -} - -static nsresult -Convert(btrc_player_attr_t aIn, enum BluetoothAvrcpPlayerAttribute& aOut) -{ - static const BluetoothAvrcpPlayerAttribute sPlayerAttr[] = { - CONVERT(0, static_cast(0)), // invalid, [0] required by gcc - CONVERT(BTRC_PLAYER_ATTR_EQUALIZER, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER), - CONVERT(BTRC_PLAYER_ATTR_REPEAT, AVRCP_PLAYER_ATTRIBUTE_REPEAT), - CONVERT(BTRC_PLAYER_ATTR_SHUFFLE, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE), - CONVERT(BTRC_PLAYER_ATTR_SCAN, AVRCP_PLAYER_ATTRIBUTE_SCAN) - }; - if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sPlayerAttr[aIn]; - return NS_OK; -} - -static nsresult -Convert(enum BluetoothAvrcpStatus aIn, btrc_status_t& aOut) -{ - static const btrc_status_t sStatus[] = { - CONVERT(AVRCP_STATUS_BAD_COMMAND, BTRC_STS_BAD_CMD), - CONVERT(AVRCP_STATUS_BAD_PARAMETER, BTRC_STS_BAD_PARAM), - CONVERT(AVRCP_STATUS_NOT_FOUND, BTRC_STS_NOT_FOUND), - CONVERT(AVRCP_STATUS_INTERNAL_ERROR, BTRC_STS_INTERNAL_ERR), - CONVERT(AVRCP_STATUS_SUCCESS, BTRC_STS_NO_ERROR) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sStatus)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sStatus[aIn]; - return NS_OK; -} - -static nsresult -Convert(enum BluetoothAvrcpEvent aIn, btrc_event_id_t& aOut) -{ - static const btrc_event_id_t sEventId[] = { - CONVERT(AVRCP_EVENT_PLAY_STATUS_CHANGED, BTRC_EVT_PLAY_STATUS_CHANGED), - CONVERT(AVRCP_EVENT_TRACK_CHANGE, BTRC_EVT_TRACK_CHANGE), - CONVERT(AVRCP_EVENT_TRACK_REACHED_END, BTRC_EVT_TRACK_REACHED_END), - CONVERT(AVRCP_EVENT_TRACK_REACHED_START, BTRC_EVT_TRACK_REACHED_START), - CONVERT(AVRCP_EVENT_PLAY_POS_CHANGED, BTRC_EVT_PLAY_POS_CHANGED), - CONVERT(AVRCP_EVENT_APP_SETTINGS_CHANGED, BTRC_EVT_APP_SETTINGS_CHANGED) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sEventId)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sEventId[aIn]; - return NS_OK; -} - -static nsresult -Convert(btrc_event_id_t aIn, enum BluetoothAvrcpEvent& aOut) -{ - static const BluetoothAvrcpEvent sEventId[] = { - CONVERT(0, static_cast(0)), // invalid, [0] required by gcc - CONVERT(BTRC_EVT_PLAY_STATUS_CHANGED, AVRCP_EVENT_PLAY_STATUS_CHANGED), - CONVERT(BTRC_EVT_TRACK_CHANGE, AVRCP_EVENT_TRACK_CHANGE), - CONVERT(BTRC_EVT_TRACK_REACHED_END, AVRCP_EVENT_TRACK_REACHED_END), - CONVERT(BTRC_EVT_TRACK_REACHED_START, AVRCP_EVENT_TRACK_REACHED_START), - CONVERT(BTRC_EVT_PLAY_POS_CHANGED, AVRCP_EVENT_PLAY_POS_CHANGED), - CONVERT(6, static_cast(0)), // invalid, [6] required by gcc - CONVERT(7, static_cast(0)), // invalid, [7] required by gcc - CONVERT(BTRC_EVT_APP_SETTINGS_CHANGED, AVRCP_EVENT_APP_SETTINGS_CHANGED) - }; - if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sEventId[aIn]; - return NS_OK; -} - -static nsresult -Convert(btrc_media_attr_t aIn, enum BluetoothAvrcpMediaAttribute& aOut) -{ - static const BluetoothAvrcpMediaAttribute sEventId[] = { - CONVERT(0, static_cast(0)), // invalid, [0] required by gcc - CONVERT(BTRC_MEDIA_ATTR_TITLE, AVRCP_MEDIA_ATTRIBUTE_TITLE), - CONVERT(BTRC_MEDIA_ATTR_ARTIST, AVRCP_MEDIA_ATTRIBUTE_ARTIST), - CONVERT(BTRC_MEDIA_ATTR_ALBUM, AVRCP_MEDIA_ATTRIBUTE_ALBUM), - CONVERT(BTRC_MEDIA_ATTR_TRACK_NUM, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM), - CONVERT(BTRC_MEDIA_ATTR_NUM_TRACKS, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS), - CONVERT(BTRC_MEDIA_ATTR_GENRE, AVRCP_MEDIA_ATTRIBUTE_GENRE), - CONVERT(BTRC_MEDIA_ATTR_PLAYING_TIME, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME) - }; - if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sEventId[aIn]; - return NS_OK; -} - -static nsresult -Convert(enum BluetoothAvrcpNotification aIn, btrc_notification_type_t& aOut) -{ - static const btrc_notification_type_t sNotificationType[] = { - CONVERT(AVRCP_NTF_INTERIM, BTRC_NOTIFICATION_TYPE_INTERIM), - CONVERT(AVRCP_NTF_CHANGED, BTRC_NOTIFICATION_TYPE_CHANGED) - }; - if (aIn >= MOZ_ARRAY_LENGTH(sNotificationType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = sNotificationType[aIn]; - return NS_OK; -} - -static nsresult -Convert(const BluetoothAvrcpElementAttribute& aIn, btrc_element_attr_val_t& aOut) -{ - const NS_ConvertUTF16toUTF8 value(aIn.mValue); - size_t len = std::min(strlen(value.get()), sizeof(aOut.text) - 1); - - memcpy(aOut.text, value.get(), len); - aOut.text[len] = '\0'; - aOut.attr_id = aIn.mId; - - return NS_OK; -} - -static nsresult -Convert(const btrc_player_settings_t& aIn, BluetoothAvrcpPlayerSettings& aOut) -{ - aOut.mNumAttr = aIn.num_attr; - memcpy(aOut.mIds, aIn.attr_ids, aIn.num_attr); - memcpy(aOut.mValues, aIn.attr_values, aIn.num_attr); - - return NS_OK; -} -#endif // ANDROID_VERSION >= 18 - -#if ANDROID_VERSION >= 19 -static nsresult -Convert(btrc_remote_features_t aIn, unsigned long& aOut) -{ - /* The input type's name is misleading. The converted value is - * actually a bitmask. - */ - aOut = static_cast(aIn); - return NS_OK; -} -#endif // ANDROID_VERSION >= 19 - -/* |ConvertArray| is a helper for converting arrays. Pass an - * instance of this structure as the first argument to |Convert| - * to convert an array. The output type has to support the array - * subscript operator. - */ -template -struct ConvertArray -{ - ConvertArray(const T* aData, unsigned long aLength) - : mData(aData) - , mLength(aLength) - { } - - const T* mData; - unsigned long mLength; -}; - -/* This implementation of |Convert| converts the elements of an - * array one-by-one. The result data structures must have enough - * memory allocated. - */ -template -static nsresult -Convert(const ConvertArray& aIn, Tout& aOut) -{ - for (unsigned long i = 0; i < aIn.mLength; ++i) { - nsresult rv = Convert(aIn.mData[i], aOut[i]); - if (NS_FAILED(rv)) { - return rv; - } - } - return NS_OK; -} - -/* This implementation of |Convert| is a helper that automatically - * allocates enough memory to hold the conversion results. The - * actual conversion is performed by the array-conversion helper - * above. - */ -template -static nsresult -Convert(const ConvertArray& aIn, nsAutoArrayPtr& aOut) -{ - aOut = new Tout[aIn.mLength]; - Tout* out = aOut.get(); - - return Convert(aIn, out); -} - -/* |ConvertDefault| is a helper function to return the result of a - * conversion or a default value if the conversion fails. - */ -template -static Tout -ConvertDefault(const Tin& aIn, const Tout& aDefault) -{ - Tout out = aDefault; // assignment silences compiler warning - if (NS_FAILED(Convert(aIn, out))) { - return aDefault; - } - return out; -} - -/* This implementation of |Convert| is a helper for copying the - * input value into the output value. It handles all cases that - * need no conversion. - */ -template -static nsresult -Convert(const T& aIn, T& aOut) -{ - aOut = aIn; - - return NS_OK; -} - -static nsresult -Convert(const bt_property_t& aIn, BluetoothProperty& aOut) -{ - /* type conversion */ - - nsresult rv = Convert(aIn.type, aOut.mType); - if (NS_FAILED(rv)) { - return rv; - } - - /* value conversion */ - - switch (aOut.mType) { - case PROPERTY_BDNAME: - /* fall through */ - case PROPERTY_REMOTE_FRIENDLY_NAME: - { - // We construct an nsCString here because bdname - // returned from Bluedroid is not 0-terminated. - aOut.mString = NS_ConvertUTF8toUTF16( - nsCString(static_cast(aIn.val), aIn.len)); - } - break; - case PROPERTY_BDADDR: - rv = Convert(*static_cast(aIn.val), aOut.mString); - break; - case PROPERTY_UUIDS: - { - size_t numUuids = aIn.len / MAX_UUID_SIZE; - ConvertArray array( - static_cast(aIn.val), numUuids); - aOut.mUuidArray.SetLength(numUuids); - rv = Convert(array, aOut.mUuidArray); - } - break; - case PROPERTY_CLASS_OF_DEVICE: - /* fall through */ - case PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: - aOut.mUint32 = *static_cast(aIn.val); - break; - case PROPERTY_TYPE_OF_DEVICE: - rv = Convert(*static_cast(aIn.val), - aOut.mDeviceType); - break; - case PROPERTY_SERVICE_RECORD: - rv = Convert(*static_cast(aIn.val), - aOut.mServiceRecord); - break; - case PROPERTY_ADAPTER_SCAN_MODE: - rv = Convert(*static_cast(aIn.val), - aOut.mScanMode); - break; - case PROPERTY_ADAPTER_BONDED_DEVICES: - { - size_t numAddresses = aIn.len / BLUETOOTH_ADDRESS_BYTES; - ConvertArray array( - static_cast(aIn.val), numAddresses); - aOut.mStringArray.SetLength(numAddresses); - rv = Convert(array, aOut.mStringArray); - } - break; - case PROPERTY_REMOTE_RSSI: - aOut.mInt32 = *static_cast(aIn.val); - break; -#if ANDROID_VERSION >= 18 - case PROPERTY_REMOTE_VERSION_INFO: - rv = Convert(*static_cast(aIn.val), - aOut.mRemoteInfo); - break; -#endif - case PROPERTY_REMOTE_DEVICE_TIMESTAMP: - /* nothing to do */ - break; - default: - /* mismatch with type conversion */ - NS_NOTREACHED("Unhandled property type"); - break; - } - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; -} - -// -// Result handling -// - -template -class BluetoothInterfaceRunnable0 : public nsRunnable -{ -public: - BluetoothInterfaceRunnable0(Obj* aObj, Res (Obj::*aMethod)()) - : mObj(aObj) - , mMethod(aMethod) - { - MOZ_ASSERT(mObj); - MOZ_ASSERT(mMethod); - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - ((*mObj).*mMethod)(); - return NS_OK; - } - -private: - nsRefPtr mObj; - void (Obj::*mMethod)(); -}; - -template -class BluetoothInterfaceRunnable1 : public nsRunnable -{ -public: - BluetoothInterfaceRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1), - const Arg1& aArg1) - : mObj(aObj) - , mMethod(aMethod) - , mArg1(aArg1) - { - MOZ_ASSERT(mObj); - MOZ_ASSERT(mMethod); - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - ((*mObj).*mMethod)(mArg1); - return NS_OK; - } - -private: - nsRefPtr mObj; - Res (Obj::*mMethod)(Arg1); - Tin1 mArg1; -}; - -template -class BluetoothInterfaceRunnable3 : public nsRunnable -{ -public: - BluetoothInterfaceRunnable3(Obj* aObj, - Res (Obj::*aMethod)(Arg1, Arg2, Arg3), - const Arg1& aArg1, const Arg2& aArg2, - const Arg3& aArg3) - : mObj(aObj) - , mMethod(aMethod) - , mArg1(aArg1) - , mArg2(aArg2) - , mArg3(aArg3) - { - MOZ_ASSERT(mObj); - MOZ_ASSERT(mMethod); - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - ((*mObj).*mMethod)(mArg1, mArg2, mArg3); - return NS_OK; - } - -private: - nsRefPtr mObj; - Res (Obj::*mMethod)(Arg1, Arg2, Arg3); - Tin1 mArg1; - Tin2 mArg2; - Tin3 mArg3; -}; - -// -// Notification handling -// - -template -class BluetoothNotificationRunnable0 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable0 SelfType; - - static already_AddRefed Create(Res (ObjectType::*aMethod)()) - { - nsRefPtr runnable(new SelfType(aMethod)); - - return runnable.forget(); - } - - static void - Dispatch(Res (ObjectType::*aMethod)()) - { - nsRefPtr runnable = Create(aMethod); - - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable0::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable0(Res (ObjectType::*aMethod)()) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - Res (ObjectType::*mMethod)(); -}; - -template -class BluetoothNotificationRunnable1 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable1 SelfType; - - template - static already_AddRefed Create( - Res (ObjectType::*aMethod)(Arg1), const T1& aIn1) - { - nsRefPtr runnable(new SelfType(aMethod)); - - if (NS_FAILED(runnable->ConvertAndSet(aIn1))) { - return nullptr; - } - return runnable.forget(); - } - - template - static void - Dispatch(Res (ObjectType::*aMethod)(Arg1), const T1& aIn1) - { - nsRefPtr runnable = Create(aMethod, aIn1); - - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable1::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(mArg1); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable1(Res (ObjectType::*aMethod)(Arg1)) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - template - nsresult - ConvertAndSet(const T1& aIn1) - { - nsresult rv = Convert(aIn1, mArg1); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; - } - - Res (ObjectType::*mMethod)(Arg1); - Tin1 mArg1; -}; - -template -class BluetoothNotificationRunnable2 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable2 SelfType; - - template - static already_AddRefed Create( - Res (ObjectType::*aMethod)(Arg1, Arg2), const T1& aIn1, const T2& aIn2) - { - nsRefPtr runnable(new SelfType(aMethod)); - - if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2))) { - return nullptr; - } - return runnable.forget(); - } - - template - static void - Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), - const T1& aIn1, const T2& aIn2) - { - nsRefPtr runnable = Create(aMethod, aIn1, aIn2); - - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable2::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(mArg1, mArg2); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable2(Res (ObjectType::*aMethod)(Arg1, Arg2)) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - template - nsresult - ConvertAndSet(const T1& aIn1, const T2& aIn2) - { - nsresult rv = Convert(aIn1, mArg1); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn2, mArg2); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; - } - - Res (ObjectType::*mMethod)(Arg1, Arg2); - Tin1 mArg1; - Tin2 mArg2; -}; - -template -class BluetoothNotificationRunnable3 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable3 SelfType; - - template - static already_AddRefed Create( - Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), - const T1& aIn1, const T2& aIn2, const T3& aIn3) - { - nsRefPtr runnable(new SelfType(aMethod)); - - if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3))) { - return nullptr; - } - return runnable.forget(); - } - - template - static void - Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), - const T1& aIn1, const T2& aIn2, const T3& aIn3) - { - nsRefPtr runnable = Create(aMethod, aIn1, aIn2, aIn3); - - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable3::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(mArg1, mArg2, mArg3); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable3(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3)) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - template - nsresult - ConvertAndSet(const T1& aIn1, const T2& aIn2, const T3& aIn3) - { - nsresult rv = Convert(aIn1, mArg1); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn2, mArg2); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn3, mArg3); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; - } - - Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3); - Tin1 mArg1; - Tin2 mArg2; - Tin3 mArg3; -}; - -template -class BluetoothNotificationRunnable4 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable4 SelfType; - - template - static already_AddRefed Create( - Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), - const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4) - { - nsRefPtr runnable(new SelfType(aMethod)); - - if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3, aIn4))) { - return nullptr; - } - return runnable.forget(); - } - - template - static void - Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), - const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4) - { - nsRefPtr runnable = Create(aMethod, aIn1, aIn2, aIn3, aIn4); - - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable4::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable4( - Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4)) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - template - nsresult - ConvertAndSet(const T1& aIn1, const T2& aIn2, - const T3& aIn3, const T4& aIn4) - { - nsresult rv = Convert(aIn1, mArg1); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn2, mArg2); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn3, mArg3); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn4, mArg4); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; - } - - Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4); - Tin1 mArg1; - Tin2 mArg2; - Tin3 mArg3; - Tin4 mArg4; -}; - -template -class BluetoothNotificationRunnable5 : public nsRunnable -{ -public: - typedef typename ObjectWrapper::ObjectType ObjectType; - typedef BluetoothNotificationRunnable5 SelfType; - - template - static already_AddRefed Create( - Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), - const T1& aIn1, const T2& aIn2, const T3& aIn3, - const T4& aIn4, const T5& aIn5) - { - nsRefPtr runnable(new SelfType(aMethod)); - - if (NS_FAILED(runnable->ConvertAndSet(aIn1, aIn2, aIn3, aIn4, aIn5))) { - return nullptr; - } - return runnable.forget(); - } - - template - static void - Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), - const T1& aIn1, const T2& aIn2, const T3& aIn3, - const T4& aIn4, const T5& aIn5) - { - nsRefPtr runnable = Create(aMethod, - aIn1, aIn2, aIn3, aIn4, aIn5); - if (!runnable) { - BT_WARNING("BluetoothNotificationRunnable5::Create failed"); - return; - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - } - - NS_METHOD - Run() MOZ_OVERRIDE - { - MOZ_ASSERT(NS_IsMainThread()); - - ObjectType* obj = ObjectWrapper::GetInstance(); - - if (!obj) { - BT_WARNING("Notification handler not initialized"); - } else { - ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4, mArg5); - } - return NS_OK; - } - -private: - BluetoothNotificationRunnable5(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, - Arg4, Arg5)) - : mMethod(aMethod) - { - MOZ_ASSERT(mMethod); - } - - template - nsresult - ConvertAndSet(const T1& aIn1, const T2& aIn2, const T3& aIn3, - const T4& aIn4, const T5& aIn5) - { - nsresult rv = Convert(aIn1, mArg1); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn2, mArg2); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn3, mArg3); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn4, mArg4); - if (NS_FAILED(rv)) { - return rv; - } - rv = Convert(aIn5, mArg5); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; - } - - Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5); - Tin1 mArg1; - Tin2 mArg2; - Tin3 mArg3; - Tin4 mArg4; - Tin5 mArg5; -}; - -// -// Socket Interface -// - -template<> -struct interface_traits -{ - typedef const btsock_interface_t const_interface_type; - - static const char* profile_id() - { - return BT_PROFILE_SOCKETS_ID; - } -}; - -typedef - BluetoothInterfaceRunnable1 - BluetoothSocketIntResultRunnable; - -typedef - BluetoothInterfaceRunnable3 - BluetoothSocketIntStringIntResultRunnable; - -typedef - BluetoothInterfaceRunnable1 - BluetoothSocketErrorRunnable; - -static nsresult -DispatchBluetoothSocketResult(BluetoothSocketResultHandler* aRes, - void (BluetoothSocketResultHandler::*aMethod)(int), - int aArg, BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothSocketIntResultRunnable(aRes, aMethod, aArg); - } else { - runnable = new BluetoothSocketErrorRunnable(aRes, - &BluetoothSocketResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -static nsresult -DispatchBluetoothSocketResult( - BluetoothSocketResultHandler* aRes, - void (BluetoothSocketResultHandler::*aMethod)(int, const nsAString&, int), - int aArg1, const nsAString& aArg2, int aArg3, BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothSocketIntStringIntResultRunnable(aRes, aMethod, - aArg1, aArg2, - aArg3); - } else { - runnable = new BluetoothSocketErrorRunnable(aRes, - &BluetoothSocketResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -void -BluetoothSocketInterface::Listen(BluetoothSocketType aType, - const nsAString& aServiceName, - const uint8_t aServiceUuid[16], - int aChannel, bool aEncrypt, bool aAuth, - BluetoothSocketResultHandler* aRes) -{ - int fd; - bt_status_t status; - btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning - - if (NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->listen(type, - NS_ConvertUTF16toUTF8(aServiceName).get(), - aServiceUuid, aChannel, &fd, - (BTSOCK_FLAG_ENCRYPT * aEncrypt) | - (BTSOCK_FLAG_AUTH * aAuth)); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothSocketResult(aRes, &BluetoothSocketResultHandler::Listen, - fd, ConvertDefault(status, STATUS_FAIL)); - } -} - -#define CMSGHDR_CONTAINS_FD(_cmsghdr) \ - ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \ - ((_cmsghdr)->cmsg_type == SCM_RIGHTS) ) - -/* |SocketMessageWatcher| receives Bluedroid's socket setup - * messages on the I/O thread. You need to inherit from this - * class to make use of it. - * - * Bluedroid sends two socket info messages (20 bytes) at - * the beginning of a connection to both peers. - * - * - 1st message: [channel:4] - * - 2nd message: [size:2][bd address:6][channel:4][connection status:4] - * - * On the server side, the second message will contain a - * socket file descriptor for the connection. The client - * uses the original file descriptor. - */ -class SocketMessageWatcher : public MessageLoopForIO::Watcher -{ -public: - static const unsigned char MSG1_SIZE = 4; - static const unsigned char MSG2_SIZE = 16; - - static const unsigned char OFF_CHANNEL1 = 0; - static const unsigned char OFF_SIZE = 4; - static const unsigned char OFF_BDADDRESS = 6; - static const unsigned char OFF_CHANNEL2 = 12; - static const unsigned char OFF_STATUS = 16; - - SocketMessageWatcher(int aFd) - : mFd(aFd) - , mClientFd(-1) - , mLen(0) - { } - - virtual ~SocketMessageWatcher() - { } - - virtual void Proceed(BluetoothStatus aStatus) = 0; - - void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE - { - BluetoothStatus status; - - switch (mLen) { - case 0: - status = RecvMsg1(); - break; - case MSG1_SIZE: - status = RecvMsg2(); - break; - default: - /* message-size error */ - status = STATUS_FAIL; - break; - } - - if (IsComplete() || status != STATUS_SUCCESS) { - mWatcher.StopWatchingFileDescriptor(); - Proceed(status); - } - } - - void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE - { } - - void Watch() - { - MessageLoopForIO::current()->WatchFileDescriptor( - mFd, - true, - MessageLoopForIO::WATCH_READ, - &mWatcher, - this); - } - - bool IsComplete() const - { - return mLen == (MSG1_SIZE + MSG2_SIZE); - } - - int GetFd() const - { - return mFd; - } - - int32_t GetChannel1() const - { - return ReadInt32(OFF_CHANNEL1); - } - - int32_t GetSize() const - { - return ReadInt16(OFF_SIZE); - } - - nsString GetBdAddress() const - { - nsString bdAddress; - ReadBdAddress(OFF_BDADDRESS, bdAddress); - return bdAddress; - } - - int32_t GetChannel2() const - { - return ReadInt32(OFF_CHANNEL2); - } - - int32_t GetConnectionStatus() const - { - return ReadInt32(OFF_STATUS); - } - - int GetClientFd() const - { - return mClientFd; - } - -private: - BluetoothStatus RecvMsg1() - { - struct iovec iv; - memset(&iv, 0, sizeof(iv)); - iv.iov_base = mBuf; - iv.iov_len = MSG1_SIZE; - - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iv; - msg.msg_iovlen = 1; - - ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL)); - if (res < 0) { - return STATUS_FAIL; - } - - mLen += res; - - return STATUS_SUCCESS; - } - - BluetoothStatus RecvMsg2() - { - struct iovec iv; - memset(&iv, 0, sizeof(iv)); - iv.iov_base = mBuf + MSG1_SIZE; - iv.iov_len = MSG2_SIZE; - - struct msghdr msg; - struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100]; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iv; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - - ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL)); - if (res < 0) { - return STATUS_FAIL; - } - - mLen += res; - - if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) { - return STATUS_FAIL; - } - - struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg); - - // Extract client fd from message header - for (; cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { - if (CMSGHDR_CONTAINS_FD(cmsgptr)) { - // if multiple file descriptors have been sent, we close - // all but the final one. - if (mClientFd != -1) { - TEMP_FAILURE_RETRY(close(mClientFd)); - } - // retrieve sent client fd - mClientFd = *(static_cast(CMSG_DATA(cmsgptr))); - } - } - - return STATUS_SUCCESS; - } - - int16_t ReadInt16(unsigned long aOffset) const - { - /* little-endian buffer */ - return (static_cast(mBuf[aOffset + 1]) << 8) | - static_cast(mBuf[aOffset]); - } - - int32_t ReadInt32(unsigned long aOffset) const - { - /* little-endian buffer */ - return (static_cast(mBuf[aOffset + 3]) << 24) | - (static_cast(mBuf[aOffset + 2]) << 16) | - (static_cast(mBuf[aOffset + 1]) << 8) | - static_cast(mBuf[aOffset]); - } - - void ReadBdAddress(unsigned long aOffset, nsAString& aBdAddress) const - { - const bt_bdaddr_t* bdAddress = - reinterpret_cast(mBuf+aOffset); - - if (NS_FAILED(Convert(*bdAddress, aBdAddress))) { - aBdAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); - } - } - - MessageLoopForIO::FileDescriptorWatcher mWatcher; - int mFd; - int mClientFd; - unsigned char mLen; - uint8_t mBuf[MSG1_SIZE + MSG2_SIZE]; -}; - -/* |SocketMessageWatcherTask| starts a SocketMessageWatcher - * on the I/O task - */ -class SocketMessageWatcherTask MOZ_FINAL : public Task -{ -public: - SocketMessageWatcherTask(SocketMessageWatcher* aWatcher) - : mWatcher(aWatcher) - { - MOZ_ASSERT(mWatcher); - } - - void Run() MOZ_OVERRIDE - { - mWatcher->Watch(); - } - -private: - SocketMessageWatcher* mWatcher; -}; - -/* |DeleteTask| deletes a class instance on the I/O thread - */ -template -class DeleteTask MOZ_FINAL : public Task -{ -public: - DeleteTask(T* aPtr) - : mPtr(aPtr) - { } - - void Run() MOZ_OVERRIDE - { - mPtr = nullptr; - } - -private: - nsAutoPtr mPtr; -}; - -/* |ConnectWatcher| specializes SocketMessageWatcher for - * connect operations by reading the socket messages from - * Bluedroid and forwarding the connected socket to the - * resource handler. - */ -class ConnectWatcher MOZ_FINAL : public SocketMessageWatcher -{ -public: - ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes) - : SocketMessageWatcher(aFd) - , mRes(aRes) - { } - - void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE - { - if (mRes) { - DispatchBluetoothSocketResult(mRes, - &BluetoothSocketResultHandler::Connect, - GetFd(), GetBdAddress(), - GetConnectionStatus(), aStatus); - } - MessageLoopForIO::current()->PostTask( - FROM_HERE, new DeleteTask(this)); - } - -private: - nsRefPtr mRes; -}; - -void -BluetoothSocketInterface::Connect(const nsAString& aBdAddr, - BluetoothSocketType aType, - const uint8_t aUuid[16], - int aChannel, bool aEncrypt, bool aAuth, - BluetoothSocketResultHandler* aRes) -{ - int fd; - bt_status_t status; - bt_bdaddr_t bdAddr; - btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && - NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->connect(&bdAddr, type, aUuid, aChannel, &fd, - (BTSOCK_FLAG_ENCRYPT * aEncrypt) | - (BTSOCK_FLAG_AUTH * aAuth)); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (status == BT_STATUS_SUCCESS) { - /* receive Bluedroid's socket-setup messages */ - Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes)); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t); - } else if (aRes) { - DispatchBluetoothSocketResult(aRes, - &BluetoothSocketResultHandler::Connect, - -1, EmptyString(), 0, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Specializes SocketMessageWatcher for Accept operations by - * reading the socket messages from Bluedroid and forwarding - * the received client socket to the resource handler. The - * first message is received immediately. When there's a new - * connection, Bluedroid sends the 2nd message with the socket - * info and socket file descriptor. - */ -class AcceptWatcher MOZ_FINAL : public SocketMessageWatcher -{ -public: - AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes) - : SocketMessageWatcher(aFd) - , mRes(aRes) - { - /* not supplying a result handler leaks received file descriptor */ - MOZ_ASSERT(mRes); - } - - void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE - { - if (mRes) { - DispatchBluetoothSocketResult(mRes, - &BluetoothSocketResultHandler::Accept, - GetClientFd(), GetBdAddress(), - GetConnectionStatus(), - aStatus); - } - MessageLoopForIO::current()->PostTask( - FROM_HERE, new DeleteTask(this)); - } - -private: - nsRefPtr mRes; -}; - -void -BluetoothSocketInterface::Accept(int aFd, BluetoothSocketResultHandler* aRes) -{ - /* receive Bluedroid's socket-setup messages and client fd */ - Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes)); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t); -} - -BluetoothSocketInterface::BluetoothSocketInterface( - const btsock_interface_t* aInterface) -: mInterface(aInterface) -{ - MOZ_ASSERT(mInterface); -} - -BluetoothSocketInterface::~BluetoothSocketInterface() -{ } - -// -// Handsfree Interface -// - -template<> -struct interface_traits -{ - typedef const bthf_interface_t const_interface_type; - - static const char* profile_id() - { - return BT_PROFILE_HANDSFREE_ID; - } -}; - -typedef - BluetoothInterfaceRunnable0 - BluetoothHandsfreeResultRunnable; - -typedef - BluetoothInterfaceRunnable1 - BluetoothHandsfreeErrorRunnable; - -static nsresult -DispatchBluetoothHandsfreeResult( - BluetoothHandsfreeResultHandler* aRes, - void (BluetoothHandsfreeResultHandler::*aMethod)(), - BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothHandsfreeResultRunnable(aRes, aMethod); - } else { - runnable = new BluetoothHandsfreeErrorRunnable(aRes, - &BluetoothHandsfreeResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -// Notification handling -// - -BluetoothHandsfreeNotificationHandler:: - ~BluetoothHandsfreeNotificationHandler() -{ } - -static BluetoothHandsfreeNotificationHandler* sHandsfreeNotificationHandler; - -struct BluetoothHandsfreeCallback -{ - class HandsfreeNotificationHandlerWrapper - { - public: - typedef BluetoothHandsfreeNotificationHandler ObjectType; - - static ObjectType* GetInstance() - { - MOZ_ASSERT(NS_IsMainThread()); - - return sHandsfreeNotificationHandler; - } - }; - - // Notifications - - typedef BluetoothNotificationRunnable2 - ConnectionStateNotification; - - typedef BluetoothNotificationRunnable2 - AudioStateNotification; - - typedef BluetoothNotificationRunnable1 - VoiceRecognitionNotification; - - typedef BluetoothNotificationRunnable0 - AnswerCallNotification; - - typedef BluetoothNotificationRunnable0 - HangupCallNotification; - - typedef BluetoothNotificationRunnable2 - VolumeNotification; - - typedef BluetoothNotificationRunnable1 - DialCallNotification; - - typedef BluetoothNotificationRunnable1 - DtmfNotification; - - typedef BluetoothNotificationRunnable1 - NRECNotification; - - typedef BluetoothNotificationRunnable1 - CallHoldNotification; - - typedef BluetoothNotificationRunnable0 - CnumNotification; - - typedef BluetoothNotificationRunnable0 - CindNotification; - - typedef BluetoothNotificationRunnable0 - CopsNotification; - - typedef BluetoothNotificationRunnable0 - ClccNotification; - - typedef BluetoothNotificationRunnable1 - UnknownAtNotification; - - typedef BluetoothNotificationRunnable0 - KeyPressedNotification; - - // Bluedroid Handsfree callbacks - - static void - ConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddr) - { - ConnectionStateNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::ConnectionStateNotification, - aState, aBdAddr); - } - - static void - AudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddr) - { - AudioStateNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::AudioStateNotification, - aState, aBdAddr); - } - - static void - VoiceRecognition(bthf_vr_state_t aState) - { - VoiceRecognitionNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification, - aState); - } - - static void - AnswerCall() - { - AnswerCallNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::AnswerCallNotification); - } - - static void - HangupCall() - { - HangupCallNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::HangupCallNotification); - } - - static void - Volume(bthf_volume_type_t aType, int aVolume) - { - VolumeNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::VolumeNotification, - aType, aVolume); - } - - static void - DialCall(char* aNumber) - { - DialCallNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::DialCallNotification, aNumber); - } - - static void - Dtmf(char aDtmf) - { - DtmfNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::DtmfNotification, aDtmf); - } - - static void - NoiseReductionEchoCancellation(bthf_nrec_t aNrec) - { - NRECNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::NRECNotification, aNrec); - } - - static void - CallHold(bthf_chld_type_t aChld) - { - CallHoldNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::CallHoldNotification, aChld); - } - - static void - Cnum() - { - CnumNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::CnumNotification); - } - - static void - Cind() - { - CindNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::CindNotification); - } - - static void - Cops() - { - CopsNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::CopsNotification); - } - - static void - Clcc() - { - ClccNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::ClccNotification); - } - - static void - UnknownAt(char* aAtString) - { - UnknownAtNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::UnknownAtNotification, - aAtString); - } - - static void - KeyPressed() - { - KeyPressedNotification::Dispatch( - &BluetoothHandsfreeNotificationHandler::KeyPressedNotification); - } -}; - -// Interface -// - -BluetoothHandsfreeInterface::BluetoothHandsfreeInterface( - const bthf_interface_t* aInterface) -: mInterface(aInterface) -{ - MOZ_ASSERT(mInterface); -} - -BluetoothHandsfreeInterface::~BluetoothHandsfreeInterface() -{ } - -void -BluetoothHandsfreeInterface::Init( - BluetoothHandsfreeNotificationHandler* aNotificationHandler, - BluetoothHandsfreeResultHandler* aRes) -{ - static bthf_callbacks_t sCallbacks = { - sizeof(sCallbacks), - BluetoothHandsfreeCallback::ConnectionState, - BluetoothHandsfreeCallback::AudioState, - BluetoothHandsfreeCallback::VoiceRecognition, - BluetoothHandsfreeCallback::AnswerCall, - BluetoothHandsfreeCallback::HangupCall, - BluetoothHandsfreeCallback::Volume, - BluetoothHandsfreeCallback::DialCall, - BluetoothHandsfreeCallback::Dtmf, - BluetoothHandsfreeCallback::NoiseReductionEchoCancellation, - BluetoothHandsfreeCallback::CallHold, - BluetoothHandsfreeCallback::Cnum, - BluetoothHandsfreeCallback::Cind, - BluetoothHandsfreeCallback::Cops, - BluetoothHandsfreeCallback::Clcc, - BluetoothHandsfreeCallback::UnknownAt, - BluetoothHandsfreeCallback::KeyPressed - }; - - sHandsfreeNotificationHandler = aNotificationHandler; - - bt_status_t status = mInterface->init(&sCallbacks); - - if (aRes) { - DispatchBluetoothHandsfreeResult(aRes, - &BluetoothHandsfreeResultHandler::Init, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::Cleanup(BluetoothHandsfreeResultHandler* aRes) -{ - mInterface->cleanup(); - - if (aRes) { - DispatchBluetoothHandsfreeResult(aRes, - &BluetoothHandsfreeResultHandler::Cleanup, - STATUS_SUCCESS); - } -} - -/* Connect / Disconnect */ - -void -BluetoothHandsfreeInterface::Connect(const nsAString& aBdAddr, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->connect(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::Connect, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::Disconnect( - const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->disconnect(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::Disconnect, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::ConnectAudio( - const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->connect_audio(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::ConnectAudio, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::DisconnectAudio( - const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->disconnect_audio(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::DisconnectAudio, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Voice Recognition */ - -void -BluetoothHandsfreeInterface::StartVoiceRecognition( - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status = mInterface->start_voice_recognition(); - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::StartVoiceRecognition, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::StopVoiceRecognition( - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status = mInterface->stop_voice_recognition(); - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::StopVoiceRecognition, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Volume */ - -void -BluetoothHandsfreeInterface::VolumeControl( - BluetoothHandsfreeVolumeType aType, int aVolume, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_volume_type_t type = BTHF_VOLUME_TYPE_SPK; - - if (NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->volume_control(type, aVolume); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::VolumeControl, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Device status */ - -void -BluetoothHandsfreeInterface::DeviceStatusNotification( - BluetoothHandsfreeNetworkState aNtkState, - BluetoothHandsfreeServiceType aSvcType, int aSignal, - int aBattChg, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_network_state_t ntkState = BTHF_NETWORK_STATE_NOT_AVAILABLE; - bthf_service_type_t svcType = BTHF_SERVICE_TYPE_HOME; - - if (NS_SUCCEEDED(Convert(aNtkState, ntkState)) && - NS_SUCCEEDED(Convert(aSvcType, svcType))) { - status = mInterface->device_status_notification(ntkState, svcType, - aSignal, aBattChg); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::DeviceStatusNotification, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Responses */ - -void -BluetoothHandsfreeInterface::CopsResponse( - const char* aCops, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status = mInterface->cops_response(aCops); - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::CopsResponse, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::CindResponse( - int aSvc, int aNumActive, int aNumHeld, - BluetoothHandsfreeCallState aCallSetupState, - int aSignal, int aRoam, int aBattChg, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_call_state_t callSetupState = BTHF_CALL_STATE_ACTIVE; - - if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState))) { - status = mInterface->cind_response(aSvc, aNumActive, aNumHeld, - callSetupState, aSignal, - aRoam, aBattChg); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::CindResponse, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::FormattedAtResponse( - const char* aRsp, BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status = mInterface->formatted_at_response(aRsp); - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::FormattedAtResponse, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::AtResponse( - BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_at_response_t responseCode = BTHF_AT_RESPONSE_ERROR; - - if (NS_SUCCEEDED(Convert(aResponseCode, responseCode))) { - status = mInterface->at_response(responseCode, aErrorCode); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::AtResponse, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothHandsfreeInterface::ClccResponse( - int aIndex, - BluetoothHandsfreeCallDirection aDir, - BluetoothHandsfreeCallState aState, - BluetoothHandsfreeCallMode aMode, - BluetoothHandsfreeCallMptyType aMpty, - const nsAString& aNumber, - BluetoothHandsfreeCallAddressType aType, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_call_direction_t dir = BTHF_CALL_DIRECTION_OUTGOING; - bthf_call_state_t state = BTHF_CALL_STATE_ACTIVE; - bthf_call_mode_t mode = BTHF_CALL_TYPE_VOICE; - bthf_call_mpty_type_t mpty = BTHF_CALL_MPTY_TYPE_SINGLE; - bthf_call_addrtype_t type = BTHF_CALL_ADDRTYPE_UNKNOWN; - - if (NS_SUCCEEDED(Convert(aDir, dir)) && - NS_SUCCEEDED(Convert(aState, state)) && - NS_SUCCEEDED(Convert(aMode, mode)) && - NS_SUCCEEDED(Convert(aMpty, mpty)) && - NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->clcc_response(aIndex, dir, state, mode, mpty, - NS_ConvertUTF16toUTF8(aNumber).get(), - type); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::ClccResponse, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Phone State */ - -void -BluetoothHandsfreeInterface::PhoneStateChange(int aNumActive, int aNumHeld, - BluetoothHandsfreeCallState aCallSetupState, const nsAString& aNumber, - BluetoothHandsfreeCallAddressType aType, - BluetoothHandsfreeResultHandler* aRes) -{ - bt_status_t status; - bthf_call_state_t callSetupState = BTHF_CALL_STATE_ACTIVE; - bthf_call_addrtype_t type = BTHF_CALL_ADDRTYPE_UNKNOWN; - - if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState)) && - NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->phone_state_change( - aNumActive, aNumHeld, callSetupState, - NS_ConvertUTF16toUTF8(aNumber).get(), type); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothHandsfreeResult( - aRes, &BluetoothHandsfreeResultHandler::PhoneStateChange, - ConvertDefault(status, STATUS_FAIL)); - } -} - -// -// Bluetooth Advanced Audio Interface -// - -template<> -struct interface_traits -{ - typedef const btav_interface_t const_interface_type; - - static const char* profile_id() - { - return BT_PROFILE_ADVANCED_AUDIO_ID; - } -}; - -typedef - BluetoothInterfaceRunnable0 - BluetoothA2dpResultRunnable; - -typedef - BluetoothInterfaceRunnable1 - BluetoothA2dpErrorRunnable; - -static nsresult -DispatchBluetoothA2dpResult( - BluetoothA2dpResultHandler* aRes, - void (BluetoothA2dpResultHandler::*aMethod)(), - BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothA2dpResultRunnable(aRes, aMethod); - } else { - runnable = new BluetoothA2dpErrorRunnable(aRes, - &BluetoothA2dpResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -// Notification handling -// - -BluetoothA2dpNotificationHandler::~BluetoothA2dpNotificationHandler() -{ } - -static BluetoothA2dpNotificationHandler* sA2dpNotificationHandler; - -struct BluetoothA2dpCallback -{ - class A2dpNotificationHandlerWrapper - { - public: - typedef BluetoothA2dpNotificationHandler ObjectType; - - static ObjectType* GetInstance() - { - MOZ_ASSERT(NS_IsMainThread()); - - return sA2dpNotificationHandler; - } - }; - - // Notifications - - typedef BluetoothNotificationRunnable2 - ConnectionStateNotification; - - typedef BluetoothNotificationRunnable2 - AudioStateNotification; - - // Bluedroid A2DP callbacks - - static void - ConnectionState(btav_connection_state_t aState, bt_bdaddr_t* aBdAddr) - { - ConnectionStateNotification::Dispatch( - &BluetoothA2dpNotificationHandler::ConnectionStateNotification, - aState, aBdAddr); - } - - static void - AudioState(btav_audio_state_t aState, bt_bdaddr_t* aBdAddr) - { - AudioStateNotification::Dispatch( - &BluetoothA2dpNotificationHandler::AudioStateNotification, - aState, aBdAddr); - } -}; - -// Interface -// - -BluetoothA2dpInterface::BluetoothA2dpInterface( - const btav_interface_t* aInterface) -: mInterface(aInterface) -{ - MOZ_ASSERT(mInterface); -} - -BluetoothA2dpInterface::~BluetoothA2dpInterface() -{ } - -void -BluetoothA2dpInterface::Init( - BluetoothA2dpNotificationHandler* aNotificationHandler, - BluetoothA2dpResultHandler* aRes) -{ - static btav_callbacks_t sCallbacks = { - sizeof(sCallbacks), - BluetoothA2dpCallback::ConnectionState, - BluetoothA2dpCallback::AudioState - }; - - sA2dpNotificationHandler = aNotificationHandler; - - bt_status_t status = mInterface->init(&sCallbacks); - - if (aRes) { - DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Init, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothA2dpInterface::Cleanup(BluetoothA2dpResultHandler* aRes) -{ - mInterface->cleanup(); - - if (aRes) { - DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Cleanup, - STATUS_SUCCESS); - } -} - -void -BluetoothA2dpInterface::Connect(const nsAString& aBdAddr, - BluetoothA2dpResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->connect(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Connect, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothA2dpInterface::Disconnect(const nsAString& aBdAddr, - BluetoothA2dpResultHandler* aRes) -{ - bt_status_t status; - bt_bdaddr_t bdAddr; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->disconnect(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Disconnect, - ConvertDefault(status, STATUS_FAIL)); - } -} - -// -// Bluetooth AVRCP Interface -// - -#if ANDROID_VERSION >= 18 -template<> -struct interface_traits -{ - typedef const btrc_interface_t const_interface_type; - - static const char* profile_id() - { - return BT_PROFILE_AV_RC_ID; - } -}; -#endif - -typedef - BluetoothInterfaceRunnable0 - BluetoothAvrcpResultRunnable; - -typedef - BluetoothInterfaceRunnable1 - BluetoothAvrcpErrorRunnable; - -static nsresult -DispatchBluetoothAvrcpResult( - BluetoothAvrcpResultHandler* aRes, - void (BluetoothAvrcpResultHandler::*aMethod)(), - BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothAvrcpResultRunnable(aRes, aMethod); - } else { - runnable = new BluetoothAvrcpErrorRunnable(aRes, - &BluetoothAvrcpResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -// Notification handling -// - -BluetoothAvrcpNotificationHandler::~BluetoothAvrcpNotificationHandler() -{ } - -static BluetoothAvrcpNotificationHandler* sAvrcpNotificationHandler; - -struct BluetoothAvrcpCallback -{ - class AvrcpNotificationHandlerWrapper - { - public: - typedef BluetoothAvrcpNotificationHandler ObjectType; - - static ObjectType* GetInstance() - { - MOZ_ASSERT(NS_IsMainThread()); - - return sAvrcpNotificationHandler; - } - }; - - // Notifications - - typedef BluetoothNotificationRunnable0 - GetPlayStatusNotification; - - typedef BluetoothNotificationRunnable0 - ListPlayerAppAttrNotification; - - typedef BluetoothNotificationRunnable1 - ListPlayerAppValuesNotification; - - typedef BluetoothNotificationRunnable2, - uint8_t, const BluetoothAvrcpPlayerAttribute*> - GetPlayerAppValueNotification; - - typedef BluetoothNotificationRunnable2, - uint8_t, const BluetoothAvrcpPlayerAttribute*> - GetPlayerAppAttrsTextNotification; - - typedef BluetoothNotificationRunnable3, - uint8_t, uint8_t, const uint8_t*> - GetPlayerAppValuesTextNotification; - - typedef BluetoothNotificationRunnable1 - SetPlayerAppValueNotification; - - typedef BluetoothNotificationRunnable2, - uint8_t, const BluetoothAvrcpMediaAttribute*> - GetElementAttrNotification; - - typedef BluetoothNotificationRunnable2 - RegisterNotificationNotification; - - typedef BluetoothNotificationRunnable2 - RemoteFeatureNotification; - - typedef BluetoothNotificationRunnable2 - VolumeChangeNotification; - - typedef BluetoothNotificationRunnable2 - PassthroughCmdNotification; - - // Bluedroid AVRCP callbacks - -#if ANDROID_VERSION >= 18 - static void - GetPlayStatus() - { - GetPlayStatusNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::GetPlayStatusNotification); - } - - static void - ListPlayerAppAttr() - { - ListPlayerAppAttrNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::ListPlayerAppAttrNotification); - } - - static void - ListPlayerAppValues(btrc_player_attr_t aAttrId) - { - ListPlayerAppValuesNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::ListPlayerAppValuesNotification, - aAttrId); - } - - static void - GetPlayerAppValue(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs) - { - GetPlayerAppValueNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::GetPlayerAppValueNotification, - aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); - } - - static void - GetPlayerAppAttrsText(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs) - { - GetPlayerAppAttrsTextNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::GetPlayerAppAttrsTextNotification, - aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); - } - - static void - GetPlayerAppValuesText(uint8_t aAttrId, uint8_t aNumVals, uint8_t* aVals) - { - GetPlayerAppValuesTextNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::GetPlayerAppValuesTextNotification, - aAttrId, aNumVals, ConvertArray(aVals, aNumVals)); - } - - static void - SetPlayerAppValue(btrc_player_settings_t* aVals) - { - SetPlayerAppValueNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::SetPlayerAppValueNotification, - *aVals); - } - - static void - GetElementAttr(uint8_t aNumAttrs, btrc_media_attr_t* aAttrs) - { - GetElementAttrNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::GetElementAttrNotification, - aNumAttrs, ConvertArray(aAttrs, aNumAttrs)); - } - - static void - RegisterNotification(btrc_event_id_t aEvent, uint32_t aParam) - { - RegisterNotificationNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::RegisterNotificationNotification, - aEvent, aParam); - } -#endif // ANDROID_VERSION >= 18 - -#if ANDROID_VERSION >= 19 - static void - RemoteFeature(bt_bdaddr_t* aBdAddr, btrc_remote_features_t aFeatures) - { - RemoteFeatureNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::RemoteFeatureNotification, - aBdAddr, aFeatures); - } - - static void - VolumeChange(uint8_t aVolume, uint8_t aCType) - { - VolumeChangeNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::VolumeChangeNotification, - aVolume, aCType); - } - - static void - PassthroughCmd(int aId, int aKeyState) - { - PassthroughCmdNotification::Dispatch( - &BluetoothAvrcpNotificationHandler::PassthroughCmdNotification, - aId, aKeyState); - } -#endif // ANDROID_VERSION >= 19 -}; - -// Interface -// - -BluetoothAvrcpInterface::BluetoothAvrcpInterface( -#if ANDROID_VERSION >= 18 - const btrc_interface_t* aInterface -#endif - ) -#if ANDROID_VERSION >= 18 -: mInterface(aInterface) -#endif -{ -#if ANDROID_VERSION >= 18 - MOZ_ASSERT(mInterface); -#endif -} - -BluetoothAvrcpInterface::~BluetoothAvrcpInterface() -{ } - -void -BluetoothAvrcpInterface::Init( - BluetoothAvrcpNotificationHandler* aNotificationHandler, - BluetoothAvrcpResultHandler* aRes) -{ -#if ANDROID_VERSION >= 18 - static btrc_callbacks_t sCallbacks = { - sizeof(sCallbacks), -#if ANDROID_VERSION >= 19 - BluetoothAvrcpCallback::RemoteFeature, -#endif - BluetoothAvrcpCallback::GetPlayStatus, - BluetoothAvrcpCallback::ListPlayerAppAttr, - BluetoothAvrcpCallback::ListPlayerAppValues, - BluetoothAvrcpCallback::GetPlayerAppValue, - BluetoothAvrcpCallback::GetPlayerAppAttrsText, - BluetoothAvrcpCallback::GetPlayerAppValuesText, - BluetoothAvrcpCallback::SetPlayerAppValue, - BluetoothAvrcpCallback::GetElementAttr, - BluetoothAvrcpCallback::RegisterNotification -#if ANDROID_VERSION >= 19 - , - BluetoothAvrcpCallback::VolumeChange, - BluetoothAvrcpCallback::PassthroughCmd -#endif - }; -#endif // ANDROID_VERSION >= 18 - - sAvrcpNotificationHandler = aNotificationHandler; - -#if ANDROID_VERSION >= 18 - bt_status_t status = mInterface->init(&sCallbacks); -#else - bt_status_t status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Init, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::Cleanup(BluetoothAvrcpResultHandler* aRes) -{ -#if ANDROID_VERSION >= 18 - mInterface->cleanup(); -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup, - STATUS_SUCCESS); - } -} - -void -BluetoothAvrcpInterface::GetPlayStatusRsp(ControlPlayStatus aPlayStatus, - uint32_t aSongLen, uint32_t aSongPos, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - btrc_play_status_t playStatus = BTRC_PLAYSTATE_STOPPED; - - if (!(NS_FAILED(Convert(aPlayStatus, playStatus)))) { - status = mInterface->get_play_status_rsp(playStatus, aSongLen, aSongPos); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::ListPlayerAppAttrRsp( - int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - ConvertArray pAttrsArray(aPAttrs, aNumAttr); - nsAutoArrayPtr pAttrs; - - if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) { - status = mInterface->list_player_app_attr_rsp(aNumAttr, pAttrs); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::ListPlayerAppValueRsp( - int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes) -{ -#if ANDROID_VERSION >= 18 - bt_status_t status = mInterface->list_player_app_value_rsp(aNumVal, aPVals); -#else - bt_status_t status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::GetPlayerAppValueRsp( - uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - btrc_player_settings_t pVals; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (false /* TODO: we don't support any player app values currently */) { - status = mInterface->get_player_app_value_rsp(&pVals); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::GetPlayerAppAttrTextRsp( - int aNumAttr, const uint8_t* aIds, const char** aTexts, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - btrc_player_setting_text_t* aPAttrs; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (false /* TODO: we don't support any attributes currently */) { - status = mInterface->get_player_app_attr_text_rsp(aNumAttr, aPAttrs); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::GetPlayerAppValueTextRsp( - int aNumVal, const uint8_t* aIds, const char** aTexts, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - btrc_player_setting_text_t* pVals; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (false /* TODO: we don't support any values currently */) { - status = mInterface->get_player_app_value_text_rsp(aNumVal, pVals); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::GetElementAttrRsp( - uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttrs, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - ConvertArray pAttrsArray(aAttrs, aNumAttr); - nsAutoArrayPtr pAttrs; - - if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) { - status = mInterface->get_element_attr_rsp(aNumAttr, pAttrs); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::SetPlayerAppValueRsp( - BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - btrc_status_t rspStatus = BTRC_STS_BAD_CMD; // silences compiler warning - - if (NS_SUCCEEDED(Convert(aRspStatus, rspStatus))) { - status = mInterface->set_player_app_value_rsp(rspStatus); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::RegisterNotificationRsp( - BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType, - const BluetoothAvrcpNotificationParam& aParam, - BluetoothAvrcpResultHandler* aRes) -{ - bt_status_t status; - -#if ANDROID_VERSION >= 18 - nsresult rv; - btrc_event_id_t event = { }; - btrc_notification_type_t type = BTRC_NOTIFICATION_TYPE_INTERIM; - btrc_register_notification_t param; - - switch (aEvent) { - case AVRCP_EVENT_PLAY_STATUS_CHANGED: - rv = Convert(aParam.mPlayStatus, param.play_status); - break; - case AVRCP_EVENT_TRACK_CHANGE: - MOZ_ASSERT(sizeof(aParam.mTrack) == sizeof(param.track)); - memcpy(param.track, aParam.mTrack, sizeof(param.track)); - rv = NS_OK; - break; - case AVRCP_EVENT_TRACK_REACHED_END: - NS_NOTREACHED("Unknown conversion"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - case AVRCP_EVENT_TRACK_REACHED_START: - NS_NOTREACHED("Unknown conversion"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - case AVRCP_EVENT_PLAY_POS_CHANGED: - param.song_pos = aParam.mSongPos; - rv = NS_OK; - break; - case AVRCP_EVENT_APP_SETTINGS_CHANGED: - NS_NOTREACHED("Unknown conversion"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - default: - NS_NOTREACHED("Unknown conversion"); - rv = NS_ERROR_ILLEGAL_VALUE; - break; - } - - if (NS_SUCCEEDED(rv) && - NS_SUCCEEDED(Convert(aEvent, event)) && - NS_SUCCEEDED(Convert(aType, type))) { - status = mInterface->register_notification_rsp(event, type, ¶m); - } else { - status = BT_STATUS_PARM_INVALID; - } -#else - status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothAvrcpInterface::SetVolume(uint8_t aVolume, - BluetoothAvrcpResultHandler* aRes) -{ -#if ANDROID_VERSION >= 19 - bt_status_t status = mInterface->set_volume(aVolume); -#else - bt_status_t status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothAvrcpResult( - aRes, &BluetoothAvrcpResultHandler::SetVolume, - ConvertDefault(status, STATUS_FAIL)); - } -} - -// -// Bluetooth Core Interface -// - -typedef - BluetoothInterfaceRunnable0 - BluetoothResultRunnable; - -typedef - BluetoothInterfaceRunnable1 - BluetoothErrorRunnable; - -static nsresult -DispatchBluetoothResult(BluetoothResultHandler* aRes, - void (BluetoothResultHandler::*aMethod)(), - BluetoothStatus aStatus) -{ - MOZ_ASSERT(aRes); - - nsRunnable* runnable; - - if (aStatus == STATUS_SUCCESS) { - runnable = new BluetoothResultRunnable(aRes, aMethod); - } else { - runnable = new - BluetoothErrorRunnable(aRes, &BluetoothResultHandler::OnError, aStatus); - } - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - BT_WARNING("NS_DispatchToMainThread failed: %X", rv); - } - return rv; -} - -// Notification handling -// - -BluetoothNotificationHandler::~BluetoothNotificationHandler() -{ } - -static BluetoothNotificationHandler* sNotificationHandler; - -struct BluetoothCallback -{ - class NotificationHandlerWrapper - { - public: - typedef BluetoothNotificationHandler ObjectType; - - static ObjectType* GetInstance() - { - MOZ_ASSERT(NS_IsMainThread()); - - return sNotificationHandler; - } - }; - - // Notifications - - typedef BluetoothNotificationRunnable1 - AdapterStateChangedNotification; - - typedef BluetoothNotificationRunnable3, - BluetoothStatus, int, - const BluetoothProperty*> - AdapterPropertiesNotification; - - typedef BluetoothNotificationRunnable4, - BluetoothStatus, const nsAString&, - int, const BluetoothProperty*> - RemoteDevicePropertiesNotification; - - typedef BluetoothNotificationRunnable2, - int, const BluetoothProperty*> - DeviceFoundNotification; - - typedef BluetoothNotificationRunnable1 - DiscoveryStateChangedNotification; - - typedef BluetoothNotificationRunnable3 - PinRequestNotification; - - typedef BluetoothNotificationRunnable5 - SspRequestNotification; - - typedef BluetoothNotificationRunnable3 - BondStateChangedNotification; - - typedef BluetoothNotificationRunnable3 - AclStateChangedNotification; - - typedef BluetoothNotificationRunnable3, - uint8_t, uint16_t, const uint8_t*> - DutModeRecvNotification; - - typedef BluetoothNotificationRunnable2 - LeTestModeNotification; - - // Bluedroid callbacks - - static const bt_property_t* - AlignedProperties(bt_property_t* aProperties, size_t aNumProperties, - nsAutoArrayPtr& aPropertiesArray) - { - // See Bug 989976: consider aProperties address is not aligned. If - // it is aligned, we return the pointer directly; otherwise we make - // an aligned copy. The argument |aPropertiesArray| keeps track of - // the memory buffer. - if (!(reinterpret_cast(aProperties) % sizeof(void*))) { - return aProperties; - } - - bt_property_t* properties = new bt_property_t[aNumProperties]; - memcpy(properties, aProperties, aNumProperties * sizeof(*properties)); - aPropertiesArray = properties; - - return properties; - } - - static void - AdapterStateChanged(bt_state_t aStatus) - { - AdapterStateChangedNotification::Dispatch( - &BluetoothNotificationHandler::AdapterStateChangedNotification, - aStatus); - } - - static void - AdapterProperties(bt_status_t aStatus, int aNumProperties, - bt_property_t* aProperties) - { - nsAutoArrayPtr propertiesArray; - - AdapterPropertiesNotification::Dispatch( - &BluetoothNotificationHandler::AdapterPropertiesNotification, - ConvertDefault(aStatus, STATUS_FAIL), aNumProperties, - ConvertArray( - AlignedProperties(aProperties, aNumProperties, propertiesArray), - aNumProperties)); - } - - static void - RemoteDeviceProperties(bt_status_t aStatus, bt_bdaddr_t* aBdAddress, - int aNumProperties, bt_property_t* aProperties) - { - nsAutoArrayPtr propertiesArray; - - RemoteDevicePropertiesNotification::Dispatch( - &BluetoothNotificationHandler::RemoteDevicePropertiesNotification, - ConvertDefault(aStatus, STATUS_FAIL), aBdAddress, aNumProperties, - ConvertArray( - AlignedProperties(aProperties, aNumProperties, propertiesArray), - aNumProperties)); - } - - static void - DeviceFound(int aNumProperties, bt_property_t* aProperties) - { - nsAutoArrayPtr propertiesArray; - - DeviceFoundNotification::Dispatch( - &BluetoothNotificationHandler::DeviceFoundNotification, - aNumProperties, - ConvertArray( - AlignedProperties(aProperties, aNumProperties, propertiesArray), - aNumProperties)); - } - - static void - DiscoveryStateChanged(bt_discovery_state_t aState) - { - DiscoveryStateChangedNotification::Dispatch( - &BluetoothNotificationHandler::DiscoveryStateChangedNotification, - aState); - } - - static void - PinRequest(bt_bdaddr_t* aRemoteBdAddress, - bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass) - { - PinRequestNotification::Dispatch( - &BluetoothNotificationHandler::PinRequestNotification, - aRemoteBdAddress, aRemoteBdName, aRemoteClass); - } - - static void - SspRequest(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName, - uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant, - uint32_t aPasskey) - { - SspRequestNotification::Dispatch( - &BluetoothNotificationHandler::SspRequestNotification, - aRemoteBdAddress, aRemoteBdName, aRemoteClass, - aPairingVariant, aPasskey); - } - - static void - BondStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, - bt_bond_state_t aState) - { - BondStateChangedNotification::Dispatch( - &BluetoothNotificationHandler::BondStateChangedNotification, - aStatus, aRemoteBdAddress, aState); - } - - static void - AclStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, - bt_acl_state_t aState) - { - AclStateChangedNotification::Dispatch( - &BluetoothNotificationHandler::AclStateChangedNotification, - aStatus, aRemoteBdAddress, aState); - } - - static void - ThreadEvt(bt_cb_thread_evt evt) - { - // This callback maintains internal state and is not exported. - } - - static void - DutModeRecv(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen) - { - DutModeRecvNotification::Dispatch( - &BluetoothNotificationHandler::DutModeRecvNotification, - aOpcode, ConvertArray(aBuf, aLen), aLen); - } - - static void - LeTestMode(bt_status_t aStatus, uint16_t aNumPackets) - { - LeTestModeNotification::Dispatch( - &BluetoothNotificationHandler::LeTestModeNotification, - aStatus, aNumPackets); - } -}; - -// Interface -// - -/* returns the container structure of a variable; _t is the container's - * type, _v the name of the variable, and _m is _v's field within _t - */ -#define container(_t, _v, _m) \ - ( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) ) - -BluetoothInterface* -BluetoothInterface::GetInstance() -{ - static BluetoothInterface* sBluetoothInterface; - - if (sBluetoothInterface) { - return sBluetoothInterface; - } - - /* get driver module */ - - const hw_module_t* module; - int err = hw_get_module(BT_HARDWARE_MODULE_ID, &module); - if (err) { - BT_WARNING("hw_get_module failed: %s", strerror(err)); - return nullptr; - } - - /* get device */ - - hw_device_t* device; - err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); - if (err) { - BT_WARNING("open failed: %s", strerror(err)); - return nullptr; - } - - const bluetooth_device_t* bt_device = - container(bluetooth_device_t, device, common); - - /* get interface */ - - const bt_interface_t* bt_interface = bt_device->get_bluetooth_interface(); - if (!bt_interface) { - BT_WARNING("get_bluetooth_interface failed"); - goto err_get_bluetooth_interface; - } - - if (bt_interface->size != sizeof(*bt_interface)) { - BT_WARNING("interface of incorrect size"); - goto err_bt_interface_size; - } - - sBluetoothInterface = new BluetoothInterface(bt_interface); - - return sBluetoothInterface; - -err_bt_interface_size: -err_get_bluetooth_interface: - err = device->close(device); - if (err) { - BT_WARNING("close failed: %s", strerror(err)); - } - return nullptr; -} - -BluetoothInterface::BluetoothInterface(const bt_interface_t* aInterface) -: mInterface(aInterface) -{ - MOZ_ASSERT(mInterface); -} - -BluetoothInterface::~BluetoothInterface() -{ } - -void -BluetoothInterface::Init(BluetoothNotificationHandler* aNotificationHandler, - BluetoothResultHandler* aRes) -{ - static bt_callbacks_t sBluetoothCallbacks = { - sizeof(sBluetoothCallbacks), - BluetoothCallback::AdapterStateChanged, - BluetoothCallback::AdapterProperties, - BluetoothCallback::RemoteDeviceProperties, - BluetoothCallback::DeviceFound, - BluetoothCallback::DiscoveryStateChanged, - BluetoothCallback::PinRequest, - BluetoothCallback::SspRequest, - BluetoothCallback::BondStateChanged, - BluetoothCallback::AclStateChanged, - BluetoothCallback::ThreadEvt, - BluetoothCallback::DutModeRecv, -#if ANDROID_VERSION >= 18 - BluetoothCallback::LeTestMode -#endif - }; - - sNotificationHandler = aNotificationHandler; - - int status = mInterface->init(&sBluetoothCallbacks); - - if (aRes) { - DispatchBluetoothResult(aRes, &BluetoothResultHandler::Init, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::Cleanup(BluetoothResultHandler* aRes) -{ - mInterface->cleanup(); - - if (aRes) { - DispatchBluetoothResult(aRes, &BluetoothResultHandler::Cleanup, - STATUS_SUCCESS); - } - - sNotificationHandler = nullptr; -} - -void -BluetoothInterface::Enable(BluetoothResultHandler* aRes) -{ - int status = mInterface->enable(); - - if (aRes) { - DispatchBluetoothResult(aRes, &BluetoothResultHandler::Enable, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::Disable(BluetoothResultHandler* aRes) -{ - int status = mInterface->disable(); - - if (aRes) { - DispatchBluetoothResult(aRes, &BluetoothResultHandler::Disable, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Adapter Properties */ - -void -BluetoothInterface::GetAdapterProperties(BluetoothResultHandler* aRes) -{ - int status = mInterface->get_adapter_properties(); - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetAdapterProperties, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::GetAdapterProperty(const nsAString& aName, - BluetoothResultHandler* aRes) -{ - int status; - bt_property_type_t type; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (false /* TODO: we don't support any values for aName currently */) { - status = mInterface->get_adapter_property(type); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetAdapterProperties, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::SetAdapterProperty(const BluetoothNamedValue& aProperty, - BluetoothResultHandler* aRes) -{ - int status; - ConvertNamedValue convertProperty(aProperty); - bt_property_t property; - - if (NS_SUCCEEDED(Convert(convertProperty, property))) { - status = mInterface->set_adapter_property(&property); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::SetAdapterProperty, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Remote Device Properties */ - -void -BluetoothInterface::GetRemoteDeviceProperties(const nsAString& aRemoteAddr, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t addr; - - if (NS_SUCCEEDED(Convert(aRemoteAddr, addr))) { - status = mInterface->get_remote_device_properties(&addr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetRemoteDeviceProperties, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::GetRemoteDeviceProperty(const nsAString& aRemoteAddr, - const nsAString& aName, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t remoteAddr; - bt_property_type_t name; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && - false /* TODO: we don't support any values for aName currently */) { - status = mInterface->get_remote_device_property(&remoteAddr, name); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetRemoteDeviceProperty, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::SetRemoteDeviceProperty(const nsAString& aRemoteAddr, - const BluetoothNamedValue& aProperty, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t remoteAddr; - bt_property_t property; - - /* FIXME: you need to implement the missing conversion functions */ - NS_NOTREACHED("Conversion function missing"); - - if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && - false /* TODO: we don't support any values for aProperty currently */) { - status = mInterface->set_remote_device_property(&remoteAddr, &property); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::SetRemoteDeviceProperty, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Remote Services */ - -void -BluetoothInterface::GetRemoteServiceRecord(const nsAString& aRemoteAddr, - const uint8_t aUuid[16], - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t remoteAddr; - bt_uuid_t uuid; - - if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr)) && - NS_SUCCEEDED(Convert(aUuid, uuid))) { - status = mInterface->get_remote_service_record(&remoteAddr, &uuid); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetRemoteServiceRecord, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::GetRemoteServices(const nsAString& aRemoteAddr, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t remoteAddr; - - if (NS_SUCCEEDED(Convert(aRemoteAddr, remoteAddr))) { - status = mInterface->get_remote_services(&remoteAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::GetRemoteServices, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Discovery */ - -void -BluetoothInterface::StartDiscovery(BluetoothResultHandler* aRes) -{ - int status = mInterface->start_discovery(); - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::StartDiscovery, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::CancelDiscovery(BluetoothResultHandler* aRes) -{ - int status = mInterface->cancel_discovery(); - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::CancelDiscovery, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Bonds */ - -void -BluetoothInterface::CreateBond(const nsAString& aBdAddr, - BluetoothResultHandler* aRes) -{ - bt_bdaddr_t bdAddr; - int status; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->create_bond(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::CreateBond, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::RemoveBond(const nsAString& aBdAddr, - BluetoothResultHandler* aRes) -{ - bt_bdaddr_t bdAddr; - int status; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->remove_bond(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::RemoveBond, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::CancelBond(const nsAString& aBdAddr, - BluetoothResultHandler* aRes) -{ - bt_bdaddr_t bdAddr; - int status; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) { - status = mInterface->cancel_bond(&bdAddr); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::CancelBond, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Authentication */ - -void -BluetoothInterface::PinReply(const nsAString& aBdAddr, bool aAccept, - const nsAString& aPinCode, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t bdAddr; - uint8_t accept; - bt_pin_code_t pinCode; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && - NS_SUCCEEDED(Convert(aAccept, accept)) && - NS_SUCCEEDED(Convert(aPinCode, pinCode))) { - status = mInterface->pin_reply(&bdAddr, accept, aPinCode.Length(), - &pinCode); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::PinReply, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::SspReply(const nsAString& aBdAddr, - const nsAString& aVariant, - bool aAccept, uint32_t aPasskey, - BluetoothResultHandler* aRes) -{ - int status; - bt_bdaddr_t bdAddr; - bt_ssp_variant_t variant; - uint8_t accept; - - if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && - NS_SUCCEEDED(Convert(aVariant, variant)) && - NS_SUCCEEDED(Convert(aAccept, accept))) { - status = mInterface->ssp_reply(&bdAddr, variant, accept, aPasskey); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::SspReply, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* DUT Mode */ - -void -BluetoothInterface::DutModeConfigure(bool aEnable, - BluetoothResultHandler* aRes) -{ - int status; - uint8_t enable; - - if (NS_SUCCEEDED(Convert(aEnable, enable))) { - status = mInterface->dut_mode_configure(enable); - } else { - status = BT_STATUS_PARM_INVALID; - } - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::DutModeConfigure, - ConvertDefault(status, STATUS_FAIL)); - } -} - -void -BluetoothInterface::DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, - BluetoothResultHandler* aRes) -{ - int status = mInterface->dut_mode_send(aOpcode, aBuf, aLen); - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::DutModeSend, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* LE Mode */ - -void -BluetoothInterface::LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen, - BluetoothResultHandler* aRes) -{ -#if ANDROID_VERSION >= 18 - int status = mInterface->le_test_mode(aOpcode, aBuf, aLen); -#else - int status = BT_STATUS_UNSUPPORTED; -#endif - - if (aRes) { - DispatchBluetoothResult(aRes, - &BluetoothResultHandler::LeTestMode, - ConvertDefault(status, STATUS_FAIL)); - } -} - -/* Profile Interfaces */ - -template -T* -BluetoothInterface::CreateProfileInterface() -{ - typename interface_traits::const_interface_type* interface = - reinterpret_cast::const_interface_type*>( - mInterface->get_profile_interface(interface_traits::profile_id())); - - if (!interface) { - BT_WARNING("Bluetooth profile '%s' is not supported", - interface_traits::profile_id()); - return nullptr; - } - - if (interface->size != sizeof(*interface)) { - BT_WARNING("interface of incorrect size"); - return nullptr; - } - - return new T(interface); -} - -#if ANDROID_VERSION < 18 -/* - * Bluedroid versions that don't support AVRCP will call this function - * to create an AVRCP interface. All interface methods will fail with - * the error constant STATUS_UNSUPPORTED. - */ -template <> -BluetoothAvrcpInterface* -BluetoothInterface::CreateProfileInterface() -{ - BT_WARNING("Bluetooth profile 'avrcp' is not supported"); - - return new BluetoothAvrcpInterface(); -} -#endif - -template -T* -BluetoothInterface::GetProfileInterface() -{ - static T* sBluetoothProfileInterface; - - if (sBluetoothProfileInterface) { - return sBluetoothProfileInterface; - } - - sBluetoothProfileInterface = CreateProfileInterface(); - - return sBluetoothProfileInterface; -} - -BluetoothSocketInterface* -BluetoothInterface::GetBluetoothSocketInterface() -{ - return GetProfileInterface(); -} - -BluetoothHandsfreeInterface* -BluetoothInterface::GetBluetoothHandsfreeInterface() -{ - return GetProfileInterface(); -} - -BluetoothA2dpInterface* -BluetoothInterface::GetBluetoothA2dpInterface() -{ - return GetProfileInterface(); -} - -BluetoothAvrcpInterface* -BluetoothInterface::GetBluetoothAvrcpInterface() -{ - return GetProfileInterface(); -} - -END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp new file mode 100644 index 000000000000..8268df279120 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp @@ -0,0 +1,480 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BluetoothSocketHALInterface.h" +#include +#include +#include +#include "BluetoothHALHelpers.h" +#include "nsXULAppAPI.h" + +BEGIN_BLUETOOTH_NAMESPACE + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothSocketHALIntResultRunnable; + +typedef + BluetoothHALInterfaceRunnable3 + BluetoothSocketHALIntStringIntResultRunnable; + +typedef + BluetoothHALInterfaceRunnable1 + BluetoothSocketHALErrorRunnable; + +static nsresult +DispatchBluetoothSocketHALResult( + BluetoothSocketResultHandler* aRes, + void (BluetoothSocketResultHandler::*aMethod)(int), int aArg, + BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothSocketHALIntResultRunnable(aRes, aMethod, aArg); + } else { + runnable = new BluetoothSocketHALErrorRunnable(aRes, + &BluetoothSocketResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +static nsresult +DispatchBluetoothSocketHALResult( + BluetoothSocketResultHandler* aRes, + void (BluetoothSocketResultHandler::*aMethod)(int, const nsAString&, int), + int aArg1, const nsAString& aArg2, int aArg3, BluetoothStatus aStatus) +{ + MOZ_ASSERT(aRes); + + nsRunnable* runnable; + + if (aStatus == STATUS_SUCCESS) { + runnable = new BluetoothSocketHALIntStringIntResultRunnable( + aRes, aMethod, aArg1, aArg2, aArg3); + } else { + runnable = new BluetoothSocketHALErrorRunnable(aRes, + &BluetoothSocketResultHandler::OnError, aStatus); + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + return rv; +} + +void +BluetoothSocketHALInterface::Listen(BluetoothSocketType aType, + const nsAString& aServiceName, + const uint8_t aServiceUuid[16], + int aChannel, bool aEncrypt, + bool aAuth, + BluetoothSocketResultHandler* aRes) +{ + int fd; + bt_status_t status; + btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning + + if (NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->listen(type, + NS_ConvertUTF16toUTF8(aServiceName).get(), + aServiceUuid, aChannel, &fd, + (BTSOCK_FLAG_ENCRYPT * aEncrypt) | + (BTSOCK_FLAG_AUTH * aAuth)); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (aRes) { + DispatchBluetoothSocketHALResult( + aRes, &BluetoothSocketResultHandler::Listen, fd, + ConvertDefault(status, STATUS_FAIL)); + } +} + +#define CMSGHDR_CONTAINS_FD(_cmsghdr) \ + ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \ + ((_cmsghdr)->cmsg_type == SCM_RIGHTS) ) + +/* |SocketMessageWatcher| receives Bluedroid's socket setup + * messages on the I/O thread. You need to inherit from this + * class to make use of it. + * + * Bluedroid sends two socket info messages (20 bytes) at + * the beginning of a connection to both peers. + * + * - 1st message: [channel:4] + * - 2nd message: [size:2][bd address:6][channel:4][connection status:4] + * + * On the server side, the second message will contain a + * socket file descriptor for the connection. The client + * uses the original file descriptor. + */ +class SocketMessageWatcher : public MessageLoopForIO::Watcher +{ +public: + static const unsigned char MSG1_SIZE = 4; + static const unsigned char MSG2_SIZE = 16; + + static const unsigned char OFF_CHANNEL1 = 0; + static const unsigned char OFF_SIZE = 4; + static const unsigned char OFF_BDADDRESS = 6; + static const unsigned char OFF_CHANNEL2 = 12; + static const unsigned char OFF_STATUS = 16; + + SocketMessageWatcher(int aFd) + : mFd(aFd) + , mClientFd(-1) + , mLen(0) + { } + + virtual ~SocketMessageWatcher() + { } + + virtual void Proceed(BluetoothStatus aStatus) = 0; + + void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE + { + BluetoothStatus status; + + switch (mLen) { + case 0: + status = RecvMsg1(); + break; + case MSG1_SIZE: + status = RecvMsg2(); + break; + default: + /* message-size error */ + status = STATUS_FAIL; + break; + } + + if (IsComplete() || status != STATUS_SUCCESS) { + mWatcher.StopWatchingFileDescriptor(); + Proceed(status); + } + } + + void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE + { } + + void Watch() + { + MessageLoopForIO::current()->WatchFileDescriptor( + mFd, + true, + MessageLoopForIO::WATCH_READ, + &mWatcher, + this); + } + + bool IsComplete() const + { + return mLen == (MSG1_SIZE + MSG2_SIZE); + } + + int GetFd() const + { + return mFd; + } + + int32_t GetChannel1() const + { + return ReadInt32(OFF_CHANNEL1); + } + + int32_t GetSize() const + { + return ReadInt16(OFF_SIZE); + } + + nsString GetBdAddress() const + { + nsString bdAddress; + ReadBdAddress(OFF_BDADDRESS, bdAddress); + return bdAddress; + } + + int32_t GetChannel2() const + { + return ReadInt32(OFF_CHANNEL2); + } + + int32_t GetConnectionStatus() const + { + return ReadInt32(OFF_STATUS); + } + + int GetClientFd() const + { + return mClientFd; + } + +private: + BluetoothStatus RecvMsg1() + { + struct iovec iv; + memset(&iv, 0, sizeof(iv)); + iv.iov_base = mBuf; + iv.iov_len = MSG1_SIZE; + + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + + ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL)); + if (res < 0) { + return STATUS_FAIL; + } + + mLen += res; + + return STATUS_SUCCESS; + } + + BluetoothStatus RecvMsg2() + { + struct iovec iv; + memset(&iv, 0, sizeof(iv)); + iv.iov_base = mBuf + MSG1_SIZE; + iv.iov_len = MSG2_SIZE; + + struct msghdr msg; + struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100]; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL)); + if (res < 0) { + return STATUS_FAIL; + } + + mLen += res; + + if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) { + return STATUS_FAIL; + } + + struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg); + + // Extract client fd from message header + for (; cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { + if (CMSGHDR_CONTAINS_FD(cmsgptr)) { + // if multiple file descriptors have been sent, we close + // all but the final one. + if (mClientFd != -1) { + TEMP_FAILURE_RETRY(close(mClientFd)); + } + // retrieve sent client fd + mClientFd = *(static_cast(CMSG_DATA(cmsgptr))); + } + } + + return STATUS_SUCCESS; + } + + int16_t ReadInt16(unsigned long aOffset) const + { + /* little-endian buffer */ + return (static_cast(mBuf[aOffset + 1]) << 8) | + static_cast(mBuf[aOffset]); + } + + int32_t ReadInt32(unsigned long aOffset) const + { + /* little-endian buffer */ + return (static_cast(mBuf[aOffset + 3]) << 24) | + (static_cast(mBuf[aOffset + 2]) << 16) | + (static_cast(mBuf[aOffset + 1]) << 8) | + static_cast(mBuf[aOffset]); + } + + void ReadBdAddress(unsigned long aOffset, nsAString& aBdAddress) const + { + const bt_bdaddr_t* bdAddress = + reinterpret_cast(mBuf+aOffset); + + if (NS_FAILED(Convert(*bdAddress, aBdAddress))) { + aBdAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); + } + } + + MessageLoopForIO::FileDescriptorWatcher mWatcher; + int mFd; + int mClientFd; + unsigned char mLen; + uint8_t mBuf[MSG1_SIZE + MSG2_SIZE]; +}; + +/* |SocketMessageWatcherTask| starts a SocketMessageWatcher + * on the I/O task + */ +class SocketMessageWatcherTask MOZ_FINAL : public Task +{ +public: + SocketMessageWatcherTask(SocketMessageWatcher* aWatcher) + : mWatcher(aWatcher) + { + MOZ_ASSERT(mWatcher); + } + + void Run() MOZ_OVERRIDE + { + mWatcher->Watch(); + } + +private: + SocketMessageWatcher* mWatcher; +}; + +/* |DeleteTask| deletes a class instance on the I/O thread + */ +template +class DeleteTask MOZ_FINAL : public Task +{ +public: + DeleteTask(T* aPtr) + : mPtr(aPtr) + { } + + void Run() MOZ_OVERRIDE + { + mPtr = nullptr; + } + +private: + nsAutoPtr mPtr; +}; + +/* |ConnectWatcher| specializes SocketMessageWatcher for + * connect operations by reading the socket messages from + * Bluedroid and forwarding the connected socket to the + * resource handler. + */ +class ConnectWatcher MOZ_FINAL : public SocketMessageWatcher +{ +public: + ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes) + : SocketMessageWatcher(aFd) + , mRes(aRes) + { } + + void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE + { + if (mRes) { + DispatchBluetoothSocketHALResult( + mRes, &BluetoothSocketResultHandler::Connect, GetFd(), + GetBdAddress(), GetConnectionStatus(), aStatus); + } + MessageLoopForIO::current()->PostTask( + FROM_HERE, new DeleteTask(this)); + } + +private: + nsRefPtr mRes; +}; + +void +BluetoothSocketHALInterface::Connect(const nsAString& aBdAddr, + BluetoothSocketType aType, + const uint8_t aUuid[16], + int aChannel, bool aEncrypt, + bool aAuth, + BluetoothSocketResultHandler* aRes) +{ + int fd; + bt_status_t status; + bt_bdaddr_t bdAddr; + btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning + + if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) && + NS_SUCCEEDED(Convert(aType, type))) { + status = mInterface->connect(&bdAddr, type, aUuid, aChannel, &fd, + (BTSOCK_FLAG_ENCRYPT * aEncrypt) | + (BTSOCK_FLAG_AUTH * aAuth)); + } else { + status = BT_STATUS_PARM_INVALID; + } + + if (status == BT_STATUS_SUCCESS) { + /* receive Bluedroid's socket-setup messages */ + Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes)); + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t); + } else if (aRes) { + DispatchBluetoothSocketHALResult( + aRes, &BluetoothSocketResultHandler::Connect, -1, EmptyString(), 0, + ConvertDefault(status, STATUS_FAIL)); + } +} + +/* Specializes SocketMessageWatcher for Accept operations by + * reading the socket messages from Bluedroid and forwarding + * the received client socket to the resource handler. The + * first message is received immediately. When there's a new + * connection, Bluedroid sends the 2nd message with the socket + * info and socket file descriptor. + */ +class AcceptWatcher MOZ_FINAL : public SocketMessageWatcher +{ +public: + AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes) + : SocketMessageWatcher(aFd) + , mRes(aRes) + { + /* not supplying a result handler leaks received file descriptor */ + MOZ_ASSERT(mRes); + } + + void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE + { + if (mRes) { + DispatchBluetoothSocketHALResult( + mRes, &BluetoothSocketResultHandler::Accept, GetClientFd(), + GetBdAddress(), GetConnectionStatus(), aStatus); + } + MessageLoopForIO::current()->PostTask( + FROM_HERE, new DeleteTask(this)); + } + +private: + nsRefPtr mRes; +}; + +void +BluetoothSocketHALInterface::Accept(int aFd, + BluetoothSocketResultHandler* aRes) +{ + /* receive Bluedroid's socket-setup messages and client fd */ + Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes)); + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t); +} + +BluetoothSocketHALInterface::BluetoothSocketHALInterface( + const btsock_interface_t* aInterface) +: mInterface(aInterface) +{ + MOZ_ASSERT(mInterface); +} + +BluetoothSocketHALInterface::~BluetoothSocketHALInterface() +{ } + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.h b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.h new file mode 100644 index 000000000000..0aef3d6929b8 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.h @@ -0,0 +1,49 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothsockethalinterface_h__ +#define mozilla_dom_bluetooth_bluedroid_bluetoothsockethalinterface_h__ + +#include +#include +#include "BluetoothCommon.h" +#include "BluetoothInterface.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothHALInterface; + +class BluetoothSocketHALInterface MOZ_FINAL + : public BluetoothSocketInterface +{ +public: + friend class BluetoothHALInterface; + + void Listen(BluetoothSocketType aType, + const nsAString& aServiceName, + const uint8_t aServiceUuid[16], + int aChannel, bool aEncrypt, bool aAuth, + BluetoothSocketResultHandler* aRes); + + void Connect(const nsAString& aBdAddr, + BluetoothSocketType aType, + const uint8_t aUuid[16], + int aChannel, bool aEncrypt, bool aAuth, + BluetoothSocketResultHandler* aRes); + + void Accept(int aFd, BluetoothSocketResultHandler* aRes); + +protected: + BluetoothSocketHALInterface(const btsock_interface_t* aInterface); + ~BluetoothSocketHALInterface(); + +private: + const btsock_interface_t* mInterface; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/moz.build b/dom/bluetooth/moz.build index 2ce396c2c631..167c54ce67bc 100644 --- a/dom/bluetooth/moz.build +++ b/dom/bluetooth/moz.build @@ -9,6 +9,7 @@ if CONFIG['MOZ_B2G_BT']: 'BluetoothAdapter.cpp', 'BluetoothDevice.cpp', 'BluetoothHidManager.cpp', + 'BluetoothInterface.cpp', 'BluetoothManager.cpp', 'BluetoothProfileController.cpp', 'BluetoothPropertyContainer.cpp', @@ -44,11 +45,16 @@ if CONFIG['MOZ_B2G_BT']: DEFINES['MOZ_B2G_BT_BLUEZ'] = True elif CONFIG['MOZ_B2G_BT_BLUEDROID']: SOURCES += [ + 'bluedroid/BluetoothA2dpHALInterface.cpp', 'bluedroid/BluetoothA2dpManager.cpp', - 'bluedroid/BluetoothInterface.cpp', + 'bluedroid/BluetoothAvrcpHALInterface.cpp', + 'bluedroid/BluetoothHALHelpers.cpp', + 'bluedroid/BluetoothHALInterface.cpp', + 'bluedroid/BluetoothHandsfreeHALInterface.cpp', 'bluedroid/BluetoothOppManager.cpp', 'bluedroid/BluetoothServiceBluedroid.cpp', 'bluedroid/BluetoothSocket.cpp', + 'bluedroid/BluetoothSocketHALInterface.cpp', 'bluedroid/BluetoothUtils.cpp', ] LOCAL_INCLUDES += [