Bug 935578 - Patch 2: BluetoothA2dpManager bluedroid version, r=echou

This commit is contained in:
Shawn Huang 2013-11-20 16:19:09 +08:00
parent 757566e5b0
commit 76c13d78b7
4 changed files with 167 additions and 55 deletions

View File

@ -8,17 +8,21 @@
#include "BluetoothA2dpManager.h"
#include <hardware/bluetooth.h>
#include <hardware/bt_av.h>
#include "BluetoothCommon.h"
#include "BluetoothService.h"
#include "BluetoothServiceBluedroid.h"
#include "BluetoothSocket.h"
#include "BluetoothUtils.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsIObserverService.h"
#include "MainThreadUtils.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
using namespace mozilla;
USING_BLUETOOTH_NAMESPACE
@ -26,8 +30,33 @@ USING_BLUETOOTH_NAMESPACE
namespace {
StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
bool sInShutdown = false;
static const btav_interface_t* sBtA2dpInterface;
} // anonymous namespace
class SinkPropertyChangedHandler : public nsRunnable
{
public:
SinkPropertyChangedHandler(const BluetoothSignal& aSignal)
: mSignal(aSignal)
{
}
NS_IMETHOD
Run()
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
a2dp->HandleSinkPropertyChanged(mSignal);
return NS_OK;
}
private:
BluetoothSignal mSignal;
};
NS_IMETHODIMP
BluetoothA2dpManager::Observe(nsISupports* aSubject,
const char* aTopic,
@ -50,18 +79,100 @@ BluetoothA2dpManager::BluetoothA2dpManager()
ResetAvrcp();
}
static void
AvStatusToSinkString(btav_connection_state_t aStatus, nsAString& aState)
{
nsAutoString state;
if (aStatus == BTAV_CONNECTION_STATE_DISCONNECTED) {
aState = NS_LITERAL_STRING("disconnected");
} else if (aStatus == BTAV_CONNECTION_STATE_CONNECTING) {
aState = NS_LITERAL_STRING("connecting");
} else if (aStatus == BTAV_CONNECTION_STATE_CONNECTED) {
aState = NS_LITERAL_STRING("connected");
} else if (aStatus == BTAV_CONNECTION_STATE_DISCONNECTING) {
aState = NS_LITERAL_STRING("disconnecting");
} else {
BT_WARNING("Unknown sink state");
}
}
static void
A2dpConnectionStateCallback(btav_connection_state_t aState,
bt_bdaddr_t* aBdAddress)
{
MOZ_ASSERT(!NS_IsMainThread());
nsString remoteDeviceBdAddress;
BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
nsString a2dpState;
AvStatusToSinkString(aState, a2dpState);
InfallibleTArray<BluetoothNamedValue> props;
props.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
remoteDeviceBdAddress, props);
NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
}
static void
A2dpAudioStateCallback(btav_audio_state_t aState,
bt_bdaddr_t* aBdAddress)
{
MOZ_ASSERT(!NS_IsMainThread());
nsString remoteDeviceBdAddress;
BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
nsString a2dpState;
if (aState == BTAV_AUDIO_STATE_STARTED) {
a2dpState = NS_LITERAL_STRING("playing");
} else if (aState == BTAV_AUDIO_STATE_STOPPED) {
// for avdtp state stop stream
a2dpState = NS_LITERAL_STRING("connected");
} else if (aState == BTAV_AUDIO_STATE_REMOTE_SUSPEND) {
// for avdtp state suspend stream from remote side
a2dpState = NS_LITERAL_STRING("connected");
}
InfallibleTArray<BluetoothNamedValue> props;
props.AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("State"), a2dpState));
BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
remoteDeviceBdAddress, props);
NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
}
static btav_callbacks_t sBtA2dpCallbacks = {
sizeof(sBtA2dpCallbacks),
A2dpConnectionStateCallback,
A2dpAudioStateCallback
};
/*
* This function will be only called when Bluetooth is turning on.
* It is important to register a2dp callbacks before enable() gets called.
* It is required to register a2dp callbacks before a2dp media task
* starts up.
*/
bool
BluetoothA2dpManager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
const bt_interface_t* btInf = GetBluetoothInterface();
NS_ENSURE_TRUE(btInf, false);
sBtA2dpInterface = (btav_interface_t *)btInf->
get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID);
NS_ENSURE_TRUE(sBtA2dpInterface, false);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
BT_WARNING("Failed to add shutdown observer!");
int ret = sBtA2dpInterface->init(&sBtA2dpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("failed to init a2dp module");
return false;
}
return true;
}
@ -93,6 +204,10 @@ BluetoothA2dpManager::ResetAvrcp()
mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
}
/*
* Static functions
*/
static BluetoothA2dpManager::SinkState
StatusStringToSinkState(const nsAString& aStatus)
{
@ -165,11 +280,11 @@ BluetoothA2dpManager::Connect(const nsAString& aDeviceAddress,
mDeviceAddress = aDeviceAddress;
mController = aController;
if (NS_FAILED(bs->SendSinkMessage(aDeviceAddress,
NS_LITERAL_STRING("Connect")))) {
aController->OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return;
}
bt_bdaddr_t remoteAddress;
StringToBdAddressType(aDeviceAddress, &remoteAddress);
NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
sBtA2dpInterface->connect(&remoteAddress));
}
void
@ -195,10 +310,11 @@ BluetoothA2dpManager::Disconnect(BluetoothProfileController* aController)
mController = aController;
if (NS_FAILED(bs->SendSinkMessage(mDeviceAddress,
NS_LITERAL_STRING("Disconnect")))) {
aController->OnDisconnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
return;
bt_bdaddr_t remoteAddress;
StringToBdAddressType(mDeviceAddress, &remoteAddress);
if (sBtA2dpInterface) {
NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
sBtA2dpInterface->disconnect(&remoteAddress));
}
}
@ -254,7 +370,8 @@ void
BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue);
MOZ_ASSERT(aSignal.value().type() ==
BluetoothValue::TArrayOfBluetoothNamedValue);
const nsString& address = aSignal.path();
const InfallibleTArray<BluetoothNamedValue>& arr =
@ -293,13 +410,12 @@ BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
break;
case SinkState::SINK_CONNECTED:
// case 5: Audio stream suspended
if (prevState == SinkState::SINK_PLAYING) {
if (prevState == SinkState::SINK_PLAYING ||
prevState == SinkState::SINK_CONNECTED) {
break;
}
// case 3: Successfully connected
MOZ_ASSERT(prevState == SinkState::SINK_CONNECTING);
// case 3: Successfully connected
mA2dpConnected = true;
mDeviceAddress = address;
NotifyConnectionStatusChanged();

View File

@ -60,9 +60,9 @@ public:
void GetTitle(nsAString& aTitle);
private:
class SinkPropertyChangedHandler;
BluetoothA2dpManager();
bool Init();
void HandleShutdown();
void NotifyConnectionStatusChanged();

View File

@ -20,6 +20,8 @@
#include <hardware/hardware.h>
#include "bluedroid/BluetoothA2dpManager.h"
#include "bluedroid/BluetoothHfpManager.h"
#include "BluetoothProfileController.h"
#include "BluetoothReplyRunnable.h"
#include "BluetoothUtils.h"
@ -172,7 +174,7 @@ IsReady()
const bt_interface_t*
GetBluetoothInterface()
{
return (IsReady()) ? sBtInterface : nullptr;
return sBtInterface;
}
void
@ -187,7 +189,7 @@ StringToBdAddressType(const nsAString& aBdAddress,
}
}
static void
void
BdAddressTypeToString(bt_bdaddr_t* aBdAddressType, nsAString& aRetBdAddress)
{
uint8_t* addr = aBdAddressType->address;
@ -635,7 +637,12 @@ EnsureBluetoothHalLoad()
module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
sBtDevice = (bluetooth_device_t *)device;
sBtInterface = sBtDevice->get_bluetooth_interface();
BT_LOGD("Bluetooth HAL loaded");
int ret = sBtInterface->init(&sBluetoothCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Error while setting the callbacks %s", __FUNCTION__);
sBtInterface = nullptr;
}
return true;
}
@ -645,25 +652,8 @@ StartStopGonkBluetooth(bool aShouldEnable)
{
MOZ_ASSERT(!NS_IsMainThread());
static bool sIsBtInterfaceInitialized = false;
if (!EnsureBluetoothHalLoad()) {
BT_LOGR("Failed to load bluedroid library.\n");
return NS_ERROR_FAILURE;
}
if (sIsBtEnabled == aShouldEnable)
return NS_OK;
if (sBtInterface && !sIsBtInterfaceInitialized) {
int ret = sBtInterface->init(&sBluetoothCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Error while setting the callbacks %s", __FUNCTION__);
sBtInterface = nullptr;
return NS_ERROR_FAILURE;
}
sIsBtInterfaceInitialized = true;
}
NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(sIsBtEnabled != aShouldEnable, NS_OK);
int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable();
NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE);
@ -709,6 +699,16 @@ ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
BluetoothServiceBluedroid::BluetoothServiceBluedroid()
{
sToggleBtMonitor = new Monitor("BluetoothService.sToggleBtMonitor");
if (!EnsureBluetoothHalLoad()) {
BT_LOGR("Error! Failed to load bluedroid library.\n");
return;
}
// Register all the bluedroid callbacks before enable() get called
// It is required to register a2dp callbacks before a2dp media task starts up.
BluetoothHfpManager::Get();
BluetoothA2dpManager::Get();
}
BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
@ -747,11 +747,6 @@ BluetoothServiceBluedroid::IsEnabledInternal()
{
MOZ_ASSERT(!NS_IsMainThread());
if (!EnsureBluetoothHalLoad()) {
NS_ERROR("Failed to load bluedroid library.\n");
return false;
}
return sIsBtEnabled;
}

View File

@ -20,14 +20,18 @@ GetBluetoothInterface();
void
StringToBdAddressType(const nsAString& aBdAddress,
bt_bdaddr_t *aRetBdAddressType);
class DBusMessage;
void
BdAddressTypeToString(bt_bdaddr_t* aBdAddressType,
nsAString& aRetBdAddress);
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothServiceBluedroid : public BluetoothService
{
public:
BluetoothServiceBluedroid();
~BluetoothServiceBluedroid();
virtual nsresult StartInternal();
virtual nsresult StopInternal();
virtual bool IsEnabledInternal();
@ -192,9 +196,6 @@ public:
virtual nsresult
SendInputMessage(const nsAString& aDeviceAddresses,
const nsAString& aMessage) MOZ_OVERRIDE;
BluetoothServiceBluedroid();
~BluetoothServiceBluedroid();
};
END_BLUETOOTH_NAMESPACE