diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.cpp new file mode 100644 index 000000000000..e4424ea02b18 --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.cpp @@ -0,0 +1,285 @@ +/* -*- 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 "BluetoothDaemonA2dpInterface.h" +#include "mozilla/unused.h" + +BEGIN_BLUETOOTH_NAMESPACE + +// +// A2DP module +// + +BluetoothA2dpNotificationHandler* + BluetoothDaemonA2dpModule::sNotificationHandler; + +void +BluetoothDaemonA2dpModule::SetNotificationHandler( + BluetoothA2dpNotificationHandler* aNotificationHandler) +{ + sNotificationHandler = aNotificationHandler; +} + +nsresult +BluetoothDaemonA2dpModule::Send(BluetoothDaemonPDU* aPDU, + BluetoothA2dpResultHandler* aRes) +{ + aRes->AddRef(); // Keep reference for response + return Send(aPDU, static_cast(aRes)); +} + +void +BluetoothDaemonA2dpModule::HandleSvc(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, void* aUserData) +{ + static void (BluetoothDaemonA2dpModule::* const HandleOp[])( + const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = { + INIT_ARRAY_AT(0, &BluetoothDaemonA2dpModule::HandleRsp), + INIT_ARRAY_AT(1, &BluetoothDaemonA2dpModule::HandleNtf), + }; + + MOZ_ASSERT(!NS_IsMainThread()); + + // negate twice to map bit to 0/1 + unsigned int isNtf = !!(aHeader.mOpcode & 0x80); + + (this->*(HandleOp[isNtf]))(aHeader, aPDU, aUserData); +} + +// Commands +// + +nsresult +BluetoothDaemonA2dpModule::ConnectCmd( + const nsAString& aRemoteAddr, BluetoothA2dpResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu(new BluetoothDaemonPDU(SERVICE_ID, + OPCODE_CONNECT, + 6)); // Address + nsresult rv = PackPDU( + PackConversion(aRemoteAddr), *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + unused << pdu.forget(); + return NS_OK; +} + +nsresult +BluetoothDaemonA2dpModule::DisconnectCmd( + const nsAString& aRemoteAddr, BluetoothA2dpResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu(new BluetoothDaemonPDU(SERVICE_ID, + OPCODE_DISCONNECT, + 6)); // Address + nsresult rv = PackPDU( + PackConversion(aRemoteAddr), *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + unused << pdu.forget(); + return NS_OK; +} + +// Responses +// + +void +BluetoothDaemonA2dpModule::ErrorRsp( + const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, BluetoothA2dpResultHandler* aRes) +{ + ErrorRunnable::Dispatch( + aRes, &BluetoothA2dpResultHandler::OnError, UnpackPDUInitOp(aPDU)); +} + +void +BluetoothDaemonA2dpModule::ConnectRsp( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU, + BluetoothA2dpResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, &BluetoothA2dpResultHandler::Connect, UnpackPDUInitOp(aPDU)); +} + +void +BluetoothDaemonA2dpModule::DisconnectRsp( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU, + BluetoothA2dpResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, &BluetoothA2dpResultHandler::Disconnect, UnpackPDUInitOp(aPDU)); +} + +void +BluetoothDaemonA2dpModule::HandleRsp( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU, + void* aUserData) +{ + static void (BluetoothDaemonA2dpModule::* const HandleRsp[])( + const BluetoothDaemonPDUHeader&, + BluetoothDaemonPDU&, + BluetoothA2dpResultHandler*) = { + INIT_ARRAY_AT(OPCODE_ERROR, + &BluetoothDaemonA2dpModule::ErrorRsp), + INIT_ARRAY_AT(OPCODE_CONNECT, + &BluetoothDaemonA2dpModule::ConnectRsp), + INIT_ARRAY_AT(OPCODE_DISCONNECT, + &BluetoothDaemonA2dpModule::DisconnectRsp), + }; + + MOZ_ASSERT(!NS_IsMainThread()); // I/O thread + + if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) || + NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) { + return; + } + + nsRefPtr res = + already_AddRefed( + static_cast(aUserData)); + + if (!res) { + return; // Return early if no result handler has been set for response + } + + (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res); +} + +// Notifications +// + +// Returns the current notification handler to a notification runnable +class BluetoothDaemonA2dpModule::NotificationHandlerWrapper MOZ_FINAL +{ +public: + typedef BluetoothA2dpNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sNotificationHandler; + } +}; + +// Init operator class for ConnectionStateNotification +class BluetoothDaemonA2dpModule::ConnectionStateInitOp MOZ_FINAL + : private PDUInitOp +{ +public: + ConnectionStateInitOp(BluetoothDaemonPDU& aPDU) + : PDUInitOp(aPDU) + { } + + nsresult + operator () (BluetoothA2dpConnectionState& aArg1, nsString& aArg2) const + { + BluetoothDaemonPDU& pdu = GetPDU(); + + /* Read state */ + nsresult rv = UnpackPDU(pdu, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + + /* Read address */ + rv = UnpackPDU( + pdu, UnpackConversion(aArg2)); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } +}; + +void +BluetoothDaemonA2dpModule::ConnectionStateNtf( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU) +{ + ConnectionStateNotification::Dispatch( + &BluetoothA2dpNotificationHandler::ConnectionStateNotification, + ConnectionStateInitOp(aPDU)); +} + +// Init operator class for AudioStateNotification +class BluetoothDaemonA2dpModule::AudioStateInitOp MOZ_FINAL + : private PDUInitOp +{ +public: + AudioStateInitOp(BluetoothDaemonPDU& aPDU) + : PDUInitOp(aPDU) + { } + + nsresult + operator () (BluetoothA2dpAudioState& aArg1, + nsString& aArg2) const + { + BluetoothDaemonPDU& pdu = GetPDU(); + + /* Read state */ + nsresult rv = UnpackPDU(pdu, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + + /* Read address */ + rv = UnpackPDU( + pdu, UnpackConversion(aArg2)); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } +}; + +void +BluetoothDaemonA2dpModule::AudioStateNtf( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU) +{ + AudioStateNotification::Dispatch( + &BluetoothA2dpNotificationHandler::AudioStateNotification, + AudioStateInitOp(aPDU)); +} + +void +BluetoothDaemonA2dpModule::HandleNtf( + const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU, + void* aUserData) +{ + static void (BluetoothDaemonA2dpModule::* const HandleNtf[])( + const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = { + INIT_ARRAY_AT(0, &BluetoothDaemonA2dpModule::ConnectionStateNtf), + INIT_ARRAY_AT(1, &BluetoothDaemonA2dpModule::AudioStateNtf), + }; + + MOZ_ASSERT(!NS_IsMainThread()); + + uint8_t index = aHeader.mOpcode - 0x81; + + if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) || + NS_WARN_IF(!HandleNtf[index])) { + return; + } + + (this->*(HandleNtf[index]))(aHeader, aPDU); +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.h b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.h new file mode 100644 index 000000000000..f27337a5c0bf --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonA2dpInterface.h @@ -0,0 +1,123 @@ +/* -*- 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_bluetoothdaemona2dpinterface_h +#define mozilla_dom_bluetooth_bluetoothdaemona2dpinterface_h + +#include "BluetoothDaemonHelpers.h" +#include "BluetoothInterface.h" +#include "BluetoothInterfaceHelpers.h" + +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothSetupResultHandler; + +class BluetoothDaemonA2dpModule +{ +public: + enum { + SERVICE_ID = 0x06 + }; + + enum { + OPCODE_ERROR = 0x00, + OPCODE_CONNECT = 0x01, + OPCODE_DISCONNECT = 0x02 + }; + + virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0; + + virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode, + BluetoothSetupResultHandler* aRes) = 0; + + virtual nsresult UnregisterModule(uint8_t aId, + BluetoothSetupResultHandler* aRes) = 0; + + void SetNotificationHandler( + BluetoothA2dpNotificationHandler* aNotificationHandler); + + // + // Commands + // + + nsresult ConnectCmd(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes); + nsresult DisconnectCmd(const nsAString& aBdAddr, + BluetoothA2dpResultHandler* aRes); + +protected: + nsresult Send(BluetoothDaemonPDU* aPDU, + BluetoothA2dpResultHandler* aRes); + + void HandleSvc(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, void* aUserData); + + // + // Responses + // + + typedef BluetoothResultRunnable0 + ResultRunnable; + + typedef BluetoothResultRunnable1 + ErrorRunnable; + + void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothA2dpResultHandler* aRes); + + void ConnectRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothA2dpResultHandler* aRes); + + void DisconnectRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothA2dpResultHandler* aRes); + + void HandleRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + void* aUserData); + + // + // Notifications + // + + class NotificationHandlerWrapper; + + typedef BluetoothNotificationRunnable2 + ConnectionStateNotification; + + typedef BluetoothNotificationRunnable2 + AudioStateNotification; + + class AudioStateInitOp; + class ConnectionStateInitOp; + + void ConnectionStateNtf(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU); + + void AudioStateNtf(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU); + + void HandleNtf(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + void* aUserData); + + static BluetoothA2dpNotificationHandler* sNotificationHandler; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth2/moz.build b/dom/bluetooth2/moz.build index f97a1aa96501..dd6894d320f0 100644 --- a/dom/bluetooth2/moz.build +++ b/dom/bluetooth2/moz.build @@ -51,6 +51,7 @@ if CONFIG['MOZ_B2G_BT']: 'bluedroid/BluetoothA2dpHALInterface.cpp', 'bluedroid/BluetoothA2dpManager.cpp', 'bluedroid/BluetoothAvrcpHALInterface.cpp', + 'bluedroid/BluetoothDaemonA2dpInterface.cpp', 'bluedroid/BluetoothDaemonHandsfreeInterface.cpp', 'bluedroid/BluetoothDaemonHelpers.cpp', 'bluedroid/BluetoothDaemonInterface.cpp',