/**************************************************************************** NAME deviceManagerNumConnectedDevs DESCRIPTION determines the number of different connected devices, a device may connected both hfp and a2dp or only one of each RETURNS number of connected devices */ uint8 deviceManagerNumConnectedDevs(void) { conn_mask mask; bdaddr dev_addr; uint8 no_devices = 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 HFP connection, or A2DP connection on device with no HFP... */ if( (mask & conn_hfp) || (!(conn_hfp & deviceManagerProfilesConnected(&dev_addr))) ) no_devices++; } } DEV_DEBUG(("DEV: Conn Count %d\n", no_devices)); return no_devices; }
/**************************************************************************** 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; }
/**************************************************************************** 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 ) ; } } }