Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1849ba7 authored by Preetam Singh Ranawat's avatar Preetam Singh Ranawat Committed by Haynes Mathew George
Browse files

hal: Add a2dp state check for device routing

- During a2dp to sco transition multiple session
  open failures are seen due to a2dp start failure

- Check a2dp streaming state with BT lib before
  routing audio on a2dp device.
  If a2dp is not ready for streaming, force drop
  audio packets for a2dp path similar to BT HAL

Change-Id: If9fdd2184943c2e25a091067477cf0bcc5dce278
parent 3916bfe8
Loading
Loading
Loading
Loading
+23 −19
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ typedef void (*audio_handoff_triggered_t)(void);
typedef void (*clear_a2dpsuspend_flag_t)(void);
typedef void * (*audio_get_codec_config_t)(uint8_t *multicast_status,uint8_t *num_dev,
                               audio_format_t *codec_type);
typedef int (*audio_check_a2dp_ready_t)(void);

enum A2DP_STATE {
    A2DP_STATE_CONNECTED,
@@ -102,6 +103,7 @@ struct a2dp_data {
    audio_handoff_triggered_t audio_handoff_triggered;
    clear_a2dpsuspend_flag_t clear_a2dpsuspend_flag;
    audio_get_codec_config_t audio_get_codec_config;
    audio_check_a2dp_ready_t audio_check_a2dp_ready;
    enum A2DP_STATE bt_state;
    audio_format_t bt_encoder_format;
    uint32_t enc_sampling_rate;
@@ -244,6 +246,8 @@ static void open_a2dp_output()
                          dlsym(a2dp.bt_lib_handle, "audio_stop_stream");
            a2dp.audio_stream_close = (audio_stream_close_t)
                          dlsym(a2dp.bt_lib_handle, "audio_stream_close");
            a2dp.audio_check_a2dp_ready = (audio_check_a2dp_ready_t)
                        dlsym(a2dp.bt_lib_handle,"audio_check_a2dp_ready");
        }
    }

