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) {
/* 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;
}
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
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_; }
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_; }
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__,
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
*/
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 */
#include <sys/un.h>
#include <unistd.h>
#include <mutex>
+#include <set>
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "bt_common.h"
int signal_fds[2];
tUIPC_CHAN ch[UIPC_CH_NUM];
+ std::set<int> active_users;
} tUIPC_MAIN;
/*****************************************************************************
/* 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 */
**
******************************************************************************/
-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();
**
******************************************************************************/
-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");