/**************************************************************************** NAME configManagerUserDefinedTones DESCRIPTION Attempt to read the user configured tones, if data exists it will be in the following format: uint16 offset in array to user tone 1, uint16 offset in array to user tone ...., uint16 offset in array to user tone 8, uint16[] user tone data To play a particular tone it can be access via gVariableTones, e.g. to access tone 1 theSink.audioData.gConfigTones->gVariableTones[0] + (uint16)*theSink.audioData.gConfigTones->gVariableTones[0] or to access tone 2 theSink.audioData.gConfigTones->gVariableTones[0] + (uint16)*theSink.audioData.gConfigTones->gVariableTones[1] and so on RETURNS void */ static void configManagerUserDefinedTones( uint16 KeyLength ) { /* if the keyLength is zero there are no user tones so don't malloc any memory */ if(KeyLength) { /* malloc only enough memory to hold the configured tone data */ uint16 * configTone = mallocPanic(KeyLength * sizeof(uint16)); /* retrieve pskey data up to predetermined max size */ uint16 size_ps_key = ConfigRetrieve( theSink.config_id, PSKEY_CONFIG_TONES , configTone , KeyLength ); CONF_DEBUG(("Co : Configurable Tones Malloc size [%x]\n", KeyLength )) ; /* is there any configurable tone data, if present update pointer to tone data */ if (size_ps_key) { /* the data is in the form of 8 x uint16 audio note start offsets followed by the up to 8 lots of tone data */ theSink.conf1->gConfigTones.gVariableTones = (ringtone_note*)&configTone[0]; } /* no user configured tone data is available, so free previous malloc as not in use */ else { /* no need to waste memory */ freePanic(configTone); } } /* no tone data available, ensure data pointer is null */ else { theSink.conf1->gConfigTones.gVariableTones = NULL; } }
/**************************************************************************** NAME configManagerButtonPatterns DESCRIPTION Read and configure any buttonpattern matches that exist RETURNS */ static void configManagerButtonPatterns( void ) { /* Allocate enough memory to hold event configuration */ button_pattern_config_type* config = (button_pattern_config_type*) mallocPanic(BM_NUM_BUTTON_MATCH_PATTERNS * sizeof(button_pattern_config_type)); CONF_DEBUG(("Co: No Button Patterns - %d\n", BM_NUM_BUTTON_MATCH_PATTERNS)); /* Now read in event configuration */ if(config) { if(ConfigRetrieve(theSink.config_id , PSKEY_BUTTON_PATTERN_CONFIG, config, BM_NUM_BUTTON_MATCH_PATTERNS * sizeof(button_pattern_config_type))) { uint16 n; /* Now we have the event configuration, map required events to system events */ for(n = 0; n < BM_NUM_BUTTON_MATCH_PATTERNS ; n++) { CONF_DEBUG(("Co : AddPattern Ev[%x]\n", config[n].event )) ; /* Map PIO button event to system events in specified states */ buttonManagerAddPatternMapping ( theSink.theButtonsTask , config[n].event , config[n].pattern, n ) ; } } else { CONF_DEBUG(("Co: !EvLen\n")) ; } freePanic(config) ; } }
static void configManagerButtons( void ) { /* Allocate enough memory to hold event configuration */ event_config_type* configA = (event_config_type*) mallocPanic(BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)); event_config_type* configB = (event_config_type*) mallocPanic(BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)); event_config_type* configC = (event_config_type*) mallocPanic(BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)); uint16 n; uint8 i = 0; ConfigRetrieve(theSink.config_id , PSKEY_EVENTS_A, configA, BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)) ; ConfigRetrieve(theSink.config_id , PSKEY_EVENTS_B, configB, BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)) ; ConfigRetrieve(theSink.config_id , PSKEY_EVENTS_C, configC, BM_EVENTS_PER_PS_BLOCK * sizeof(event_config_type)) ; /* Now we have the event configuration, map required events to system events */ for(n = 0; n < BM_EVENTS_PER_PS_BLOCK; n++) { CONF_DEBUG(("Co : AddMap indexes [%u,%u] Ev[%x][%x][%x]\n", n, i, configA[n].event , configB[n].event, configC[n].event )) ; /* check to see if a valid pio mask is present, this includes the upper 2 bits of the state info as these are being used for bc5 as vreg enable and charger detect */ if ( (configA[n].pio_mask)||(configA[n].state_mask & 0xC000)) buttonManagerAddMapping ( &configA[n], i++ ); if ( (configB[n].pio_mask)||(configB[n].state_mask & 0xC000)) buttonManagerAddMapping ( &configB[n], i++ ); if ( (configC[n].pio_mask)||(configC[n].state_mask & 0xC000)) buttonManagerAddMapping ( &configC[n], i++ ); } freePanic(configA) ; freePanic(configB) ; freePanic(configC) ; /* perform an initial pio check to see if any pio changes need processing following the completion of the configuration ps key reading */ BMCheckButtonsAfterReadingConfig(); }
/**************************************************************************** NAME SetupPowerTable DESCRIPTION Attempts to obtain a low power table from the Ps Key store. If no table (or an incomplete one) is found in Ps Keys then the default is used. RETURNS void */ void SetupPowerTable( void ) { uint16 size_ps_key; power_table *PowerTable; /* obtain the size of memory in words required to hold the contents of the pskey */ size_ps_key = PsFullRetrieve(PS_HFP_POWER_TABLE, NULL, 0); /* initialise user power table */ theSink.user_power_table = 0; /* check whether any pskey data exists */ if (size_ps_key) { /* malloc storage for power table entries */ PowerTable = (power_table*)mallocPanic(size_ps_key); /* attempt to retrieve all power table entries from ps */ size_ps_key = PsFullRetrieve(PS_HFP_POWER_TABLE, PowerTable, ((sizeof(lp_power_table) * MAX_POWER_TABLE_ENTRIES) + sizeof(uint16))); /* sanity check the number of entried and length of pskey data to ensure entries are complete */ if(size_ps_key == ((sizeof(lp_power_table)*PowerTable->normalEntries)+ (sizeof(lp_power_table)*PowerTable->SCOEntries)+ (sizeof(lp_power_table)*PowerTable->A2DPStreamEntries)+ (sizeof(uint16))) ) { /* Use user defined power table */ theSink.user_power_table = PowerTable; /* pskey format is correct */ INIT_DEBUG(("User Power Table - Norm[%x] Sco[%x] Stream[%x]\n",PowerTable->normalEntries,PowerTable->SCOEntries,PowerTable->A2DPStreamEntries)); } else { /* No/incorrect power table defined in Ps Keys - use default table */ freePanic(PowerTable); PowerTable = NULL; INIT_DEBUG(("No User Power Table\n")); } } }
void configManagerInit( void ) { /* use a memory allocation for the lengths data to reduce stack usage */ lengths_config_type * keyLengths = mallocPanic(sizeof(lengths_config_type)); /* Read key lengths */ configManagerKeyLengths(keyLengths); /* Allocate the memory required for the configuration data */ InitConfigMemory(keyLengths); /* Read and configure the button translations */ configManagerButtonTranslations( ); /* Read and configure the button durations */ configManagerButtonDurations( ); /* Read the system event configuration and configure the buttons */ configManagerButtons( ); /*configures the pattern button events*/ configManagerButtonPatterns( ) ; /*Read and configure the event tones*/ configManagerEventTones( keyLengths->no_tones ) ; /* Read and configure the system features */ configManagerFeatureBlock( ); /* Read and configure the automatic switch off time*/ configManagerConfiguration( ); /* Must happen between features and session data... */ InitA2dp(); /* Read and configure the user defined tones */ configManagerUserDefinedTones( keyLengths->userTonesLength ); /* Read and configure the LEDs */ configManagerLEDS(); /* Read and configure the voume settings */ configManagerVolume( ); /* Read and configure the power management system */ configManagerPower( ); /* Read and configure the radio parameters */ configManagerRadio(); /* Read and configure the volume orientation, LED Disable state, and tts_language */ configManagerReadSessionData ( ) ; configManagerReadDspData(); /* Read and configure the sniff sub-rate parameters */ configManagerSetupSsr ( ) ; configManagerEventTTSPhrases( keyLengths->no_tts ) ; configManagerVoicePromptsInit( keyLengths->no_vp , keyLengths->no_tts_languages ); #if defined (ENABLE_REMOTE) && defined (ENABLE_SOUNDBAR) /* Read the hid remote control key mapping. */ configManagerHidkeyMap(); #endif /* don't allocate memory for AT commands if they're not required */ if (keyLengths->size_at_commands) { InitConfigMemoryAtCommands(keyLengths->size_at_commands); configManagerAtCommands(keyLengths->size_at_commands + sizeof(config_block3_t) - 1); } #ifdef ENABLE_FM /* read the fm configuration data */ configManagerReadFmData(); #endif /* release the memory used for the lengths key */ freePanic(keyLengths); }
/**************************************************************************** NAME A2dpRouteAudio DESCRIPTION attempt to connect an audio connection from a2dp device via the passed in deviceID RETURNS */ void A2dpRouteAudio(uint8 Index, Sink sink) { AUD_DEBUG(("AudioA2dpRoute Index[%x] Sink[%x]\n", Index , (uint16) sink )) ; /* ensure sink is valid before attempting the connection */ if(sink) { a2dp_codec_settings * codec_settings; AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x]\n", Index , theSink.a2dp_link_data->device_id[Index] )) ; /* get the rate information for connection */ codec_settings = A2dpCodecGetSettings(theSink.a2dp_link_data->device_id[Index], theSink.a2dp_link_data->stream_id[Index]); /* ensure stream is valid */ if(codec_settings) { AudioPluginFeatures features; AUDIO_MODE_T mode = AUDIO_MODE_CONNECTED; uint16 a2dp_gain = theSink.conf1->gVolMaps[ theSink.a2dp_link_data->gAvVolumeLevel[Index] ].A2dpGain; /* determine additional features applicable for this audio plugin */ features.stereo = theSink.features.stereo; features.use_i2s_output = theSink.features.UseI2SOutputCapability; if (theSink.conf1->gVolMaps[ theSink.a2dp_link_data->gAvVolumeLevel[Index] ].A2dpGain == VOLUME_A2DP_MUTE_GAIN) { mode = AUDIO_MODE_MUTE_SPEAKER; } else { /* must take off 1 when passing to audio plugin if not mute; 0 = MUTE, 1 = Gain 0, 2 = Gain 1, etc. */ a2dp_gain--; } /* initialise the AudioConnect extra parameters required to pass in additional codec information */ theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size = codec_settings->codecData.packet_size; /* Packet size retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.content_protection = codec_settings->codecData.content_protection; /* content protection retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch = theSink.a2dp_link_data->clockMismatchRate[Index]; /* clock mismatch rate for this device */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; /* EQ mode and Audio enhancements */ #ifdef INCLUDE_A2DP_EXTRA_CODECS #ifdef INCLUDE_FASTSTREAM theSink.a2dp_link_data->a2dp_audio_connect_params.voice_rate = codec_settings->codecData.voice_rate; /* voice rate retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.bitpool = codec_settings->codecData.bitpool; /* bitpool retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.format = codec_settings->codecData.format; /* format retrieved from a2dp library */ #endif #ifdef INCLUDE_APTX theSink.a2dp_link_data->a2dp_audio_connect_params.channel_mode = codec_settings->channel_mode; /* aptX channel mode */ #endif #ifdef INCLUDE_APTX_ACL_SPRINT theSink.a2dp_link_data->a2dp_audio_connect_params.aptx_sprint_params = codec_settings->codecData.aptx_sprint_params; /* aptX LL params */ #endif #endif #ifdef ENABLE_SOUNDBAR theSink.a2dp_link_data->seid[Index] = codec_settings->seid; #endif /* ENABLE_SOUNDBAR */ #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x] Gain[%x] Codec[%x] ClkMismatch[%x] EQ[%x] packet_size[%u]\n", Index , theSink.a2dp_link_data->device_id[Index], a2dp_gain, codec_settings->seid, theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch, (uint16)theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params, theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size)) ; audioIndicateCodec( codec_settings->seid ); #ifdef ENABLE_SOUNDBAR /* Set the LE SCAN priority to Low since we are Streaming It is possible that we might be receiving less or no LE adverts when streaming is in progress*/ InquirySetPriority(inquiry_low_priority); #endif /* ENABLE_SOUNDBAR */ /* connect the audio via the audio plugin */ AudioConnect( getA2dpPlugin(codec_settings->seid), sink , AUDIO_SINK_AV , theSink.codec_task, a2dp_gain, codec_settings->rate, features , mode, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, &theSink.task); audioControlLowPowerCodecs (FALSE) ; /* caller responsible for freeing memory */ freePanic(codec_settings); #ifdef ENABLE_AVRCP if(theSink.features.avrcp_enabled) { /* any AVRCP commands should be targeted to the device which has A2DP audio routed */ sinkAvrcpSetActiveConnection(&theSink.a2dp_link_data->bd_addr[Index]); } #endif } /* update the current sink being routed */ theSink.routed_audio = sink; } }
/**************************************************************************** NAME A2dpRouteAudio DESCRIPTION attempt to connect an audio connection from a2dp device via the passed in deviceID RETURNS */ void A2dpRouteAudio(uint8 Index, Sink sink) { AUD_DEBUG(("AudioA2dpRoute Index[%x] Sink[%x]\n", Index , (uint16) sink )) ; /* ensure sink is valid before attempting the connection */ if(sink) { /* Use an instance of A2DP message structure for initial volume setting */ AUDIO_PLUGIN_SET_VOLUME_A2DP_MSG_T volumeInitAudio; a2dp_codec_settings * codec_settings; AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x]\n", Index , theSink.a2dp_link_data->device_id[Index] )) ; /* get the rate information for connection */ codec_settings = A2dpCodecGetSettings(theSink.a2dp_link_data->device_id[Index], theSink.a2dp_link_data->stream_id[Index]); /* ensure stream is valid */ if(codec_settings) { AUDIO_MODE_T mode = AUDIO_MODE_CONNECTED; int16 a2dp_gain_dB; /* determine additional features applicable for this audio plugin */ /* Volume info is sent to DSP in dB units */ a2dp_gain_dB = VolumeConvertStepsToDB(theSink.volume_levels->a2dp_volume[Index].masterVolume, &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); /* check for MUTE volume level and mute as appropriate */ if (theSink.volume_levels->a2dp_volume[Index].masterVolume == VOLUME_A2DP_MUTE_GAIN) { mode = AUDIO_MODE_MUTE_SPEAKER; } /* initialise the AudioConnect extra parameters required to pass in additional codec information */ if (codec_settings->codecData.latency_reporting) /* latency reporting retrieved from a2dp library */ { /* TODO: obtain settings from PS, probably based on codec type */ theSink.a2dp_link_data->a2dp_audio_connect_params.latency.last = 150; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.target = 150/5; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.change = 10/5; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.period = 500/100; } theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size = codec_settings->codecData.packet_size; /* Packet size retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.content_protection = codec_settings->codecData.content_protection; /* content protection retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch = theSink.a2dp_link_data->clockMismatchRate[Index]; /* clock mismatch rate for this device */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; /* EQ mode and Audio enhancements */ #ifdef INCLUDE_A2DP_EXTRA_CODECS #ifdef INCLUDE_FASTSTREAM theSink.a2dp_link_data->a2dp_audio_connect_params.voice_rate = codec_settings->codecData.voice_rate; /* voice rate retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.bitpool = codec_settings->codecData.bitpool; /* bitpool retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.format = codec_settings->codecData.format; /* format retrieved from a2dp library */ #endif #ifdef INCLUDE_APTX theSink.a2dp_link_data->a2dp_audio_connect_params.channel_mode = codec_settings->channel_mode; /* aptX channel mode */ #endif #ifdef INCLUDE_APTX_ACL_SPRINT theSink.a2dp_link_data->a2dp_audio_connect_params.aptx_sprint_params = codec_settings->codecData.aptx_sprint_params; /* aptX LL params */ #endif #endif #ifdef ENABLE_SOUNDBAR theSink.a2dp_link_data->seid[Index] = codec_settings->seid; #endif /* ENABLE_SOUNDBAR */ #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x] Gain[%x] Codec[%x] ClkMismatch[%x] EQ[%x] packet_size[%u]\n", Index , theSink.a2dp_link_data->device_id[Index], a2dp_gain_dB, codec_settings->seid, theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch, (uint16)theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params, theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size)) ; audioIndicateCodec( codec_settings->seid ); #ifdef ENABLE_SOUNDBAR /* Set the LE SCAN priority to Low since we are Streaming It is possible that we might be receiving less or no LE adverts when streaming is in progress*/ InquirySetPriority(inquiry_low_priority); #endif /* ENABLE_SOUNDBAR */ /* We need to set A2DP volume info as the audio is in mute state after connection */ volumeInitAudio.volume_type = theSink.conf1->volume_config.volume_control_config.volume_type; volumeInitAudio.codec_task = theSink.codec_task; volumeInitAudio.master_gain = a2dp_gain_dB; volumeInitAudio.system_gain = theSink.conf1->volume_config.volume_control_config.system_volume; volumeInitAudio.trim_gain_left = theSink.conf1->volume_config.volume_control_config.trim_volume_left; volumeInitAudio.trim_gain_right= theSink.conf1->volume_config.volume_control_config.trim_volume_right; volumeInitAudio.device_trim_master = theSink.conf1->volume_config.volume_control_config.device_trim_master; volumeInitAudio.device_trim_slave = theSink.conf1->volume_config.volume_control_config.device_trim_slave; volumeInitAudio.tones_gain = VolumeConvertStepsToDB(((TonesGetToneVolume(FALSE) * theSink.conf1->volume_config.volume_control_config.no_of_steps)/VOLUME_NUM_VOICE_STEPS), &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); volumeInitAudio.mute_active = theSink.sink_enable_present; /* connect the audio via the audio plugin */ AudioConnect(getA2dpPlugin(codec_settings->seid), sink , AUDIO_SINK_AV , theSink.codec_task, volumeInitAudio.tones_gain, codec_settings->rate, theSink.conf2->audio_routing_data.PluginFeatures , mode, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, FALSE, &theSink.task); AudioSetVolumeA2DP(&volumeInitAudio); #ifdef ENABLE_SUBWOOFER /* set subwoofer volume level */ updateSwatVolume(theSink.volume_levels->a2dp_volume[Index].masterVolume); SWAT_DEBUG(("SW : Send sample rate to Sub, rate is %ld\n",codec_settings->rate)); /* send sample rate to sub */ sendSampleRateToSub(codec_settings->rate); #endif audioControlLowPowerCodecs (FALSE) ; /* caller responsible for freeing memory */ freePanic(codec_settings); #ifdef ENABLE_AVRCP if(theSink.features.avrcp_enabled) { UpdateAvrpcMessage_t * lUpdateMessage = mallocPanic ( sizeof(UpdateAvrpcMessage_t) ) ; lUpdateMessage->bd_addr = theSink.a2dp_link_data->bd_addr[Index]; /* any AVRCP commands should be targeted to the device which has A2DP audio routed */ MessageSend( &theSink.task, EventSysSetActiveAvrcpConnection, lUpdateMessage); } #endif } /* update the current sink being routed */ theSink.routed_audio = sink; } }
/**************************************************************************** NAME mapcHandleServiceSearchAttributeCfm DESCRIPTION confirmation of the service search for MAP support, if successful the app will progress and attempt to connect to the message access service PARAMS @cfm message RETURNS void */ void mapcHandleServiceSearchAttributeCfm( const CL_SDP_SERVICE_SEARCH_ATTRIBUTE_CFM_T *cfm) { uint8 *rfcomm_channels; uint8 size_rfcomm_channels = 1; uint8 channels_found = 0; mapcState *state = NULL; mapc_link_priority device_id = mapcGetLinkFromBdAddr( &cfm->bd_addr ); /* ensure device_id has been correctly retrieved */ if(device_id != mapc_invalid_link) state = &(theSink.rundata->mapc_data.state[device_id]); /* if the service search has been successful, parse returned entries */ if(cfm->status == sdp_response_success) { MAPC_DEBUG(("MAPC:\tReceived SDP Response of length %d\n", cfm->size_attributes)); rfcomm_channels = mallocPanic(size_rfcomm_channels * sizeof(uint8)); /* parse all returned reports */ if (SdpParseGetMultipleRfcommServerChannels( cfm->size_attributes, (uint8*)cfm->attributes, 1, &rfcomm_channels, &channels_found) ) { /* If receiving multiple responses, the first record will be stored in this application */ if(state) { state->masChannel = rfcomm_channels[0]; state->bdAddr = cfm->bd_addr; state->device_state = mapc_sdp_searched; /* set the link security requirements */ ConnectionSmSetSdpSecurityOut(TRUE, &cfm->bd_addr); ConnectionSmRegisterOutgoingService(&theSink.task, &cfm->bd_addr, protocol_rfcomm, state->masChannel, sec4_out_level_2); /* attempt to connect the message access service */ MapcMasConnectRequest( &theSink.task, &cfm->bd_addr, state->masChannel ); } } /* no channels were found, there reset the state of this connection */ else { if(state) state->device_state = mapc_state_idle; MAPC_DEBUG(("MAPC:NO Channels found\n")); } /* ensure memory used in sdp record parsing is free'd */ freePanic(rfcomm_channels); } /* the sdp record search was not successful, no further action needs to be taken */ else { /* reset current connection state so that it can be reused */ if(state) state->device_state = mapc_state_idle; MAPC_DEBUG(("MAPC:SDP Search Failed. Status = %x, more = %x, error = %x \n", cfm->status, cfm->more_to_come, cfm->error_code)); } }
/**************************************************************************** NAME sinkWriteEirData DESCRIPTION Writes the local name, inquiry tx power and device UUIDs into device EIR data RETURNS void */ void sinkWriteEirData( CL_DM_LOCAL_NAME_COMPLETE_T *message ) { uint16 size_uuids = 0; uint16 size = 0; uint8 *eir = NULL; uint8 *p = NULL; /* Determine length of EIR data */ size_uuids = SIZE_A2DP_UUIDS + SIZE_AVRCP_UUIDS + SIZE_PBAP_UUIDS + SIZE_HFP_UUIDS + SIZE_HSP_UUIDS; size = GetDeviceIdEirDataSize() + EIR_BLOCK_SIZE(EIR_DATA_SIZE_FULL(size_uuids) + EIR_DATA_SIZE_FULL(message->size_local_name) + EIR_DATA_SIZE_FULL(sizeof(uint8))); /* Allocate space for EIR data */ eir = (uint8 *)mallocPanic(size * sizeof(uint8)); p = eir; /* Device Id Record */ p += WriteDeviceIdEirData( p ); /* Inquiry Tx Field */ *p++ = EIR_DATA_SIZE(sizeof(int8)); *p++ = EIR_TYPE_INQUIRY_TX; *p++ = theSink.inquiry_tx; /* UUID16 field */ *p++ = EIR_DATA_SIZE(size_uuids); *p++ = EIR_TYPE_UUID16_PARTIAL; if(theSink.features.EnableA2dpStreaming) { memmove(p, a2dp_uuids, sizeof(a2dp_uuids)); p += sizeof(a2dp_uuids); } #ifdef ENABLE_AVRCP if (theSink.features.avrcp_enabled) { memmove(p, avrcp_uuids, sizeof(avrcp_uuids)); p += sizeof(avrcp_uuids); } #endif #ifdef ENABLE_PBAP if (theSink.features.pbap_enabled) { memmove(p, pbap_uuids, sizeof(pbap_uuids)); p += sizeof(pbap_uuids); } #endif if(theSink.hfp_profiles & hfp_handsfree_all) { memmove(p, hfp_uuids, sizeof(hfp_uuids)); p += sizeof(hfp_uuids); } if(theSink.hfp_profiles & hfp_headset_all) { memmove(p, hsp_uuids, sizeof(hsp_uuids)); p += sizeof(hsp_uuids); } /* Device Name Field */ *p++ = EIR_DATA_SIZE(message->size_local_name); *p++ = EIR_TYPE_LOCAL_NAME_COMPLETE; memmove(p, message->local_name, message->size_local_name); p += message->size_local_name; /* NULL Termination */ *p++ = 0x00; /* Register and free EIR data */ ConnectionWriteEirData(FALSE, size, eir); freePanic(eir); }
/**************************************************************************** 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())); } }