Bug 860166 - Use two server sockets to listen to both HFP and HSP services, r=gyeh, r=mrbkap

This commit is contained in:
Eric Chou 2013-04-19 17:08:00 +08:00
parent 61e8e696a1
commit a7bc2c708b
3 changed files with 113 additions and 48 deletions

View File

@ -393,12 +393,6 @@ BluetoothHfpManager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
mSocket = new BluetoothSocket(this,
BluetoothSocketType::RFCOMM,
true,
true);
mPrevSocketStatus = mSocket->GetConnectionStatus();
sHfpObserver = new BluetoothHfpManagerObserver();
if (!sHfpObserver->Init()) {
NS_WARNING("Cannot set up Hfp Observers!");
@ -422,6 +416,8 @@ BluetoothHfpManager::Init()
rv = settingsLock->Get(AUDIO_VOLUME_BT_SCO, callback);
NS_ENSURE_SUCCESS(rv, false);
Listen();
return true;
}
@ -476,8 +472,7 @@ BluetoothHfpManager::NotifySettings()
type.AssignLiteral("bluetooth-hfp-status-changed");
name.AssignLiteral("connected");
v = (mSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_CONNECTED);
v = IsConnected();
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("address");
@ -573,7 +568,7 @@ BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
}
// Only send volume back when there's a connected headset
if (mSocket->GetConnectionStatus() == SocketConnectionStatus::SOCKET_CONNECTED) {
if (IsConnected()) {
SendCommand("+VGS: ", mCurrentVgs);
}
@ -945,15 +940,21 @@ BluetoothHfpManager::Connect(const nsAString& aDevicePath,
return false;
}
SocketConnectionStatus s = mSocket->GetConnectionStatus();
if (s == SocketConnectionStatus::SOCKET_CONNECTED ||
s == SocketConnectionStatus::SOCKET_CONNECTING) {
if (mSocket) {
NS_WARNING("BluetoothHfpManager has been already connected");
return false;
}
mSocket->Disconnect();
// Stop listening because currently we only support one connection at a time.
if (mHandsfreeSocket) {
mHandsfreeSocket->Disconnect();
mHandsfreeSocket = nullptr;
}
if (mHeadsetSocket) {
mHeadsetSocket->Disconnect();
mHeadsetSocket = nullptr;
}
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, false);
@ -966,6 +967,8 @@ BluetoothHfpManager::Connect(const nsAString& aDevicePath,
}
mRunnable = aRunnable;
mSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
nsresult rv = bs->GetSocketViaService(aDevicePath,
uuid,
@ -988,32 +991,54 @@ BluetoothHfpManager::Listen()
return false;
}
if (mSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_LISTENING) {
NS_WARNING("BluetoothHfpManager has been already listening");
return true;
}
mSocket->Disconnect();
if (!mSocket->Listen(BluetoothReservedChannels::CHANNEL_HANDSFREE_AG)) {
NS_WARNING("[HFP] Can't listen on socket!");
if (mSocket) {
NS_WARNING("mSocket exists. Failed to listen.");
return false;
}
mPrevSocketStatus = mSocket->GetConnectionStatus();
if (!mHandsfreeSocket) {
mHandsfreeSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
if (!mHandsfreeSocket->Listen(
BluetoothReservedChannels::CHANNEL_HANDSFREE_AG)) {
NS_WARNING("[HFP] Can't listen on RFCOMM socket!");
mHandsfreeSocket = nullptr;
return false;
}
}
if (!mHeadsetSocket) {
mHeadsetSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
if (!mHeadsetSocket->Listen(
BluetoothReservedChannels::CHANNEL_HEADSET_AG)) {
NS_WARNING("[HSP] Can't listen on RFCOMM socket!");
mHandsfreeSocket->Disconnect();
mHandsfreeSocket = nullptr;
mHeadsetSocket = nullptr;
return false;
}
}
return true;
}
void
BluetoothHfpManager::Disconnect()
{
mSocket->Disconnect();
if (mSocket) {
mSocket->Disconnect();
mSocket = nullptr;
}
}
bool
BluetoothHfpManager::SendLine(const char* aMessage)
{
MOZ_ASSERT(mSocket);
nsAutoCString msg;
msg.AppendLiteral(kHfpCrlf);
@ -1026,7 +1051,8 @@ BluetoothHfpManager::SendLine(const char* aMessage)
bool
BluetoothHfpManager::SendCommand(const char* aCommand, uint8_t aValue)
{
if (mPrevSocketStatus != SocketConnectionStatus::SOCKET_CONNECTED) {
if (!IsConnected()) {
NS_WARNING("Trying to SendCommand() without a SLC");
return false;
}
@ -1141,8 +1167,8 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
const nsAString& aNumber,
bool aSend)
{
if (mSocket->GetConnectionStatus() !=
SocketConnectionStatus::SOCKET_CONNECTED) {
if (!IsConnected()) {
// Normal case. No need to print out warnings.
return;
}
@ -1192,8 +1218,10 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
number.AssignLiteral("");
}
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new SendRingIndicatorTask(number, mCurrentCallArray[aCallIndex].mType),
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
new SendRingIndicatorTask(number,
mCurrentCallArray[aCallIndex].mType),
sRingInterval);
}
break;
@ -1266,7 +1294,8 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
break;
case nsITelephonyProvider::CALL_STATE_CONNECTED:
// No call is ongoing
if (sCINDItems[CINDType::CALLHELD].value == CallHeldState::NO_CALLHELD) {
if (sCINDItems[CINDType::CALLHELD].value ==
CallHeldState::NO_CALLHELD) {
UpdateCIND(CINDType::CALL, CallState::NO_CALL, aSend);
}
break;
@ -1307,7 +1336,28 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
void
BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
{
MOZ_ASSERT(aSocket == mSocket);
MOZ_ASSERT(aSocket);
/**
* If the created connection is an inbound connection, close another server
* socket because currently only one SLC is allowed. After that, we need to
* make sure that both server socket would be nulled out. As for outbound
* connections, we do nothing since sockets have been already handled in
* function Connect().
*/
if (aSocket == mHandsfreeSocket) {
MOZ_ASSERT(!mSocket);
mHandsfreeSocket.swap(mSocket);
mHeadsetSocket->Disconnect();
mHeadsetSocket = nullptr;
} else if (aSocket == mHeadsetSocket) {
MOZ_ASSERT(!mSocket);
mHeadsetSocket.swap(mSocket);
mHandsfreeSocket->Disconnect();
mHandsfreeSocket = nullptr;
}
nsCOMPtr<nsITelephonyProvider> provider =
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
@ -1326,7 +1376,6 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
// Cache device path for NotifySettings() since we can't get socket address
// when a headset disconnect with us
mSocket->GetAddress(mDevicePath);
mPrevSocketStatus = mSocket->GetConnectionStatus();
NotifySettings();
}
@ -1334,8 +1383,6 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
void
BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket)
{
MOZ_ASSERT(aSocket == mSocket);
// For active connection request, we need to reply the DOMRequest
if (mRunnable) {
BluetoothValue v;
@ -1346,6 +1393,10 @@ BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket)
mRunnable.forget();
}
mSocket = nullptr;
mHandsfreeSocket = nullptr;
mHeadsetSocket = nullptr;
// If connecting for some reason didn't work, restart listening
Listen();
}
@ -1353,24 +1404,28 @@ BluetoothHfpManager::OnConnectError(BluetoothSocket* aSocket)
void
BluetoothHfpManager::OnDisconnect(BluetoothSocket* aSocket)
{
MOZ_ASSERT(aSocket == mSocket);
MOZ_ASSERT(aSocket);
// When we close a connected socket, then restart listening again and
// notify Settings app.
if (mPrevSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
Listen();
NotifySettings();
} else if (mPrevSocketStatus == SocketConnectionStatus::SOCKET_CONNECTING) {
NS_WARNING("BluetoothHfpManager got unexpected socket status!");
if (aSocket != mSocket) {
// Do nothing when a listening server socket is closed.
return;
}
mSocket = nullptr;
CloseScoSocket();
Listen();
NotifySettings();
Reset();
}
bool
BluetoothHfpManager::IsConnected()
{
return mSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_CONNECTED;
if (mSocket) {
return mSocket->GetConnectionStatus() ==
SocketConnectionStatus::SOCKET_CONNECTED;
}
return false;
}

View File

@ -114,12 +114,22 @@ private:
nsString mDevicePath;
nsString mMsisdn;
nsString mOperatorName;
SocketConnectionStatus mPrevSocketStatus;
nsTArray<Call> mCurrentCallArray;
nsAutoPtr<BluetoothTelephonyListener> mListener;
nsRefPtr<BluetoothReplyRunnable> mRunnable;
// If a connection has been established, mSocket will be the socket
// communicating with the remote socket. We maintain the invariant that if
// mSocket is non-null, mHandsfreeSocket and mHeadsetSocket must be null (and
// vice versa).
nsRefPtr<BluetoothSocket> mSocket;
// Server sockets. Once an inbound connection is established, it will hand
// over the ownership to mSocket, and get a new server socket while Listen()
// is called.
nsRefPtr<BluetoothSocket> mHandsfreeSocket;
nsRefPtr<BluetoothSocket> mHeadsetSocket;
};
END_BLUETOOTH_NAMESPACE

View File

@ -105,7 +105,7 @@ BluetoothScoManagerObserver::Observe(nsISupports* aSubject,
const PRUnichar* aData)
{
MOZ_ASSERT(gBluetoothScoManager);
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
return gBluetoothScoManager->HandleShutdown();
}