Bug 830213 - Patch 2: Implementation of ConnectSco/DisconnectSco/IsScoConnected in BluetoothHfpManager, r=echou, sr=mrbkap

This commit is contained in:
Gina Yeh 2013-05-10 19:01:10 +08:00
parent 4fada6d52b
commit 0d6b87eddd
2 changed files with 187 additions and 12 deletions

View File

@ -31,6 +31,7 @@
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
#define MOBILE_CONNECTION_ICCINFO_CHANGED "mobile-connection-iccinfo-changed"
#define MOBILE_CONNECTION_VOICE_CHANGED "mobile-connection-voice-changed"
#define BLUETOOTH_SCO_STATUS_CHANGED "bluetooth-sco-status-changed"
/**
* These constants are used in result code such as +CLIP and +CCWA. The value
@ -125,7 +126,7 @@ class mozilla::dom::bluetooth::Call {
public:
Call(uint16_t aState = nsITelephonyProvider::CALL_STATE_DISCONNECTED,
bool aDirection = false,
const nsAString& aNumber = NS_LITERAL_STRING(""),
const nsAString& aNumber = EmptyString(),
int aType = TOA_UNKNOWN)
: mState(aState), mDirection(aDirection), mNumber(aNumber), mType(aType)
{
@ -439,6 +440,12 @@ BluetoothHfpManager::Init()
Listen();
mScoSocket = new BluetoothSocket(this,
BluetoothSocketType::SCO,
true,
false);
mScoSocketStatus = mScoSocket->GetConnectionStatus();
ListenSco();
return true;
}
@ -497,7 +504,7 @@ BluetoothHfpManager::NotifySettings()
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("address");
v = mDevicePath;
v = mDeviceAddress;
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
@ -524,6 +531,22 @@ BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
}
}
void
BluetoothHfpManager::NotifyAudioManager(const nsAString& aAddress)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs =
do_GetService("@mozilla.org/observer-service;1");
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->NotifyObservers(nullptr,
BLUETOOTH_SCO_STATUS_CHANGED,
aAddress.BeginReading()))) {
NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!");
}
}
nsresult
BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
{
@ -682,6 +705,7 @@ BluetoothHfpManager::HandleShutdown()
MOZ_ASSERT(NS_IsMainThread());
gInShutdown = true;
Disconnect();
DisconnectSco();
gBluetoothHfpManager = nullptr;
return NS_OK;
}
@ -1030,7 +1054,7 @@ BluetoothHfpManager::Listen()
MOZ_ASSERT(NS_IsMainThread());
if (gInShutdown) {
MOZ_ASSERT(false, "Listen called while in shutdown!");
NS_WARNING("Listen called while in shutdown!");
return false;
}
@ -1383,6 +1407,12 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
{
MOZ_ASSERT(aSocket);
// Success to create a SCO socket
if (aSocket == mScoSocket) {
OnScoConnectSuccess();
return;
}
/**
* If the created connection is an inbound connection, close another server
* socket because currently only one SLC is allowed. After that, we need to
@ -1415,27 +1445,35 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
nsString errorStr;
DispatchBluetoothReply(mRunnable, v, errorStr);
mRunnable.forget();
mRunnable = nullptr;
}
mFirstCKPD = true;
// Cache device path for NotifySettings() since we can't get socket address
// when a headset disconnect with us
mSocket->GetAddress(mDevicePath);
mSocket->GetAddress(mDeviceAddress);
NotifySettings();
ListenSco();
}
void
BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket)
{
// Failed to create a SCO socket
if (aSocket == mScoSocket) {
OnScoConnectError();
return;
}
// For active connection request, we need to reply the DOMRequest
if (mRunnable) {
BluetoothValue v;
DispatchBluetoothReply(mRunnable, v,
NS_LITERAL_STRING("OnConnectError:no runnable"));
mRunnable.forget();
NS_NAMED_LITERAL_STRING(replyError,
"Failed to connect with a bluetooth headset!");
DispatchBluetoothReply(mRunnable, BluetoothValue(), replyError);
mRunnable = nullptr;
}
mSocket = nullptr;
@ -1451,13 +1489,19 @@ BluetoothHfpManager::OnDisconnect(BluetoothSocket* aSocket)
{
MOZ_ASSERT(aSocket);
if (aSocket == mScoSocket) {
// SCO socket is closed
OnScoDisconnect();
return;
}
if (aSocket != mSocket) {
// Do nothing when a listening server socket is closed.
return;
}
mSocket = nullptr;
CloseScoSocket();
DisconnectSco();
Listen();
NotifySettings();
@ -1491,6 +1535,43 @@ BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
}
}
void
BluetoothHfpManager::OnScoConnectSuccess()
{
// For active connection request, we need to reply the DOMRequest
if (mScoRunnable) {
DispatchBluetoothReply(mScoRunnable,
BluetoothValue(true), EmptyString());
mScoRunnable = nullptr;
}
NotifyAudioManager(mDeviceAddress);
mScoSocketStatus = mScoSocket->GetConnectionStatus();
}
void
BluetoothHfpManager::OnScoConnectError()
{
if (mScoRunnable) {
NS_NAMED_LITERAL_STRING(replyError, "Failed to create SCO socket!");
DispatchBluetoothReply(mScoRunnable, BluetoothValue(), replyError);
mScoRunnable = nullptr;
}
ListenSco();
}
void
BluetoothHfpManager::OnScoDisconnect()
{
if (mScoSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
ListenSco();
NotifyAudioManager(EmptyString());
}
}
bool
BluetoothHfpManager::IsConnected()
{
@ -1507,3 +1588,86 @@ BluetoothHfpManager::GetAddress(nsAString& aDeviceAddress)
{
return mSocket->GetAddress(aDeviceAddress);
}
bool
BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
if (gInShutdown) {
NS_WARNING("ConnecteSco called while in shutdown!");
return false;
}
if (!IsConnected()) {
NS_WARNING("BluetoothHfpManager is not connected");
return false;
}
SocketConnectionStatus status = mScoSocket->GetConnectionStatus();
if (status == SocketConnectionStatus::SOCKET_CONNECTED ||
status == SocketConnectionStatus::SOCKET_CONNECTING ||
(mScoRunnable && (mScoRunnable != aRunnable))) {
NS_WARNING("SCO connection exists or is being established");
return false;
}
mScoSocket->Disconnect();
mScoRunnable = aRunnable;
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, false);
nsresult rv = bs->GetScoSocket(mDeviceAddress, true, false, mScoSocket);
return NS_SUCCEEDED(rv);
}
bool
BluetoothHfpManager::DisconnectSco()
{
if (!mScoSocket) {
NS_WARNING("BluetoothHfpManager is not connected");
return false;
}
mScoSocket->Disconnect();
return true;
}
bool
BluetoothHfpManager::ListenSco()
{
MOZ_ASSERT(NS_IsMainThread());
if (gInShutdown) {
NS_WARNING("ListenSco called while in shutdown!");
return false;
}
if (mScoSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_LISTENING) {
NS_WARNING("SCO socket has been already listening");
return false;
}
mScoSocket->Disconnect();
if (!mScoSocket->Listen(-1)) {
NS_WARNING("Can't listen on SCO socket!");
return false;
}
mScoSocketStatus = mScoSocket->GetConnectionStatus();
return true;
}
bool
BluetoothHfpManager::IsScoConnected()
{
if (mScoSocket) {
return mScoSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_CONNECTED;
}
return false;
}

View File

@ -73,6 +73,9 @@ public:
BluetoothReplyRunnable* aRunnable);
void Disconnect();
bool Listen();
bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr);
bool DisconnectSco();
bool ListenSco();
/**
* @param aSend A boolean indicates whether we need to notify headset or not
@ -82,6 +85,7 @@ public:
bool aSend);
bool IsConnected();
bool IsScoConnected();
void GetAddress(nsAString& aDeviceAddress);
private:
@ -107,10 +111,14 @@ private:
void NotifyDialer(const nsAString& aCommand);
void NotifySettings();
void NotifyAudioManager(const nsAString& aAddress);
bool SendCommand(const char* aCommand, uint8_t aValue = 0);
bool SendLine(const char* aMessage);
void UpdateCIND(uint8_t aType, uint8_t aValue, bool aSend);
void OnScoConnectSuccess();
void OnScoConnectError();
void OnScoDisconnect();
int mCurrentVgs;
int mCurrentVgm;
@ -123,13 +131,14 @@ private:
int mNetworkSelectionMode;
bool mReceiveVgsFlag;
bool mBLDNProcessed;
nsString mDevicePath;
nsString mDeviceAddress;
nsString mMsisdn;
nsString mOperatorName;
nsTArray<Call> mCurrentCallArray;
nsAutoPtr<BluetoothTelephonyListener> mListener;
nsRefPtr<BluetoothReplyRunnable> mRunnable;
nsRefPtr<BluetoothReplyRunnable> mScoRunnable;
// If a connection has been established, mSocket will be the socket
// communicating with the remote socket. We maintain the invariant that if
@ -142,6 +151,8 @@ private:
// is called.
nsRefPtr<BluetoothSocket> mHandsfreeSocket;
nsRefPtr<BluetoothSocket> mHeadsetSocket;
nsRefPtr<BluetoothSocket> mScoSocket;
SocketConnectionStatus mScoSocketStatus;
};
END_BLUETOOTH_NAMESPACE