static bool id_match(const conn_instance* p, conn_type type, conn_id id) { bool match = FALSE; if(p != NULL) { if(p->type == type) { switch(type) { case conn_rfcomm: /* Searching for an RFCOMM connection instance is complicated as only limited data is available during the early phases of connection establishment. It's not until the completion of parameter negotiation that the mux id and server channel have been assigned */ if(id.rfcomm_id.server_channel == INVALID_SERVER_CHANNEL) { /* Invalid Server Channel, match on Bluetooth Device Address and Multiplexer id */ if(BdaddrIsSame(&p->id.rfcomm_id.bd_addr, &id.rfcomm_id.bd_addr) || (p->id.rfcomm_id.mux_id == id.rfcomm_id.mux_id)) { match = TRUE; } if(BdaddrIsZero(&id.rfcomm_id.bd_addr) && (p->id.rfcomm_id.mux_id == id.rfcomm_id.mux_id)) { if(p->id.rfcomm_id.server_channel == 0xff) match = TRUE; } } else if(id.rfcomm_id.mux_id == INVALID_MUX_ID) { /* Invalid Multiplexer ID, match on Bluetooth Address and Server Channel */ if (BdaddrIsSame(&p->id.rfcomm_id.bd_addr, &id.rfcomm_id.bd_addr) && (p->id.rfcomm_id.server_channel == id.rfcomm_id.server_channel)) match = TRUE; } else { /* Match on Multiplexer ID and Server Channel */ if((p->id.rfcomm_id.mux_id == id.rfcomm_id.mux_id && p->id.rfcomm_id.server_channel == id.rfcomm_id.server_channel)) { match = TRUE; } } break; case conn_l2cap: if(p->id.l2cap_id.cid == id.l2cap_id.cid && id.l2cap_id.cid != L2CA_CID_INVALID) match = TRUE; else if ((p->id.l2cap_id.psm == id.l2cap_id.psm) && (id.l2cap_id.psm != L2CA_PSM_INVALID) && (id.l2cap_id.cid != L2CA_CID_INVALID) &&(p->id.l2cap_id.cid == L2CA_CID_INVALID)) match = FALSE; else if (p->id.l2cap_id.psm == id.l2cap_id.psm && id.l2cap_id.psm != L2CA_PSM_INVALID && p->id.l2cap_id.cid == L2CA_CID_INVALID) match = TRUE; break; } } } return match; }
/************************************************************************* NAME gattFindConnAddr DESCRIPTION Find GATT connection entry in task_cid_map by the address. This only done for SDP searches and so the transport will always be BREDR and the address type PUBLIC. RETURNS */ cid_map_t *gattFindConnAddr(const bdaddr *addr) { cid_map_t *found = NULL; cid_map_t *conn; tp_bdaddr tpaddr; uint16 i; /* go through active connections */ for (i = 0; i < MAX_ATT_CONNECTIONS; i++) { conn = &theGatt->u.cid_map[i]; /* fake instance for SDP search */ if ((conn->data.scenario == gatt_ms_discover_all_bredr_services || conn->data.scenario == gatt_ms_discover_bredr_service) && BdaddrIsSame( addr, &conn->data.req.discover_all_bredr_services.addr)) { return conn; } /* get address from cid */ else if (VmGetBdAddrtFromCid(conn->cid, &tpaddr) && tpaddr.transport == TRANSPORT_BREDR_ACL && tpaddr.taddr.type == TBDADDR_PUBLIC && BdaddrIsSame(addr, &tpaddr.taddr.addr)) { found = conn; } } return found; }
/**************************************************************************** NAME sinkCheckAvrcpStateMatch DESCRIPTION helper function to check an avrcp play status for a given a2dp link priority RETURNS true is the avrcp play state matches that passed in false if state does not match or no matching avrcp link is found for a2dp profile index */ bool sinkCheckAvrcpStateMatch(a2dp_link_priority priority, avrcp_play_status play_status) { if((BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[priority], &theSink.avrcp_link_data->bd_addr[a2dp_primary])&&(theSink.avrcp_link_data->play_status[a2dp_primary] == play_status))|| (BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[priority], &theSink.avrcp_link_data->bd_addr[a2dp_secondary])&&(theSink.avrcp_link_data->play_status[a2dp_secondary] == play_status))) { return TRUE; } else { return FALSE; } }
/**************************************************************************** NAME linkPolicyPhonebookAccessComplete DESCRIPTION set the link policy requirements back after phonebook access, based on current device audio state RETURNS void */ void linkPolicyPhonebookAccessComplete(Sink sink) { typed_bdaddr taddr; uint16 DeviceId; uint16 StreamId; uint8 i; bool a2dpSetting = FALSE; /* If device is in the stream a2dp state, use a2dp link policy */ for_all_a2dp(i) { DeviceId = theSink.a2dp_link_data->device_id[i]; StreamId = theSink.a2dp_link_data->stream_id[i]; if( SinkGetBdAddr(sink, &taddr) && BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[i], &taddr.addr) ) { a2dpSetting = TRUE; if(A2dpMediaGetState(DeviceId, StreamId)== a2dp_stream_streaming) linkPolicyUseA2dpSettings(DeviceId, StreamId, A2dpMediaGetSink(DeviceId, StreamId)); else linkPolicyUseHfpSettings(hfp_primary_link, sink); } } /* Otherwise, use hfp link policy */ if(!a2dpSetting) { linkPolicyUseHfpSettings(hfp_primary_link, sink); } }
/**************************************************************************** NAME sendSearchRequest DESCRIPTION Decide whather a search request primitive can be sent to BlueStack or not RETURNS sdp_search_req - see typedef above */ static sdp_search_req sendSearchRequest(Task theAppTask, const connectionSdpState *state, const bdaddr *bd_addr) { /* Check the first lock */ if (state->sdpLock) { /* SDP search session open or non search primitive sent to BlueStack */ if (BdaddrIsZero(&state->sdpServerAddr)) { /* SDP search session not open but another prim is currently being handled (sdpLock set) so we can't start the search yet */ return sdp_lock_set; } else { /* Addr set - SDP search session open */ if (state->sdpSearchLock) { /* Search currently active so can't start another one */ return sdp_search_lock_set; } else { /* SDP session open but no active search */ if (BdaddrIsSame(&state->sdpServerAddr, bd_addr)) { /* SDP search session open to the device we want to search so we can just start our search */ return sdp_start_search; } else { /* SDP search session open to a different device so we can't do our search until this session is closed. */ return sdp_session_open_other_dev; } } } } else { /* Check if we currently have a search active, block internal requests if sdpLock not set */ if (state->sdpSearchLock || theAppTask == connectionGetCmTask()) { /* Search currently active */ return sdp_search_lock_set; } else { /* No search currently active */ return sdp_start_search; } } }
/**************************************************************************** NAME sinkPartyModeCheckForOtherPausedSource DESCRIPTION function to look for a device other than the one passed in that is in an paused state RETURNS link priority if an avrcp paused device is found */ a2dp_link_priority sinkPartyModeCheckForOtherPausedSource(a2dp_link_priority link) { /* determine if the other device is connected and has avrcp connected*/ if(BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[OTHER_DEVICE(link)], &theSink.avrcp_link_data->bd_addr[a2dp_primary])) { /* device is connected, check its current avrcp state, if paused then return index of device */ if(theSink.avrcp_link_data->play_status[a2dp_primary] == avrcp_play_status_paused) return OTHER_DEVICE(link); } /* determine if the other device is connected and has avrcp connected*/ else if(BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[OTHER_DEVICE(link)], &theSink.avrcp_link_data->bd_addr[a2dp_secondary])) { /* device is connected, check its current avrcp state, if paused then return index of device */ if(theSink.avrcp_link_data->play_status[a2dp_secondary] == avrcp_play_status_paused) return OTHER_DEVICE(link); } /* no paused other devices found */ return a2dp_invalid; }
/**************************************************************************** NAME hidFindFromBddr DESCRIPTION Searches for a HID instance with matching address. RETURNS HID - Pointer to HID instance, or NULL if no match. */ HID *hidFindFromBddr(HID_LIB *hid_lib, const bdaddr *addr) { HID *hid = hid_lib->list; while (hid) { if (BdaddrIsSame(&hid->remote_addr, addr)) break; hid = hid->next; } return hid; }
/**************************************************************************** NAME deviceManagerIsSameDevice DESCRIPTION Determines if the supplied HF and AV devices are actually one and the same RETURNS TRUE if the devices are the same, FALSE otherwise */ bool deviceManagerIsSameDevice(a2dp_link_priority a2dp_link, hfp_link_priority hfp_link) { typed_bdaddr tbdaddr1, tbdaddr2; if (theSink.a2dp_link_data && theSink.a2dp_link_data->connected[a2dp_link]) { /* A2dp link data present and device marked as connected */ if (HfpLinkGetBdaddr(hfp_link, &tbdaddr1.addr) && A2dpDeviceGetBdaddr(theSink.a2dp_link_data->device_id[a2dp_link], &tbdaddr2.addr)) { /* Successfully obtained bdaddrs */ return BdaddrIsSame(&tbdaddr1.addr, &tbdaddr2.addr); } } return FALSE; }
/**************************************************************************** NAME mapcGetLinkFromBdAddr DESCRIPTION Searches through any MAP connections looking for a match of bdaddr, if found returns the link associated with that bdaddr PARAMS @pAddr RETURNS mapc_link_priority */ static mapc_link_priority mapcGetLinkFromBdAddr(const bdaddr *pAddr) { mapc_link_priority device_id = 0; /* search all possible map connections */ for(device_id = 0; device_id < MAX_MAPC_CONNECTIONS; device_id ++) { mapcState *state = &(theSink.rundata->mapc_data.state[device_id]); /* if bdaddr matches that passed then return the appropriate link id */ if(BdaddrIsSame(&state->bdAddr, pAddr)) return(device_id); } /* no map connections matching the passed in bdaddr */ return(mapc_invalid_link); }
/**************************************************************************** DESCRIPTION This function searches for the specified peer device in the Trusted Device List (TDL). The value returned as position defines the record number of the device in TDL. -------------------------------------- |R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | -------------------------------------- If the value returned is zero then the device does not exist in the TDL */ static uint16 find_trusted_device(const bdaddr* p_peer_addr) { uint16 rec; TrustedDeviceRecordType record; /* Loop through list of trusted devices */ for(rec = 0; rec < NO_DEVICES_TO_MANAGE; rec++) { if(PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType))) { /* If this device is already a trusted device? */ if(BdaddrIsSame(&record.bd_addr, p_peer_addr)) return (rec + 1); } } /* Device is not in the trusted device list */ return 0; }
Task connectionGetPsmBdaddrMatch(uint16 psm_local, bdaddr addr, uint16 *instances) { conn_instance* curr = conn_list_head; Task appTask = NULL; *instances = 0; while(curr != NULL) { if((curr->type == conn_l2cap) && BdaddrIsSame(&curr->addr, &addr) && (curr->id.l2cap_id.psm == psm_local)) { *instances = *instances + 1; appTask = curr->appTask; } curr = curr->next; } return appTask; }
/**************************************************************************** NAME deviceManagerProfilesConnected DESCRIPTION Compare bdaddr against those of the current connected devices RETURNS conn_mask indicating which profiles the device is connected to */ conn_mask deviceManagerProfilesConnected(const bdaddr * bd_addr) { bdaddr dev_addr; conn_mask mask, result = 0; /* Go through all profiles */ for(mask = conn_hfp_pri; mask <= conn_a2dp_sec; mask <<=1) { /* Get bluetooth address for profile if connected */ if(deviceManagerGetProfileAddr(mask, &dev_addr)) { /* If address matches device passed in... */ if(BdaddrIsSame(bd_addr, &dev_addr)) result |= mask; } } DEV_DEBUG(("DEV: profiles connected bdaddr %x %x %x Conn Mask %X\n", (uint16)bd_addr->nap,(uint16)bd_addr->uap,(uint16)bd_addr->lap,result)); return result; }
Task connectionCompletedConnectionsGetPsmBdaddrMatch(uint16 psm_local, bdaddr addr, uint16 *instances) { multiple_channels_instance* curr = multiple_channels_list_head; Task appTask = NULL; uint16 i = 0; *instances = 0; for (i = 0; i < multiple_channels_entries; i++) { if(BdaddrIsSame(&curr->addr, &addr) && (curr->psm == psm_local)) { *instances = *instances + 1; appTask = curr->appTask; } curr++; } return appTask; }
static void handlePbapConnectCfm(PBAPC_CONNECT_CFM_T *pMsg) { PBAP_DEBUG(("PBAPC_CONNECT_CFM, Status : %d, packet size:[%d]\n", pMsg->status, pMsg->packetSize)); if(pMsg->status == pbapc_success) { /* If the Pbap of primary HFP device has been connected, save its device_id as the active link */ bdaddr ag_addr; Sink sink; if( HfpLinkGetSlcSink(hfp_primary_link, &sink) && SinkGetBdAddr(sink, &ag_addr) ) { if(BdaddrIsSame(&ag_addr, &(pMsg->bdAddr))) { theHeadset.pbap_active_link = pMsg->device_id; PBAP_DEBUG(("PBAPC_CONNECT_CFM, Set the active Pbap link as [%d]\n", theHeadset.pbap_active_link)); #ifdef BHC612 PBAP_DEBUG(("[BT Addr: nap %04x uap %02x lap %08lx]\n",ag_addr.nap,ag_addr.uap,ag_addr.lap)); #endif } } /* if we are making Pbapc dialing now */ if(theHeadset.pbap_dial_state == pbapc_dialling) { PBAP_DEBUG(("PBAPC_CONNECT_CFM, Pbap dialling, set the phonebook\n")); /* Set required phonebook */ PbapcSetPhonebook(pMsg->device_id, pbap_local, theHeadset.pbap_active_pb); } } else { /* pbapc profile connection failure */ if(theHeadset.pbap_dial_state == pbapc_dialling) { MessageSend ( &theHeadset.task , EventPbapDialFail , 0 ) ; theHeadset.pbap_dial_state = pbapc_no_dial; } } }
/**************************************************************************** NAME scanStoreInquireResult DESCRIPTION Stores the data returned in an inquiry result message. */ void scanStoreInquireResult (const CL_DM_INQUIRE_RESULT_T *prim) { /* Default EIR values */ mvdEirData result; DEBUG_SCAN(("Found device: 0x%X 0x%X 0x%lX\n", (uint16)prim->bd_addr.nap, (uint16)prim->bd_addr.uap, (uint32)prim->bd_addr.lap)); result = parseEirData(prim->size_eir_data, prim->eir_data); result.profiles &= the_app->supported_profiles; /* If device doesn't support anything we can use forget it */ if ((result.profiles == ProfileNone) && (result.profiles_complete)) { DEBUG_SCAN(("Device Unsupported\n")); return; } /* Subtract RSSI from Inquiry Tx Power, assume min possible RSSI if unknown */ result.path_loss -= (prim->rssi == CL_RSSI_UNKNOWN) ? -127 : prim->rssi; DEBUG_SCAN(("path loss: %i\n",result.path_loss)); if ( (s_inquiry_scan_data != NULL) && (s_inquiry_scan_data->write_idx < INQUIRY_SCAN_BUFFER_SIZE) ) { uint8 j,k; /* Start by checking if we have already found this device */ for ( k = 0 ; k < s_inquiry_scan_data->write_idx ; k++ ) { /* Found duplicate */ if (BdaddrIsSame(&prim->bd_addr, &s_inquiry_scan_data->buffer[k])) { DEBUG_SCAN(("Device already found\n")); /* If we got a lower path loss this time */ if (result.path_loss < s_inquiry_scan_data->eir_data[k].path_loss) { /* Remove the old record and put this one in */ DEBUG_SCAN((" - updating\n")); s_inquiry_scan_data->write_idx--; for ( j=k ; j < s_inquiry_scan_data->write_idx ; j++) { memcpy(&s_inquiry_scan_data->buffer[j],&s_inquiry_scan_data->buffer[j+1], sizeof(bdaddr)); s_inquiry_scan_data->eir_data[j] = s_inquiry_scan_data->eir_data[j+1]; } break; } else { /* No point updating */ DEBUG_SCAN((" - returning\n")); return; } } } /* Move up the found devices list */ for ( k = k ; k > 0 ; k-- ) { /* If next dev up has lower path loss we have found our place */ if (s_inquiry_scan_data->eir_data[k-1].path_loss <= result.path_loss) break; } DEBUG_SCAN(("Adding device at %d of %d\n",k,s_inquiry_scan_data->write_idx)); /* Shuffle down other entries if required */ for ( j = s_inquiry_scan_data->write_idx ; j > k ; j-- ) { memcpy(&s_inquiry_scan_data->buffer[j],&s_inquiry_scan_data->buffer[j-1], sizeof(bdaddr)); s_inquiry_scan_data->eir_data[j] = s_inquiry_scan_data->eir_data[j-1]; } /* Add device at k and increment write index */ memcpy(&s_inquiry_scan_data->buffer[k], &prim->bd_addr, sizeof(bdaddr)); s_inquiry_scan_data->eir_data[k] = result; s_inquiry_scan_data->write_idx++; } }
bool BdaddrTypedIsSame(const typed_bdaddr *first, const typed_bdaddr *second) { return first->type == second->type && BdaddrIsSame(&first->addr, &second->addr); }
/**************************************************************************** NAME inquiry_store_result - Store the device returned in the CL_DM_INQUIRE_RESULT message */ static void inquiry_store_result(const CL_DM_INQUIRE_RESULT_T *prim) { INQUIRY_EIR_DATA_T result; INQUIRY_DEBUG(("INQUIRY: Found device:")); DEBUG_BDADDR(prim->bd_addr); result = inquiry_parse_eir_data(prim->size_eir_data, prim->eir_data); /* If device doesn't support anything we can use forget it */ if ((result.profiles == PROFILE_NONE) && (result.profiles_complete)) { INQUIRY_DEBUG(("INQUIRY: Device Unsupported\n")); return; } /* Subtract RSSI from Inquiry Tx Power, assume min possible RSSI if unknown */ result.path_loss -= (prim->rssi == CL_RSSI_UNKNOWN) ? -127 : prim->rssi; INQUIRY_DEBUG(("INQUIRY: path loss: %i\n", result.path_loss)); if ((theSource->inquiry_data != NULL) && (theSource->inquiry_data->write_idx < INQUIRY_SCAN_BUFFER_SIZE)) { uint8 j, k; /* Start by checking if we have already found this device */ for (k = 0; k < theSource->inquiry_data->write_idx; k++) { /* Found duplicate */ if (BdaddrIsSame(&prim->bd_addr, &theSource->inquiry_data->buffer[k] )) { INQUIRY_DEBUG(("INQUIRY: Device already found\n")); /* If we got a lower path loss this time */ if (result.path_loss < theSource->inquiry_data->eir_data[k].path_loss) { /* Remove the old record and put this one in */ INQUIRY_DEBUG(("INQUIRY: - updating\n")); theSource->inquiry_data->write_idx--; for (j = k; j < theSource->inquiry_data->write_idx; j++) { theSource->inquiry_data->buffer[j] = theSource->inquiry_data->buffer[j+1]; theSource->inquiry_data->eir_data[j] = theSource->inquiry_data->eir_data[j+1]; } break; } else { /* No point updating */ INQUIRY_DEBUG(("INQUIRY: - returning\n")); return; } } } /* Move up the found devices list */ for (k = k; k > 0; k--) { /* If next dev up has lower path loss we have found our place */ if (theSource->inquiry_data->eir_data[k-1].path_loss <= result.path_loss) break; } INQUIRY_DEBUG(("INQUIRY: Adding device at %d of %d\n", k, theSource->inquiry_data->write_idx)); INQUIRY_DEBUG((" path_loss:%d profiles:%d profiles_complete:%d\n", result.path_loss, result.profiles, result.profiles_complete)); DEBUG_BDADDR(prim->bd_addr); /* Shuffle down other entries if required */ for (j = theSource->inquiry_data->write_idx; j > k; j--) { theSource->inquiry_data->buffer[j] = theSource->inquiry_data->buffer[j-1]; theSource->inquiry_data->eir_data[j] = theSource->inquiry_data->eir_data[j-1]; } /* Add device at k and increment write index */ theSource->inquiry_data->buffer[k] = prim->bd_addr; theSource->inquiry_data->eir_data[k] = result; theSource->inquiry_data->write_idx++; } }
/**************************************************************************** NAME sinkHandleSlcConnectCfm DESCRIPTION Confirmation that the SLC has been established (or not). RETURNS void */ bool sinkHandleSlcConnectCfm( const HFP_SLC_CONNECT_CFM_T *cfm ) { sink_attributes attributes; bool lResult = FALSE; #ifdef ENABLE_PEER inquiry_result_t* connecting_device = inquiryGetConnectingDevice(); #endif deviceManagerGetDefaultAttributes(&attributes, FALSE); (void)deviceManagerGetAttributes(&attributes, &cfm->bd_addr); /* cancel any link loss reminders */ MessageCancelAll(&theSink.task , EventSysLinkLoss ); /* Check the status of the SLC attempt */ if (cfm->status == hfp_connect_success) { SLC_DEBUG(("SLC: ConnCfm - Success\n")) ; lResult = TRUE ; /* update the profile volume level */ theSink.profile_data[PROFILE_INDEX(cfm->priority)].audio.gSMVolumeLevel = attributes.hfp.volume; /* Handle new connection setup */ slcConnectionComplete(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr); /* Handle common setup for new SLC/link loss */ slcConnectionSetup(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr); /* Record the position of the device in the PDL - prevents reconnection later */ theSink.profile_data[PROFILE_INDEX(cfm->priority)].status.list_id = deviceManagerSetPriority((bdaddr *)&cfm->bd_addr); #ifdef ENABLE_PEER /* If RSSI pairing, check inquiry results for A2DP support */ if (theSink.inquiry.action == rssi_pairing) { if ((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp)) { attributes.profiles |= sink_a2dp; } } #endif /* Make sure we store this device */ attributes.profiles |= sink_hfp; deviceManagerStoreAttributes(&attributes, &cfm->bd_addr); /* if rssi pairing check to see if need to cancel rssi pairing or not */ if(theSink.inquiry.action == rssi_pairing) { /* if rssi pairing has completed and the device being connected currently doesn't support A2DP, then stop it progressing further */ if(!((theSink.features.PairIfPDLLessThan) && ( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan ))) { #ifdef ENABLE_PEER if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp))) #endif { inquiryStop(); } } } /* Disable A2dp link loss management if connected on remote device */ if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], FALSE); } else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], FALSE); } /* Auto answer call if ringing - only answer the incoming call if its on the connecting AG */ if ( (theSink.features.AutoAnswerOnConnect) && (HfpLinkPriorityFromCallState(hfp_call_state_incoming) == cfm->priority) && (stateManagerGetState() < deviceActiveCallSCO) ) { MessageSend (&theSink.task , EventUsrAnswer , 0 ) ; SLC_DEBUG(("SLC: AutoAnswer triggered\n")) ; } } else { SLC_DEBUG(("SLC: ConnCfm - Fail\n")) ; /* a connection timeout will arrive here, need to report fail for multipoint connections also such that a link loss retry will be performed */ if(!stateManagerIsConnected() || theSink.MultipointEnable) { /* Update local state to reflect this */ slcConnectFail(); } } /* if using multipoint and both devices are connected disable connectable */ if((theSink.MultipointEnable) && (deviceManagerNumConnectedDevs() == MAX_MULTIPOINT_CONNECTIONS)) { SLC_DEBUG(("SLC: disable Conn \n" )); MessageCancelAll(&theSink.task, EventSysConnectableTimeout); #ifdef ENABLE_SUBWOOFER if(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id)) { sinkDisableConnectable(); } #else sinkDisableConnectable(); #endif } SLC_DEBUG(("SLC: Connect A2DP? En=%d att=%d\n",theSink.features.EnableA2dpStreaming,attributes.profiles)) ; /* if the AG supports A2DP profile attempt to connect to it if auto reconnect is enabled */ if ((theSink.features.EnableA2dpStreaming) && ((!cfm->priority)||(cfm->status == hfp_connect_success) || (cfm->status == hfp_connect_sdp_fail) || (cfm->status == hfp_connect_rejected)) && ((slcDetermineConnectAction() & AR_Rssi)||(attributes.profiles & sink_a2dp)) && ((slcDetermineConnectAction() & AR_Rssi)||(stateManagerGetState()!=deviceConnDiscoverable))) { SLC_DEBUG(("SLC: Connecting A2DP Remote %x\n",gSlcData.gSlcConnectRemote)) ; /* attempt connection to device supporting A2DP */ theSink.a2dp_link_data->remote_connection = gSlcData.gSlcConnectRemote; A2dpSignallingConnectRequest((bdaddr *)&cfm->bd_addr); MessageCancelFirst(&theSink.task, EventSysContinueSlcConnectRequest); /* if rssi pairing check to see if need to cancel rssi pairing or not */ if(theSink.inquiry.action == rssi_pairing) { /* if rssi pairing has completed then stop it progressing further */ if(!((theSink.features.PairIfPDLLessThan)&&( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan ))) { #ifdef ENABLE_PEER if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp))) #endif { inquiryStop(); } } } } else { /* reset connection via remote ag instead of device flag */ gSlcData.gSlcConnectRemote = FALSE; } #ifdef ENABLE_MAPC mapcMasConnectRequest((bdaddr *)&cfm->bd_addr); #endif return lResult ; }
/**************************************************************************** NAME sinkPartyModeTrackChangeIndication DESCRIPTION Called when AVRCP has detected a track change indication RETURNS none */ void sinkPartyModeTrackChangeIndication(uint16 index) { /* check to see if this is an indication from the currently active device */ if ((theSink.PartyModeEnabled)&&(theSink.features.PartyMode)&&(index == sinkAvrcpGetActiveConnection())) { PTY_DEBUG(("PTY: track change active dev\n")); if(!theSink.features.avrcp_enabled || !theSink.features.EnableAvrcpAudioSwitching) { PTY_DEBUG(("PTY: ignore AVRCP in party mode\n")); return; } /* check whether to changing the audio routing */ else { /* get current audio status */ audio_source_status * lAudioStatus = audioGetStatus(theSink.routed_audio); /* ensure device is still streaming/playing */ /* determine which device track change came from */ if(BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[a2dp_primary], &theSink.avrcp_link_data->bd_addr[index])) { /* track change on primary a2dp device, check it is still streaming and audio is routed */ if(((theSink.avrcp_link_data->play_status[index] == avrcp_play_status_playing)||(theSink.avrcp_link_data->play_status[index] == avrcp_play_status_stopped)||(theSink.avrcp_link_data->play_status[index] == avrcp_play_status_paused))&& (lAudioStatus->a2dpSinkPri == lAudioStatus->audio_routed)&&(lAudioStatus->a2dpStatePri == a2dp_stream_streaming)) { /* track change on a2dp primary is valid, check if a2dp secondary is paused */ if((lAudioStatus->a2dpStateSec == a2dp_stream_streaming)||(lAudioStatus->a2dpStateSec == a2dp_stream_open)) { /* check avrcp play status is paused */ if((theSink.rundata->partymode_pause.audio_source_secondary_paused)&&(theSink.avrcp_link_data->play_status[(index^1)] == avrcp_play_status_paused)) { PTY_DEBUG(("PTY: track change route sec dis pri\n")); /* disconnect primary device */ sinkPartyModeDisconnectAndResume(a2dp_primary, lAudioStatus); /* reset paused flag */ theSink.rundata->partymode_pause.audio_source_secondary_paused = FALSE; } } } } else if(BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[a2dp_secondary], &theSink.avrcp_link_data->bd_addr[index])) { /* track change on primary a2dp device, check it is still streaming and audio is routed */ if(((theSink.avrcp_link_data->play_status[index] == avrcp_play_status_playing)||(theSink.avrcp_link_data->play_status[index] == avrcp_play_status_stopped)||(theSink.avrcp_link_data->play_status[index] == avrcp_play_status_paused))&& (lAudioStatus->a2dpSinkSec == lAudioStatus->audio_routed)&&(lAudioStatus->a2dpStateSec == a2dp_stream_streaming)) { /* track change on a2dp primary is valid, check if a2dp secondary is paused */ if((lAudioStatus->a2dpStatePri == a2dp_stream_streaming)||(lAudioStatus->a2dpStatePri == a2dp_stream_open)) { /* check avrcp play status is paused */ if((theSink.rundata->partymode_pause.audio_source_primary_paused)&&(theSink.avrcp_link_data->play_status[(index^1)] == avrcp_play_status_paused)) { PTY_DEBUG(("PTY: track change route pri dis sec\n")); /* disconnect secondary device */ sinkPartyModeDisconnectAndResume(a2dp_secondary, lAudioStatus); /* reset paused flag */ theSink.rundata->partymode_pause.audio_source_primary_paused = FALSE; } } } } /* free malloc'd status memory slot */ freePanic(lAudioStatus); } } /* indication from device that isn't currently streaming audio, ignore */ else { PTY_DEBUG(("PTY: track change ignored PTY[%d] index[%d] ActiveIdx[%d]\n",(theSink.PartyModeEnabled && theSink.features.PartyMode),index,sinkAvrcpGetActiveConnection())); } }
/**************************************************************************** NAME sinkHandleSlcDisconnectInd DESCRIPTION Indication that the SLC has been released. RETURNS void */ void sinkHandleSlcDisconnectInd( const HFP_SLC_DISCONNECT_IND_T *ind ) { conn_mask mask = deviceManagerProfilesConnected(&ind->bd_addr); SLC_DEBUG(("SLC: slc DiscInd for index %d, status = %d\n",ind->priority, ind->status)) ; if(ind->status == hfp_disconnect_success || ind->status == hfp_disconnect_link_loss || ind->status == hfp_disconnect_abnormally) { /* store volume info */ deviceManagerUpdateAttributes(&ind->bd_addr, sink_hfp, ind->priority, 0); /* Sends the indication to the device manager to send an event out if a device has disconnected*/ deviceManagerDeviceDisconnectedInd(&ind->bd_addr); /*if the device is off then this is disconnect as part of the power off cycle - dont re-enable connectable*/ if ( stateManagerGetState() != deviceLimbo) { /* Enable A2dp link loss management if connected on remote device */ if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], TRUE); } else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], TRUE); } /* Kick role checking now a device has disconnected */ linkPolicyCheckRoles(); /* at least one device disconnected, re-enable connectable for another 60 seconds */ sinkEnableMultipointConnectable(); } /*a disconnect in active call state is a call transfer*/ if ( (stateManagerGetState() == deviceActiveCallSCO) || (stateManagerGetState() == deviceActiveCallNoSCO) ) { gSlcData.gCallTransferInProgress = TRUE ; } else { gSlcData.gCallTransferInProgress = FALSE ; } /* if not a link loss reset the last outgoing AG as AG1 will no longer exist now */ theSink.last_outgoing_ag = hfp_primary_link; /* reset the list id of the device just dropped */ theSink.profile_data[PROFILE_INDEX(ind->priority)].status.list_id = INVALID_LIST_ID; /* if device has now disconnected all profiles, mark as disconnected */ if((ind->status != hfp_disconnect_link_loss)&&(!(mask & conn_hfp))) theSink.profile_data[PROFILE_INDEX(ind->priority)].status.connected = FALSE; /* If primary disconnected */ if(ind->priority == hfp_primary_link) { /* ...and we have a secondary link it will be promoted to primary */ if(theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id != INVALID_LIST_ID) { /* Block copy secondary data to primary location */ theSink.profile_data[PROFILE_INDEX(hfp_primary_link)] = theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)]; /* Secondary link no longer exists, set it to invalid */ theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id = INVALID_LIST_ID; } } /* send event slc disconnected only if the status of the indication is success or link loss indication */ MessageSend(&theSink.task , ((ind->status == hfp_disconnect_link_loss) ? EventSysReconnectFailed : EventSysSLCDisconnected) , 0) ; } /*if the device is off then this is disconnect as part of the power off cycle, otherwise check whether device needs to be made connectable */ if ( stateManagerGetState() != deviceLimbo) { /* if the device state still shows connected and there are no profiles currently connected then update the device state to reflect the change of connections */ if ((stateManagerIsConnected()) && (!deviceManagerNumConnectedDevs())) { stateManagerEnterConnectableState( FALSE ) ; } } }
/**************************************************************************** NAME deviceManagerSetPriority DESCRIPTION Set a device's priority in the PDL RETURNS new pdl listId of passed in src addr */ uint8 deviceManagerSetPriority(const bdaddr* dev_addr) { conn_mask mask = deviceManagerProfilesConnected(dev_addr); uint8 ListId = 0; DEV_DEBUG(("DEV: Update PDL/MRU\n")) ; /* more than 1 connected device ? */ if(deviceManagerNumConnectedDevs() > 1) { typed_bdaddr typed_ag_addr; bdaddr ag_addr; sink_attributes attributes; DEV_DEBUG(("DEV: Update MRU - two devices connected\n")) ; /* is this a connection of a2dp or hfp to the already connected primary device ? */ deviceManagerGetIndexedAttributes(0, &attributes, &typed_ag_addr); /* extract bluetooth address from packed structure */ ag_addr = typed_ag_addr.addr; /* check if this is the primary device? */ if(BdaddrIsSame(&ag_addr,dev_addr)) { DEV_DEBUG(("DEV: Update MRU - two devices two profiles connected - primary device\n")) ; ListId = 0; } else { DEV_DEBUG(("DEV: Update MRU - two devices two profiles connected - secondary device\n")) ; /* Move the second device to top of the PDL */ ConnectionSmUpdateMruDevice(dev_addr); /* get bdaddr of the device that was previously the primary device but is now the secondary device */ deviceManagerGetIndexedAttributes(1, &attributes, &typed_ag_addr); /* extract bluetooth address from packed structure */ ag_addr = typed_ag_addr.addr; /* then move the what is now 'secondary device' back to the top of the PDL */ ConnectionSmUpdateMruDevice(&ag_addr); /* this is the secondary device */ ListId = 1; /* send connected event if not already done so */ if(mask && !((mask & conn_hfp)&&(mask & conn_a2dp))) { MessageSend (&theSink.task , EventSecondaryDeviceConnected , NULL ); } } } /* only 1 device so must be primary */ else { /* Move device to top of the PDL */ DEV_DEBUG(("DEV: Update MRU - primary device\n")) ; ConnectionSmUpdateMruDevice(dev_addr); /* if this is the first profile for the device to be connected then send the primary device connected event */ if(mask && !((mask & conn_hfp)&&(mask & conn_a2dp))) { MessageSend (&theSink.task , EventPrimaryDeviceConnected , NULL ); } } /* return current pdl list position of this device which is 0, top of list */ DEV_DEBUG(("DEV: Update MRU - ListId = %x\n",ListId)) ; return ListId; }