@@ -279,27 +283,17 @@ static int close_a2dp_output()
        ALOGE("a2dp handle is not identified, Ignoring close request");
        return -ENOSYS;
    }
    if ((a2dp.bt_state == A2DP_STATE_CONNECTED) &&
        (a2dp.bt_state == A2DP_STATE_STARTED) &&
        (a2dp.bt_state == A2DP_STATE_STOPPED)) {
    if (a2dp.bt_state != A2DP_STATE_DISCONNECTED) {
        ALOGD("calling BT stream close");
        if(a2dp.audio_stream_close() == false)
            ALOGE("failed close a2dp control path from BT library");
    }
    a2dp.a2dp_started = false;
    a2dp.a2dp_total_active_session_request = 0;
    a2dp.a2dp_suspended = false;
    a2dp.bt_encoder_format = AUDIO_FORMAT_INVALID;
    a2dp.enc_sampling_rate = 48000;
    a2dp.bt_state = A2DP_STATE_DISCONNECTED;
    } else {
        ALOGD("close a2dp called in improper state");
        a2dp.a2dp_started = false;
        a2dp.a2dp_total_active_session_request = 0;
        a2dp.a2dp_suspended = false;
        a2dp.bt_encoder_format = AUDIO_FORMAT_INVALID;
        a2dp.enc_sampling_rate = 48000;
        a2dp.bt_state = A2DP_STATE_DISCONNECTED;
    }

    return 0;
}
@@ -631,7 +625,6 @@ int audio_extn_a2dp_start_playback()
        if (ret != 0 ) {
           ALOGE("BT controller start failed");
           a2dp.a2dp_started = false;
           ret = -ETIMEDOUT;
        } else {
           if(configure_a2dp_encoder_format() == true) {
                a2dp.a2dp_started = true;
@@ -692,7 +685,7 @@ int audio_extn_a2dp_stop_playback()
        return -ENOSYS;
    }

    if (a2dp.a2dp_started && (a2dp.a2dp_total_active_session_request > 0))
    if (a2dp.a2dp_total_active_session_request > 0)
        a2dp.a2dp_total_active_session_request--;

    if ( a2dp.a2dp_started && !a2dp.a2dp_total_active_session_request) {
@@ -810,6 +803,17 @@ void audio_extn_a2dp_get_apptype_params(uint32_t *sample_rate,
        *bit_width = 16;
    *sample_rate = a2dp.enc_sampling_rate;
}

bool audio_extn_a2dp_is_ready()
{
    bool ret = false;

    if ((a2dp.is_a2dp_offload_supported) &&
        (a2dp.audio_check_a2dp_ready))
           ret = a2dp.audio_check_a2dp_ready();
    return ret;
}

void audio_extn_a2dp_init (void *adev)
{
  a2dp.adev = (struct audio_device*)adev;
+2 −2
Original line number Diff line number Diff line
@@ -206,7 +206,7 @@ bool audio_extn_usb_is_capture_supported();
#define audio_extn_a2dp_set_handoff_mode(is_on)          (0)
#define audio_extn_a2dp_get_apptype_params(sample_rate,bit_width)    (0)
#define audio_extn_a2dp_get_encoder_latency()            (0)

#define audio_extn_a2dp_is_ready()                       (0)
#else
void audio_extn_a2dp_init(void *adev);
int audio_extn_a2dp_start_playback();
@@ -217,7 +217,7 @@ void audio_extn_a2dp_set_handoff_mode(bool is_on);
void audio_extn_a2dp_get_apptype_params(uint32_t *sample_rate,
                                        uint32_t *bit_width);
uint32_t audio_extn_a2dp_get_encoder_latency();

bool audio_extn_a2dp_is_ready();
#endif

#ifndef SSR_ENABLED
+33 −10
Original line number Diff line number Diff line
@@ -2185,6 +2185,19 @@ int start_output_stream(struct stream_out *out)
        goto error_config;
    }

    if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
        if (!audio_extn_a2dp_is_ready()) {
            if (out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
                //combo usecase just by pass a2dp
                ALOGW("%s: A2DP profile is not ready, route it to speaker", __func__);
                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
            } else {
                ALOGE("%s: A2DP profile is not ready, return error", __func__);
                ret = -EAGAIN;
                goto error_config;
            }
        }
    }
    out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
    if (out->pcm_device_id < 0) {
        ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
@@ -2647,17 +2660,27 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
                (val == AUDIO_DEVICE_NONE)) {
                val = AUDIO_DEVICE_OUT_SPEAKER;
        }
        /* To avoid a2dp to sco overlapping force route BT usecases
         * to speaker based on Phone state
        /* To avoid a2dp to sco overlapping / BT device improper state
         * check with BT lib about a2dp streaming support before routing
         */
        if ((((val & AUDIO_DEVICE_OUT_SPEAKER) &&
                  (val & AUDIO_DEVICE_OUT_ALL_A2DP)) ||
              ((adev->snd_dev_ref_cnt[SND_DEVICE_OUT_BT_A2DP] == 0) &&
                  (val & AUDIO_DEVICE_OUT_ALL_A2DP))) &&
            ((adev->mode == AUDIO_MODE_RINGTONE) ||
            (adev->mode == AUDIO_MODE_IN_CALL))) {
            ALOGD("Forcing a2dp routing to speaker for ring/call mode");
        if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
            if (!audio_extn_a2dp_is_ready()) {
                if (val & AUDIO_DEVICE_OUT_SPEAKER) {
                    //combo usecase just by pass a2dp
                    ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
                    val = AUDIO_DEVICE_OUT_SPEAKER;
                } else {
                    ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
                    /* update device to a2dp and don't route as BT returned error
                     * However it is still possible a2dp routing called because
                     * of current active device disconnection (like wired headset)
                     */
                    out->devices = val;
                    pthread_mutex_unlock(&out->lock);
                    pthread_mutex_unlock(&adev->lock);
                    goto error;
                }
            }
        }
        /*
         * select_devices() call below switches all the usecases on the same