OSDN Git Service

A2DP: Cleanup UIPC when no active device
authorHansong Zhang <hsz@google.com>
Fri, 2 Feb 2018 02:02:53 +0000 (18:02 -0800)
committerPavlin Radoslavov <pavlin@google.com>
Wed, 14 Feb 2018 05:11:46 +0000 (05:11 +0000)
* Modified UIPC to support multiple users
* A2DP now calls UIPC_Close() when it has no active device, and calls
  UIPC_Init() when it has an active device

Bug: 72701090
Test: Carkits with A2DP
Change-Id: Ic1b4b1be2aa01c9896883e3cb2a668d7a43316f9

btif/src/btif_a2dp_control.cc
btif/src/btif_a2dp_source.cc
btif/src/btif_av.cc
udrv/include/uipc.h
udrv/ulinux/uipc.cc

index 51a89e9..b9bd4d9 100644 (file)
@@ -44,13 +44,13 @@ static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
 static tA2DP_CTRL_CMD a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
 
 void btif_a2dp_control_init(void) {
-  UIPC_Init(NULL);
+  UIPC_Init(NULL, UIPC_USER_A2DP);
   UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
 }
 
 void btif_a2dp_control_cleanup(void) {
   /* This calls blocks until UIPC is fully closed */
-  UIPC_Close(UIPC_CH_ID_ALL);
+  UIPC_Close(UIPC_CH_ID_ALL, UIPC_USER_A2DP);
 }
 
 static void btif_a2dp_recv_ctrl_data(void) {
@@ -64,7 +64,7 @@ static void btif_a2dp_recv_ctrl_data(void) {
   /* detach on ctrl channel means audioflinger process was terminated */
   if (n == 0) {
     APPL_TRACE_WARNING("%s: CTRL CH DETACHED", __func__);
-    UIPC_Close(UIPC_CH_ID_AV_CTRL);
+    UIPC_Close(UIPC_CH_ID_AV_CTRL, UIPC_USER_A2DP);
     return;
   }
 
index 00ac616..b560596 100644 (file)
@@ -655,7 +655,7 @@ static void btif_a2dp_source_audio_tx_stop_event(void) {
   alarm_free(btif_a2dp_source_cb.media_alarm);
   btif_a2dp_source_cb.media_alarm = nullptr;
 
-  UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+  UIPC_Close(UIPC_CH_ID_AV_AUDIO, UIPC_USER_A2DP);
 
   /*
    * Try to send acknowldegment once the media stream is
index 03424b5..2c5a3d8 100644 (file)
@@ -363,11 +363,37 @@ class BtifAvSource {
   const RawAddress& ActivePeer() const { return active_peer_; }
   bool SetActivePeer(const RawAddress& peer_address) {
     if (active_peer_ == peer_address) return true;  // Nothing has changed
-    if (bta_av_co_set_active_peer(peer_address)) {
+    if (peer_address.IsEmpty()) {
+      BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the audio source",
+                       __func__);
+      if (!bta_av_co_set_active_peer(peer_address)) {
+        BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
+                           __func__);
+      }
+      btif_a2dp_source_shutdown();
       active_peer_ = peer_address;
       return true;
     }
-    return false;
+
+    BtifAvPeer* peer = FindPeer(peer_address);
+    if (peer != nullptr && !peer->IsConnected()) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
+                       peer->PeerAddress().ToString().c_str());
+      return false;
+    }
+    if (!bta_av_co_set_active_peer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: unable to set active peer to %s in BtaAvCo",
+                       __func__, peer_address.ToString().c_str());
+      return false;
+    }
+    bool should_startup = active_peer_.IsEmpty();
+    active_peer_ = peer_address;
+    if (should_startup) {
+      BTIF_TRACE_EVENT("%s: active peer is empty, startup the Audio source",
+                       __func__);
+      btif_a2dp_source_startup();
+    }
+    return true;
   }
 
   const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
@@ -436,11 +462,38 @@ class BtifAvSink {
 
   const RawAddress& ActivePeer() const { return active_peer_; }
   bool SetActivePeer(const RawAddress& peer_address) {
-    if (bta_av_co_set_active_peer(peer_address)) {
+    if (active_peer_ == peer_address) return true;  // Nothing has changed
+    if (peer_address.IsEmpty()) {
+      BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the audio sink",
+                       __func__);
+      if (!bta_av_co_set_active_peer(peer_address)) {
+        BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
+                           __func__);
+      }
+      btif_a2dp_sink_shutdown();
       active_peer_ = peer_address;
       return true;
     }
-    return false;
+
+    BtifAvPeer* peer = FindPeer(peer_address);
+    if (peer != nullptr && !peer->IsConnected()) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
+                       peer->PeerAddress().ToString().c_str());
+      return false;
+    }
+    if (!bta_av_co_set_active_peer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: unable to set active peer to %s in BtaAvCo",
+                       __func__, peer_address.ToString().c_str());
+      return false;
+    }
+    bool should_startup = active_peer_.IsEmpty();
+    active_peer_ = peer_address;
+    if (should_startup) {
+      BTIF_TRACE_EVENT("%s: active peer is empty, startup the Audio source",
+                       __func__);
+      btif_a2dp_source_startup();
+    }
+    return true;
   }
 
   const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
@@ -2371,27 +2424,20 @@ static void set_active_peer_int(uint8_t peer_sep,
   BTIF_TRACE_EVENT("%s: peer_sep=%s (%d) peer_address=%s", __func__,
                    (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep,
                    peer_address.ToString().c_str());
-
   BtifAvPeer* peer = nullptr;
   if (peer_sep == AVDT_TSEP_SNK) {
-    peer = btif_av_source.FindPeer(peer_address);
-    if (peer != nullptr && peer->IsConnected()) {
-      if (!btif_av_source.SetActivePeer(peer_address)) {
-        BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
-                         peer_address.ToString().c_str());
-      }
-      return;
+    if (!btif_av_source.SetActivePeer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__,
+                       peer_address.ToString().c_str());
     }
+    return;
   }
   if (peer_sep == AVDT_TSEP_SRC) {
-    peer = btif_av_sink.FindPeer(peer_address);
-    if (peer != nullptr && peer->IsConnected()) {
-      if (!btif_av_sink.SetActivePeer(peer_address)) {
-        BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
-                         peer_address.ToString().c_str());
-      }
-      return;
+    if (!btif_av_sink.SetActivePeer(peer_address)) {
+      BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__,
+                       peer_address.ToString().c_str());
     }
+    return;
   }
   // If reached here, we could not set the active peer
   BTIF_TRACE_ERROR("%s: Cannot set active %s peer to %s: peer not %s", __func__,
index fb956b5..332beca 100644 (file)
@@ -37,6 +37,13 @@ typedef enum {
   UIPC_TX_DATA_READY_EVT = 0x0010
 } tUIPC_EVENT;
 
+/* UIPC users */
+typedef enum {
+  UIPC_USER_A2DP = 0,
+  UIPC_USER_HEARING_AID = 1,
+  UIPC_USER_NUM = 2
+} tUIPC_USER;
+
 /*
  * UIPC IOCTL Requests
  */
@@ -55,72 +62,62 @@ typedef void(tUIPC_RCV_CBACK)(
 
 const char* dump_uipc_event(tUIPC_EVENT event);
 
-/*******************************************************************************
- *
- * Function         UIPC_Init
- *
- * Description      Initialize UIPC module
+/**
+ * Initialize UIPC module
  *
- * Returns          void
- *
- ******************************************************************************/
-void UIPC_Init(void*);
+ * @param user User ID who uses UIPC
+ */
+void UIPC_Init(void*, int user);
 
-/*******************************************************************************
- *
- * Function         UIPC_Open
+/**
+ * Open a UIPC channel
  *
- * Description      Open UIPC interface
- *
- * Returns          void
- *
- ******************************************************************************/
+ * @param ch_id Channel ID
+ * @param p_cback Callback handler
+ * @return true on success, otherwise false
+ */
 bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback);
 
-/*******************************************************************************
+/**
+ * Closes a channel in UIPC or the entire UIPC module
  *
- * Function         UIPC_Close
- *
- * Description      Close UIPC interface
- *
- * Returns          void
- *
- ******************************************************************************/
-void UIPC_Close(tUIPC_CH_ID ch_id);
+ * @param ch_id Channel ID; if ch_id is UIPC_CH_ID_ALL, then cleanup UIPC
+ * @param user User ID who uses UIPC
+ */
+void UIPC_Close(tUIPC_CH_ID ch_id, int user);
 
-/*******************************************************************************
- *
- * Function         UIPC_Send
- *
- * Description      Called to transmit a message over UIPC.
- *
- * Returns          void
+/**
+ * Send a message over UIPC
  *
- ******************************************************************************/
+ * @param ch_id Channel ID
+ * @param msg_evt Message event type
+ * @param p_buf Buffer for the message
+ * @param msglen Message length
+ * @return true on success, otherwise false
+ */
 bool UIPC_Send(tUIPC_CH_ID ch_id, uint16_t msg_evt, const uint8_t* p_buf,
                uint16_t msglen);
 
-/*******************************************************************************
- *
- * Function         UIPC_Read
- *
- * Description      Called to read a message from UIPC.
+/**
+ * Read a message from UIPC
  *
- * Returns          void
- *
- ******************************************************************************/
+ * @param ch_id Channel ID
+ * @param p_msg_evt Message event type
+ * @param p_buf Buffer for the message
+ * @param len Bytes to read
+ * @return true on success, otherwise false
+ */
 uint32_t UIPC_Read(tUIPC_CH_ID ch_id, uint16_t* p_msg_evt, uint8_t* p_buf,
                    uint32_t len);
 
-/*******************************************************************************
- *
- * Function         UIPC_Ioctl
+/**
+ * Control the UIPC parameter
  *
- * Description      Called to control UIPC.
- *
- * Returns          void
- *
- ******************************************************************************/
+ * @param ch_id Channel ID
+ * @param request Request type
+ * @param param Optional parameters
+ * @return true on success, otherwise false
+ */
 bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param);
 
 #endif /* UIPC_H */
index 63a7fb0..78fdac8 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/un.h>
 #include <unistd.h>
 #include <mutex>
+#include <set>
 
 #include "audio_a2dp_hw/include/audio_a2dp_hw.h"
 #include "bt_common.h"
@@ -93,6 +94,7 @@ typedef struct {
   int signal_fds[2];
 
   tUIPC_CHAN ch[UIPC_CH_NUM];
+  std::set<int> active_users;
 } tUIPC_MAIN;
 
 /*****************************************************************************
@@ -247,6 +249,8 @@ void uipc_main_cleanup(void) {
 
   /* close any open channels */
   for (i = 0; i < UIPC_CH_NUM; i++) uipc_close_ch_locked(i);
+
+  uipc_main.active_users.clear();
 }
 
 /* check pending events in read task */
@@ -548,8 +552,17 @@ void uipc_stop_main_server_thread(void) {
  **
  ******************************************************************************/
 
-void UIPC_Init(UNUSED_ATTR void* p_data) {
+void UIPC_Init(UNUSED_ATTR void* p_data, int user) {
   BTIF_TRACE_DEBUG("UIPC_Init");
+  if (user < 0 || user >= UIPC_USER_NUM) {
+    BTIF_TRACE_ERROR("UIPC_Close : invalid user ID %d", user);
+    return;
+  }
+  std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+  auto result_insert = uipc_main.active_users.insert(user);
+  if ((uipc_main.active_users.size() != 1) || !result_insert.second) {
+    return;
+  }
 
   uipc_main_init();
   uipc_start_main_server_thread();
@@ -601,15 +614,27 @@ bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback) {
  **
  ******************************************************************************/
 
-void UIPC_Close(tUIPC_CH_ID ch_id) {
+void UIPC_Close(tUIPC_CH_ID ch_id, int user) {
   BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
-
+  if (user < 0 || user >= UIPC_USER_NUM) {
+    BTIF_TRACE_ERROR("UIPC_Close : invalid user ID %d", user);
+    return;
+  }
   /* special case handling uipc shutdown */
   if (ch_id != UIPC_CH_ID_ALL) {
     std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
     uipc_close_locked(ch_id);
     return;
   }
+
+  if (uipc_main.active_users.erase(user) == 0) {
+    return;
+  }
+
+  if (!uipc_main.active_users.empty()) {
+    return;
+  }
+
   BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
   uipc_stop_main_server_thread();
   BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");