Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f71b1cc4 authored by Hansong Zhang's avatar Hansong Zhang Committed by Pavlin Radoslavov
Browse files

A2DP: Cleanup UIPC when no active device

* 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
parent dfbe6202
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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;
  }

+1 −1
Original line number Diff line number Diff line
@@ -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
+65 −19
Original line number Diff line number Diff line
@@ -363,12 +363,38 @@ 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;
    }

    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,12 +462,39 @@ 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;
    }

    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,28 +2424,21 @@ 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 (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 reached here, we could not set the active peer
  BTIF_TRACE_ERROR("%s: Cannot set active %s peer to %s: peer not %s", __func__,
                   (peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",
+47 −50
Original line number Diff line number Diff line
@@ -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 */
+28 −3
Original line number Diff line number Diff line
@@ -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");