void connectionHandleRfcommEstablishCfm(const RFC_ESTABLISH_CFM_T* cfm) { /* Get the connection instance data keyed by server channel and mux id */ conn_instance *conn = getRfcommConnection(NULL, cfm->mux_id, cfm->server_chan); if(conn) { if(cfm->result_code == RFC_SUCCESS) { /* Move to the modem status phase */ conn->config.rfcomm.state = modem_status_phase; /* Send modem status signal, data cannot be exchanged until both sides have exchanged modem status signals */ startControlPhase(conn); } else if (cfm->result_code == DLC_ALREADY_EXISTS) { /* Send a cfm to the app indicating an error has ocurred*/ sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_channel_already_open, INVALID_SERVER_CHANNEL, 0, 0); /* Cancel the connect timeout and clean up the connection state data. */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); (void) deleteRfcommConnection(NULL, cfm->mux_id, cfm->server_chan); } else if (cfm->result_code == REMOTE_REFUSAL) { /* Connection establishment failed, clean up */ endConnection(conn); /* Inform the app of the failure */ sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_rejected, INVALID_SERVER_CHANNEL, 0, 0); /* Cancel the connect timeout and clean up the connection state data. */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); (void) deleteRfcommConnection(NULL, cfm->mux_id, cfm->server_chan); } else { /* Connection establishment failed, clean up */ endConnection(conn); /* Inform the app of the failure */ sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_failed, INVALID_SERVER_CHANNEL, 0, 0); /* Cancel the connect timeout and clean up the connection state data. */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); (void) deleteRfcommConnection(NULL, cfm->mux_id, cfm->server_chan); } } /* This could happen if the connect timeout has triggered and cleaned up the connection state entry and then we get an RFC_ESTABLISH_CFM indicating the remote end failed to respond. We should just ignore this cfm. */ }
/**************************************************************************** NAME audio_start_active_timer - Starts the audio active timer in USB mode if the USB audio interfaces are inactive */ void audio_start_active_timer(void) { MessageCancelFirst(&theSource->app_data.appTask, APP_USB_AUDIO_ACTIVE); MessageCancelFirst(&theSource->app_data.appTask, APP_USB_AUDIO_INACTIVE); #ifndef ANALOGUE_INPUT_DEVICE /* Audio active timer only applies to a USB device as an Analogue input device cannot be notified when audio is present */ if ((theSource->ps_config->ps_timers.usb_audio_active_timer != TIMER_NO_TIMEOUT) && (!theSource->audio_data.audio_usb_active)) { /* send the audio inactive message after the PS configured delay */ MessageSendLater(&theSource->app_data.appTask, APP_USB_AUDIO_INACTIVE, 0, D_SEC(theSource->ps_config->ps_timers.usb_audio_active_timer)); } #endif }
void connectionHandleRfcommRegisterCfm(connectionRfcommState *rfcommState, const RFC_REGISTER_CFM_T *cfm) { connection_lib_status status = fail; /* Cancel the message checking we got a register cfm from BlueStack */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_REGISTER_TIMEOUT_IND); if(rfcommState->registerLock) { if(cfm->accept) { map_id id, new_id; id.channel = INVALID_SERVER_CHANNEL; new_id.channel = cfm->server_chan; /* Update the task map with the registered server channel. */ connectionUpdateTaskMap(conn_rfcomm, id, new_id); status = success; } else { /* Delete task map entry the rfcomm register failed */ deleteTaskMap(INVALID_SERVER_CHANNEL); } /* Send register cfm message to Client application */ sendRfcommRegisterCfm(rfcommState->registerLock, status, status==success?cfm->server_chan:0x00); /* Reset lock */ rfcommState->registerLock = 0; } }
/******************************************************************************* NAME handleWriteBatteryLevelClientConfig DESCRIPTION Handle when a GATT_BATTERY_SERVER_WRITE_CLIENT_CONFIG_IND message is recieved. PARAMETERS ind Pointer to a GATT_BATTERY_SERVER_WRITE_CLIENT_CONFIG_IND message. RETURNS void */ static void handleWriteBatteryLevelClientConfig(GATT_BATTERY_SERVER_WRITE_CLIENT_CONFIG_IND_T * ind) { gatt_client_connection_t *conn = gattClientFindByCid(ind->cid); /* * Check whether the remote device has enabled or disabled * notifications for the Battery Level characteristic. This value will need * to be stored as device attributes so they are persistent. */ GATT_BATTERY_SERVER_INFO(("GATT_BATTERY_SERVER_WRITE_CLIENT_CONFIG_IND bas=[0x%p] cid=[0x%x] value[0x%x]\n", (void *)ind->battery_server, ind->cid, ind->config_value)); if (conn) { unsigned short updateNeedsSending = 0; if (ind->battery_server == GATT_SERVER.bas_server_local) { conn->client_config.battery_local = ind->config_value; GATT_BATTERY_SERVER_INFO((" battery local client_config[0x%x]\n", conn->client_config.battery_local)); gattClientStoreConfigAttributes(ind->cid, gatt_attr_service_battery_local); if( LOCAL_UPDATE_REQD(conn) ) { updateNeedsSending++; } } else if (ind->battery_server == GATT_SERVER.bas_server_remote) { conn->client_config.battery_remote = ind->config_value; GATT_BATTERY_SERVER_INFO((" battery remote client_config[0x%x]\n", conn->client_config.battery_remote)); gattClientStoreConfigAttributes(ind->cid, gatt_attr_service_battery_remote); if( REMOTE_UPDATE_REQD(conn) ) { updateNeedsSending++; } } else if (ind->battery_server == GATT_SERVER.bas_server_peer) { conn->client_config.battery_peer = ind->config_value; GATT_BATTERY_SERVER_INFO((" battery peer client_config[0x%x]\n", conn->client_config.battery_peer)); gattClientStoreConfigAttributes(ind->cid, gatt_attr_service_battery_peer); if( PEER_UPDATE_REQD(conn) ) { updateNeedsSending++; } } if( updateNeedsSending > 0 ) { MessageCancelFirst( sinkGetBleTask(), BLE_INTERNAL_MESSAGE_BATTERY_READ_TIMER ); MessageSend( sinkGetBleTask(), BLE_INTERNAL_MESSAGE_BATTERY_READ_TIMER, 0 ); } } }
/**************************************************************************** NAME connectionSendInitCfm DESCRIPTION This function is called from the main Connection Library task handler to indicate to the Client application the result of the request to initialise the Connection Library */ void connectionSendInitCfm(Task task, connection_lib_status status, cl_dm_bt_version version) { MAKE_CL_MESSAGE(CL_INIT_CFM); message->status = status; message->version = version; MessageSend(task, CL_INIT_CFM, message); /* Cancel initialisation timeout */ if(status == success) (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_INIT_TIMEOUT_IND); }
/* We end up here after reboot */ bool HandleCommitHostContinue(MessageId id, Message message) { switch(id) { case UPGRADE_HOST_IN_PROGRESS_RES: { UPGRADE_HOST_IN_PROGRESS_RES_T *msg = (UPGRADE_HOST_IN_PROGRESS_RES_T *)message; MessageCancelFirst(UpgradeGetUpgradeTask(), UPGRADE_INTERNAL_RECONNECTION_TIMEOUT); if(msg->action == 0) { MoveToState(UPGRADE_STATE_COMMIT_VERIFICATION); } else { MoveToState(UPGRADE_STATE_SYNC); } } break; case UPGRADE_INTERNAL_RECONNECTION_TIMEOUT: { bool dfu = UpgradePartitionDataIsDfuUpdate(); uint16 err = LoaderErrorCheck(); if(dfu && !err) { /* Carry on */ CommitConfirmYes(); } else { /* Revert */ UpgradeRevertUpgrades(); UpgradeCtxGetPSKeys()->upgrade_in_progress_key = UPGRADE_RESUME_POINT_ERROR; UpgradeSavePSKeys(); PRINT(("P&R: UPGRADE_RESUME_POINT_ERROR saved\n")); SetState(UPGRADE_STATE_SYNC); BootSetMode(BootGetMode()); } } break; default: return FALSE; } return TRUE; }
/**************************************************************************** NAME slcAttemptConnection DESCRIPTION attemp connection to next item in pdl RETURNS void */ void slcAttemptConnection(void) { typed_bdaddr ag_addr; sink_attributes attributes; /* attempt to obtain the device attributes for the current ListID required */ if(deviceManagerGetIndexedAttributes(gSlcData.gListID, &attributes, &ag_addr)) { /* device exists, determine whether the device supports HFP/HSP, A2DP or both and connect as appropriate */ SLC_DEBUG(("SLC: slcAttConn, listId = %d, attrib = %x\n",gSlcData.gListID,attributes.profiles)) ; /* ensure the device supports the required profiles before attempting to connect otherwise try to find another device */ if((attributes.profiles & (sink_hfp | sink_a2dp | sink_avrcp))&&(IsSameBTAdrSALT(&ag_addr.addr)==FALSE)) { /* attempt to connect to device */ slcConnectDevice(&ag_addr.addr, attributes.profiles); } /* device does not support required profiles, try to find another device that does */ else { /* attempts to find another paired device in the PDL */ MessageCancelFirst(&theSink.task, EventSysContinueSlcConnectRequest); MessageSend(&theSink.task, EventSysContinueSlcConnectRequest, 0); } } else { /* attempts to find another paired device in the PDL */ MessageCancelFirst(&theSink.task, EventSysContinueSlcConnectRequest); MessageSend(&theSink.task, EventSysContinueSlcConnectRequest, 0); } SLC_DEBUG(("SLC: slcAttConnm\n")) ; }
/**************************************************************************** NAME slcConnectionSetup DESCRIPTION Perform link setup for a given SLC RETURNS void */ static void slcConnectionSetup(hfp_link_priority priority, Sink sink, bdaddr* bd_addr) { uint16 priorityIdx = PROFILE_INDEX(priority); /* Set timeout to 5 seconds */ ConnectionSetLinkSupervisionTimeout(sink, SINK_LINK_SUPERVISION_TIMEOUT); /* Send our link policy settings */ linkPolicyUseHfpSettings(priority, sink); /* Send a delayed message to request a role indication and make necessary changes as appropriate */ MessageCancelFirst(&theSink.task , EventSysCheckRole); MessageSendConditionally (&theSink.task , EventSysCheckRole , NULL , &theSink.rundata->connection_in_progress ); #ifdef ENABLE_PBAP /* Connect the PBAP link of this device */ pbapConnect(priority); #endif /* Sync volume level and mute settings with AG */ VolumeSendAndSetHeadsetVolume(theSink.profile_data[priorityIdx].audio.gSMVolumeLevel ,FALSE , priority) ; /* Enable +CLIP from AG if using Audio Prompt numbers/names or display, always request if using display */ #if !defined(ENABLE_DISPLAY) if(theSink.features.VoicePromptNumbers) #endif HfpCallerIdEnableRequest(priority, TRUE); /* HS uses call waiting indications when AG SCO is not routed */ HfpCallWaitingEnableRequest(priority, TRUE); /* Attempt to pull the audio across if not already present, delay by 5 seconds to prevent a race condition occuring with certain phones */ MessageSendLater ( &theSink.task , EventSysCheckForAudioTransfer , 0 , 5000 ) ; /* Send different event if first connection since power on - allows different LED pattern */ if((theSink.features.UseDiffConnectedEventAtPowerOn)&&(theSink.powerup_no_connection)) MessageSend (&theSink.task , EventSysSLCConnectedAfterPowerOn , NULL ); else MessageSend (&theSink.task , EventSysSLCConnected , NULL ); /* Reset the flag - first connection indicated */ theSink.powerup_no_connection = FALSE; }
void connectionHandleRfcommControlInd(const RFC_CONTROL_IND_T *ind) { /* Get the connection instance data keyed by server channel and mux id */ conn_instance *conn = getRfcommConnection(NULL, ind->mux_id, ind->server_chan); if(conn) { /* Get the connection sink */ Sink sink = StreamRfcommSink(ind->mux_id, ind->server_chan); /* Cancel the connection timeout */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); /* Connection establishment complete, let the client application know */ sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_success, ind->server_chan, conn->config.rfcomm.maxMtu, sink); /* Associate the task with its sink */ (void) MessageSinkTask(sink, conn->config.rfcomm.app_task); /* No longer require connection instance data */ (void) deleteRfcommConnection(NULL, ind->mux_id, ind->server_chan); } else { /* This indicates that the connection is already established and as we throw away connection state on successful connection establishment, we wouldn't expect to find a connection instance */ Task task; Sink sink = StreamRfcommSink(ind->mux_id, ind->server_chan); task = MessageSinkGetTask(sink); /* Send modem status indication */ if(task) sendRfcommControlInd(task, sink, ind->control_pars.break_signal, ind->control_pars.modem_signal); } }
/**************************************************************************** NAME hfpHandleDisconnectRequest DESCRIPTION We're in the right state and have received a disconnect request, handle it here. RETURNS void */ void hfpHandleDisconnectRequest(hfp_link_data* link) { if (link->audio_sink) { MAKE_HFP_MESSAGE(HFP_INTERNAL_SLC_DISCONNECT_REQ); message->link = link; /* If we have a SCO/eSCO active need to tear that down first */ hfpHandleAudioDisconnectReq(link); /* Queue up the SLC disconnect message */ MessageSendConditionally(&theHfp->task, HFP_INTERNAL_SLC_DISCONNECT_REQ, message, (uint16 *) &link->audio_sink); /*lint !e740 */ } else { /* If recovering from link loss or timed out we need to be sure to force disconnect */ if (link->ag_link_loss_state == hfp_link_loss_recovery || link->ag_link_loss_state == hfp_link_loss_timeout) { /* Link was recovering from link loss, stop the procedure */ MessageId message_id = hfpGetLinkTimeoutMessage(link, HFP_RFCOMM_LINK_LOSS_TIMEOUT_LINK_0_IND); MessageCancelFirst(&theHfp->task, message_id); hfpHandleRfcommLinkLossAbort(link, TRUE); } /* Either no link loss or we aborted link loss recovery. Now bring down the link. */ else { /* Can only get here from searching/outgoing/incoming/connected/complete */ if(link->ag_slc_state == hfp_slc_searching) { /* Notify application of connection failure (link will be reset so SDP results ignored) */ hfpSendSlcConnectCfmToApp(link, NULL, hfp_connect_sdp_fail); } else { /* Request the connection lib aborts/disconnects the RFCOMM connection */ ConnectionRfcommDisconnectRequest(&theHfp->task, hfpGetLinkSink(link)); } } } }
/**************************************************************************** NAME handleUsbMessage DESCRIPTION Handle firmware USB messages RETURNS void */ void handleUsbMessage(Task task, MessageId id, Message message) { USB_DEBUG(("USB: ")); switch (id) { case MESSAGE_USB_ATTACHED: { USB_DEBUG(("MESSAGE_USB_ATTACHED\n")); usbUpdateChargeCurrent(); audioHandleRouting(audio_source_none); usbSetLowPowerMode(theSink.usb.config.attach_timeout); if(theSink.usb.dead_battery) MessageSendLater(&theSink.task, EventUsbDeadBatteryTimeout, 0, D_MIN(45)); break; } case MESSAGE_USB_DETACHED: { USB_DEBUG(("MESSAGE_USB_DETACHED\n")); theSink.usb.enumerated = FALSE; theSink.usb.suspended = FALSE; theSink.usb.deconfigured = FALSE; usbUpdateChargeCurrent(); audioHandleRouting(audio_source_none); MessageCancelAll(&theSink.task, EventUsbLowPowerMode); MessageCancelAll(&theSink.task, EventUsbDeadBatteryTimeout); break; } case MESSAGE_USB_ENUMERATED: { USB_DEBUG(("MESSAGE_USB_ENUMERATED\n")); if(!theSink.usb.enumerated) { theSink.usb.enumerated = TRUE; usbUpdateChargeCurrent(); MessageCancelAll(&theSink.task, EventUsbLowPowerMode); MessageCancelAll(&theSink.task, EventUsbDeadBatteryTimeout); } break; } case MESSAGE_USB_SUSPENDED: { MessageUsbSuspended* ind = (MessageUsbSuspended*)message; USB_DEBUG(("MESSAGE_USB_SUSPENDED - %s\n", (ind->has_suspended ? "Suspend" : "Resume"))); if(ind->has_suspended != theSink.usb.suspended) { theSink.usb.suspended = ind->has_suspended; usbUpdateChargeCurrent(); } break; } case MESSAGE_USB_DECONFIGURED: { USB_DEBUG(("MESSAGE_USB_DECONFIGURED\n")); if(theSink.usb.enumerated) { theSink.usb.enumerated = FALSE; theSink.usb.deconfigured = TRUE; usbUpdateChargeCurrent(); usbSetLowPowerMode(theSink.usb.config.deconfigured_timeout); } break; } case MESSAGE_USB_ALT_INTERFACE: { uint16 interface_id; MessageUsbAltInterface* ind = (MessageUsbAltInterface*)message; USB_DEBUG(("MESSAGE_USB_ALT_INTERFACE %d %d\n", ind->interface, ind->altsetting)); UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_MIC_INTERFACE_ID, &interface_id); if(interface_id == ind->interface) { theSink.usb.mic_active = (ind->altsetting ? TRUE : FALSE); USB_DEBUG(("USB: Mic ID %d active %d\n", interface_id, theSink.usb.mic_active)); } UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_SPEAKER_INTERFACE_ID, &interface_id); if(interface_id == ind->interface) { theSink.usb.spkr_active = (ind->altsetting ? TRUE : FALSE); USB_DEBUG(("USB: Speaker ID %d active %d\n", interface_id, theSink.usb.spkr_active)); } #ifdef ENABLE_USB_AUDIO /* check for changes in required audio routing */ USB_DEBUG(("USB: MESSAGE_USB_ALT_INTERFACE checkAudioRouting\n")); MessageCancelFirst(&theSink.task, EventCheckAudioRouting); MessageSendLater(&theSink.task, EventCheckAudioRouting, 0, USB_AUDIO_DISCONNECT_DELAY); #endif break; } case USB_DEVICE_CLASS_MSG_AUDIO_LEVELS_IND: { USB_DEBUG(("USB_DEVICE_CLASS_MSG_AUDIO_LEVELS_IND\n")); usbAudioSetVolume(); break; } default: { USB_DEBUG(("Unhandled USB message 0x%x\n", id)); break; } } }
/**************************************************************************** NAME sysHandleSystemMessage DESCRIPTION Handle messages received from firmware/DSP. */ void sysHandleSystemMessage(MessageId id, Message message) { switch(id) { case MESSAGE_FROM_KALIMBA: { switch (*((uint16*)message)) { case KALIMBA_AUDIO_USB_OUT_STATUS: { DEBUG_KALIMBA(("KALIMBA_AUDIO_USB_OUT_STATUS:%u\n",*(((uint16*)message)+1))); if ( *(((uint16*)message)+1) ) { if ( !MessageCancelFirst(&the_app->task, APP_AUDIO_STREAMING_INACTIVE) ) { MessageSend(&the_app->task, APP_AUDIO_STREAMING_ACTIVE, NULL); } } else { MessageSendLater(&the_app->task, APP_AUDIO_STREAMING_INACTIVE, NULL, DSP_MSG_FILTER_DELAY); } break; } case KALIMBA_AUDIO_USB_IN_STATUS: { DEBUG_KALIMBA(("KALIMBA_AUDIO_USB_IN_STATUS:%u\n",*(((uint16*)message)+1))); #if !defined USE_HID_TELEPHONY /* only do VOIP calls if HFP connected */ if (aghfpSlcGetConnectedHF() != NULL) { if ( *(((uint16*)message)+1) ) { if ( !MessageCancelFirst(&the_app->task, APP_VOIP_CALL_INACTIVE) ) { MessageSendLater(&the_app->task, APP_VOIP_CALL_ACTIVE, NULL, VISTA_MSG_FILTER_DELAY); } } else { if ( !MessageCancelFirst(&the_app->task, APP_VOIP_CALL_ACTIVE) ) { MessageSendLater(&the_app->task, APP_VOIP_CALL_INACTIVE, NULL, DSP_MSG_FILTER_DELAY); } } } #endif break; } default: { break; } } break; } case MESSAGE_MORE_DATA: { DEBUG(("MESSAGE_MORE_DATA\n")); /* If this is on the USB source handle it as such */ usbHidHandleInterfaceEvent(((MessageMoreData *)message)->source); break; } default: { DEBUG(("Unhandled System message 0x%X\n", (uint16)id)); break; } } }
/**************************************************************************** This function handler is called in response to an RFC_START_CFM message being sent by Bluestack. This message is sent to indicate the status of the requested RFCOMM MUX session. */ void connectionHandleRfcommStartCfm(connectionRfcommState* rfcommState, const RFC_START_CFM_T* cfm) { conn_instance* conn; bdaddr addr; connectionConvertBdaddr(&addr, &cfm->bd_addr); /* It's possible to have multiple MUX sessions being setup to different devices, therefore first get the connection instance that this message refers. At this point in the connection state machine, the only parameter that uniquely identifies this connection instance is the target Bluetooth Device Address */ conn = getRfcommConnection(&addr, INVALID_MUX_ID, INVALID_SERVER_CHANNEL); if(conn) { /* Determine the current status */ switch(cfm->result_code) { case RFC_CONNECTION_PENDING: { /* Wait for second RFC_START_CFM, if we never get this message then the RFCOMM connection timeout will expire to cancel the connection request */ conn->id.rfcomm_id.mux_id = cfm->mux_id; break; } case MUX_ALREADY_OPEN: case RFC_SUCCESS: { /* A MUX session has successfully been established or was already open, move to the parameter negotiation phase */ conn->config.rfcomm.state = parneg_phase; /* Add the mux_id */ conn->id.rfcomm_id.mux_id = cfm->mux_id; /* Initiate parameter negotiation */ startParnegPhase(conn); /* Unlock */ rfcommState->lock = 0; } break; default: { /* This indicates that Mux session establishment has failed */ sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_failed, INVALID_SERVER_CHANNEL, 0, 0); /* CAncel the watchdog timer and delete connection data */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); (void) deleteRfcommConnection(&addr, INVALID_MUX_ID, INVALID_SERVER_CHANNEL); /* Unlock */ rfcommState->lock = 0; break; } } } else { /* This indicates that a previous attempt to open a Mux has failed resulting in a timeout. We need to tear down this mux */ closeMuxSession(cfm->mux_id); } }
void connectionHandleRfcommReleaseInd(const RFC_EX_RELEASE_IND_T *ind) { /* Get the connection instance data keyed by server channel and mux id */ conn_instance *conn = getRfcommConnection(NULL, ind->mux_id, ind->server_chan); if(conn) { /* If the client application task id is valid then notify them of the connection status. If the task is not valid then we never informed the client application task that an incoming connection was active therefore they do not need to know that the attempt has been terminated for some reason */ if(conn->config.rfcomm.app_task) { /* Cancel the connection timeout */ (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_RFCOMM_CONNECT_TIMEOUT_IND); if (conn->config.rfcomm.state != disconnected) { /* Connection establishment not completed, connection failed */ if (ind->reason_code == REMOTE_REFUSAL) sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_rejected, ind->server_chan, 0, 0); else sendRfcommConnectionCfm(conn->config.rfcomm.app_task, rfcomm_connect_failed, ind->server_chan, 0, 0); if(ind->num_server_chans == 1) { /* Close down mux if we opened it */ if((ind->reason_code == RFC_SUCCESS)||(ind->reason_code == REMOTE_REFUSAL)) closeMuxSession(ind->mux_id); } } /* No longer require connection instance data */ (void) deleteRfcommConnection(NULL, ind->mux_id, ind->server_chan); } } else { /* This indicates that the connection was fully established and as we throw away connection state on successful connection establishment, we wouldn't expect to find a connection instance Check if this is the last DLC on this mux, RFC_EX_RELEASE_IND tells us how many DLC's are still open */ Sink sink; if(ind->num_server_chans == 1) { /* Close down mux if we opened it */ if(ind->reason_code == RFC_SUCCESS) { closeMuxSession(ind->mux_id); } } /* Send notification to the client application that the connection has been disconnected */ sink = StreamRfcommSink(ind->mux_id, ind->server_chan); sendRfcommDisconnectInd(MessageSinkGetTask(sink), ind->reason_code, sink); } }
/**************************************************************************** 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 ; }