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

Commit 1f88a062 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "hal: select phone call snd device when audio recording with usb headset"

parents 256ce19b 8a6aaf36
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -5485,6 +5485,11 @@ typedef void (*maxxaudio_set_parameters_t)(struct audio_device *,
                                  struct str_parms *);
static maxxaudio_set_parameters_t maxxaudio_set_parameters;

typedef void (*maxxaudio_get_parameters_t)(struct audio_device *,
                                  struct str_parms *,
                                  struct str_parms *);
static maxxaudio_get_parameters_t maxxaudio_get_parameters;

typedef bool (*maxxaudio_supported_usb_t)();
static maxxaudio_supported_usb_t maxxaudio_supported_usb;

@@ -5512,6 +5517,8 @@ int maxx_audio_feature_init(bool is_feature_enabled)
                 (maxxaudio_set_device_t)dlsym(maxxaudio_lib_handle, "ma_set_device")) ||
            !(maxxaudio_set_parameters =
                 (maxxaudio_set_parameters_t)dlsym(maxxaudio_lib_handle, "ma_set_parameters")) ||
            !(maxxaudio_get_parameters =
                 (maxxaudio_get_parameters_t)dlsym(maxxaudio_lib_handle, "ma_get_parameters")) ||
            !(maxxaudio_supported_usb =
                 (maxxaudio_supported_usb_t)dlsym(
                                    maxxaudio_lib_handle, "ma_supported_usb"))) {
@@ -5533,6 +5540,7 @@ feature_disabled:
    maxxaudio_set_state = NULL;
    maxxaudio_set_device = NULL;
    maxxaudio_set_parameters = NULL;
    maxxaudio_get_parameters = NULL;
    maxxaudio_supported_usb = NULL;
    ALOGW(":: %s: ---- Feature MAXX_AUDIO is disabled ----", __func__);
    return -ENOSYS;
@@ -5580,6 +5588,14 @@ void audio_extn_ma_set_parameters(struct audio_device *adev,
        maxxaudio_set_parameters(adev, parms);
}

void audio_extn_ma_get_parameters(struct audio_device *adev,
                                  struct str_parms *query,
                                  struct str_parms *reply)
{
    if (maxxaudio_get_parameters)
        maxxaudio_get_parameters(adev, query, reply);
}

bool audio_extn_ma_supported_usb()
{
    return (maxxaudio_supported_usb ? maxxaudio_supported_usb(): false);
+3 −0
Original line number Diff line number Diff line
@@ -361,6 +361,9 @@ bool audio_extn_ma_set_state(struct audio_device *adev, int stream_type,
void audio_extn_ma_set_device(struct audio_usecase *usecase);
void audio_extn_ma_set_parameters(struct audio_device *adev,
                                  struct str_parms *parms);
void audio_extn_ma_get_parameters(struct audio_device *adev,
                                  struct str_parms *query,
                                  struct str_parms *reply);
bool audio_extn_ma_supported_usb();
bool audio_extn_is_maxx_audio_enabled();
// --- Function pointers from audio_extn needed by MAXX_AUDIO
+176 −57
Original line number Diff line number Diff line
@@ -50,10 +50,14 @@
#define MA_QDSP_SET_VOL         "maxxaudio_qdsp_set_volume"
#define MA_QDSP_SET_VOLT        "maxxaudio_qdsp_set_volume_table"
#define MA_QDSP_SET_PARAM       "maxxaudio_qdsp_set_parameter"
#define MA_QDSP_SET_COMMAND     "maxxaudio_qdsp_set_command"
#define MA_QDSP_GET_COMMAND     "maxxaudio_qdsp_get_command"

#define SUPPORT_DEV "18d1:5033" // Blackbird usbid
#define SUPPORTED_USB 0x01

#define WAVES_COMMAND_SIZE 10240

typedef unsigned int effective_scope_flag_t;
const effective_scope_flag_t EFFECTIVE_SCOPE_RTC = 1 << 0;   /* RTC  */
const effective_scope_flag_t EFFECTIVE_SCOPE_ACDB = 1 << 1;  /* ACDB */
@@ -145,6 +149,16 @@ typedef bool (*ma_set_param_t)(ma_audio_cal_handle_t,
                               const struct ma_audio_cal_settings *,
                               unsigned int, double);

typedef bool (*ma_set_cmd_t)(ma_audio_cal_handle_t handle,
                             const struct ma_audio_cal_settings *,
                             const char*);

typedef bool (*ma_get_cmd_t)(ma_audio_cal_handle_t handle,
                             const struct ma_audio_cal_settings *,
                             const char *,
                             char *,
                             uint32_t);

struct ma_platform_data {
    void *waves_handle;
    void *platform;
@@ -158,6 +172,8 @@ struct ma_platform_data {
    ma_set_volume_t          ma_set_volume;
    ma_set_volume_table_t    ma_set_volume_table;
    ma_set_param_t           ma_set_param;
    ma_set_cmd_t             ma_set_cmd;
    ma_get_cmd_t             ma_get_cmd;
    bool speaker_lr_swap;
    bool orientation_used;
    int dispaly_orientation;
@@ -167,6 +183,9 @@ ma_audio_cal_handle_t g_ma_audio_cal_handle = NULL;
static uint16_t g_supported_dev = 0;
static struct ma_state ma_cur_state_table[STREAM_MAX_TYPES];
static struct ma_platform_data *my_data = NULL;
static char ma_command_data[WAVES_COMMAND_SIZE];
static char ma_reply_data[WAVES_COMMAND_SIZE];

// --- external function dependency ---
fp_platform_set_parameters_t fp_platform_set_parameters;
fp_audio_extn_get_snd_card_split_t fp_audio_extn_get_snd_card_split;
@@ -276,7 +295,6 @@ static void ma_cal_init(struct ma_audio_cal_settings *ma_cal)

static bool check_and_send_all_audio_cal(struct audio_device *adev, ma_cmd_t cmd)
{
    int i = 0;
    bool ret = false;
    struct listnode *node;
    struct audio_usecase *usecase;
@@ -481,15 +499,14 @@ void ma_init(void *platform, maxx_audio_init_config_t init_config)
    } else {
        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_MA_PARAM);

         my_data->ma_param_init = (ma_param_init_t)dlsym(my_data->waves_handle,
                                   MA_QDSP_PARAM_INIT);
        my_data->ma_param_init = (ma_param_init_t)dlsym(my_data->waves_handle, MA_QDSP_PARAM_INIT);
        if (!my_data->ma_param_init) {
            ALOGE("%s: dlsym error %s for ma_param_init", __func__, dlerror());
            goto error;
        }

         my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(
                                     my_data->waves_handle, MA_QDSP_PARAM_DEINIT);
        my_data->ma_param_deinit = (ma_param_deinit_t)dlsym(my_data->waves_handle,
                                                            MA_QDSP_PARAM_DEINIT);
        if (!my_data->ma_param_deinit) {
            ALOGE("%s: dlsym error %s for ma_param_deinit", __func__, dlerror());
            goto error;
@@ -514,33 +531,41 @@ void ma_init(void *platform, maxx_audio_init_config_t init_config)
            goto error;
        }

         my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(
                                       my_data->waves_handle, MA_QDSP_SET_MODE);
        my_data->ma_set_sound_mode = (ma_set_sound_mode_t)dlsym(my_data->waves_handle,
                                                                MA_QDSP_SET_MODE);
        if (!my_data->ma_set_sound_mode) {
            ALOGE("%s: dlsym error %s for ma_set_sound_mode", __func__, dlerror());
            goto error;
        }

         my_data->ma_set_volume = (ma_set_volume_t)dlsym(my_data->waves_handle,
                                   MA_QDSP_SET_VOL);
        my_data->ma_set_volume = (ma_set_volume_t)dlsym(my_data->waves_handle, MA_QDSP_SET_VOL);
        if (!my_data->ma_set_volume) {
            ALOGE("%s: dlsym error %s for ma_set_volume", __func__, dlerror());
            goto error;
        }

         my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(
                                         my_data->waves_handle, MA_QDSP_SET_VOLT);
        my_data->ma_set_volume_table = (ma_set_volume_table_t)dlsym(my_data->waves_handle,
                                                                    MA_QDSP_SET_VOLT);
        if (!my_data->ma_set_volume_table) {
            ALOGE("%s: dlsym error %s for ma_set_volume_table", __func__, dlerror());
            goto error;
        }

         my_data->ma_set_param = (ma_set_param_t)dlsym(
                                  my_data->waves_handle, MA_QDSP_SET_PARAM);
        my_data->ma_set_param = (ma_set_param_t)dlsym(my_data->waves_handle, MA_QDSP_SET_PARAM);
        if (!my_data->ma_set_param) {
            ALOGE("%s: dlsym error %s for ma_set_param", __func__, dlerror());
            goto error;
        }

        my_data->ma_set_cmd = (ma_set_cmd_t)dlsym(my_data->waves_handle, MA_QDSP_SET_COMMAND);
        if (!my_data->ma_set_cmd) {
            ALOGE("%s: dlsym error %s for ma_set_cmd", __func__, dlerror());
        }

        my_data->ma_get_cmd = (ma_get_cmd_t)dlsym(my_data->waves_handle, MA_QDSP_GET_COMMAND);
        if (!my_data->ma_get_cmd) {
            ALOGE("%s: dlsym error %s for ma_get_cmd", __func__, dlerror());
        }
    }

    /* get preset table */
@@ -679,7 +704,6 @@ bool ma_set_state(struct audio_device *adev, int stream_type,

void ma_set_device(struct audio_usecase *usecase)
{
    int i = 0;
    struct ma_audio_cal_settings ma_cal;

    if (!my_data) {
@@ -731,8 +755,101 @@ void ma_set_device(struct audio_usecase *usecase)
    pthread_mutex_unlock(&my_data->lock);
}

void ma_set_parameters(struct audio_device *adev,
                                  struct str_parms *parms)
static bool ma_set_command(struct ma_audio_cal_settings *audio_cal_settings, char *cmd_data)
{
    if (my_data->ma_set_cmd)
        return my_data->ma_set_cmd(g_ma_audio_cal_handle, audio_cal_settings, cmd_data);
    return false;
}

static bool ma_get_command(struct ma_audio_cal_settings *audio_cal_settings, char *cmd_data,
                           char *reply_data, uint32_t reply_size)
{
    if (my_data->ma_get_cmd)
        return my_data->ma_get_cmd(g_ma_audio_cal_handle, audio_cal_settings, cmd_data, reply_data,
                                   reply_size);
    return false;
}

static bool ma_fill_apptype_and_device_from_params(struct str_parms *parms, uint32_t *app_type,
                                                   struct listnode *devices)
{
    int ret;
    char value[128];

    ret = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));

    if (ret >= 0) {
        *app_type = (uint32_t)atoi(value);
        ret = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
        if (ret >= 0) {
            update_device_list(devices, (uint32_t)atoi(value), "", true);
            return true;
        }
    }
    return false;
}

static bool ma_add_apptype_and_device_to_params(struct str_parms *parms, uint32_t app_type,
                                                struct listnode *devices)
{
    if (0 <= str_parms_add_int(parms, "cal_apptype", app_type)) {
        if (0 <= str_parms_add_int(parms, "cal_devid", get_device_types(devices))) {
            return true;
        }
    }
    return false;
}

static bool ma_get_command_parameters(struct str_parms *query, struct str_parms *reply)
{
    struct ma_audio_cal_settings ma_cal;
    int ret;

    ret = str_parms_get_str(query, "waves_data", ma_command_data, sizeof(ma_command_data));
    if (ret >= 0) {
        ma_cal_init(&ma_cal);
        if (ma_fill_apptype_and_device_from_params(query, &ma_cal.common.app_type,
                &ma_cal.common.devices)) {
            ma_add_apptype_and_device_to_params(reply, ma_cal.common.app_type,
                                                &ma_cal.common.devices);
            ALOGV("%s: before - command=%s", __func__, (char *)ma_command_data);
            if (ma_get_command(&ma_cal, ma_command_data, ma_reply_data, sizeof(ma_reply_data))) {
                str_parms_add_str(reply, "waves_data", ma_reply_data);
                ALOGV("%s: after - command=%s", __func__, (char *)ma_reply_data);
                return true;
            } else {
                str_parms_add_str(reply, "waves_data", "");
            }
        }
    }
    return false;
}

static bool ma_set_command_parameters(struct str_parms *parms)
{
    struct ma_audio_cal_settings ma_cal;
    int ret;

    ret = str_parms_get_str(parms, "waves_data", ma_command_data, sizeof(ma_command_data));
    if (ret >= 0) {
        ma_cal_init(&ma_cal);
        if (ma_fill_apptype_and_device_from_params(parms, &ma_cal.common.app_type,
                &ma_cal.common.devices)) {
            return ma_set_command(&ma_cal, ma_command_data);
        }
    }
    return false;
}

void ma_get_parameters(struct audio_device *adev, struct str_parms *query,
                       struct str_parms *reply)
{
    (void)adev;
    ma_get_command_parameters(query, reply);
}

void ma_set_parameters(struct audio_device *adev, struct str_parms *parms)
{
    int ret;
    int val;
@@ -791,6 +908,8 @@ void ma_set_parameters(struct audio_device *adev,
            }
        }
    }

    ma_set_command_parameters(parms);
}

bool ma_supported_usb()
+80 −5
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@
#include <hardware/audio_alsaops.h>
#include <system/thread_defs.h>
#include <tinyalsa/asoundlib.h>
#include <utils/Timers.h> // systemTime
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include <audio_utils/format.h>
@@ -2642,7 +2643,11 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
                                 is_single_device_type_equal(&vc_usecase->device_list,
                                                        AUDIO_DEVICE_OUT_HEARING_AID) ||
                                 is_single_device_type_equal(&usecase->device_list,
                                                     AUDIO_DEVICE_IN_VOICE_CALL))) {
                                                     AUDIO_DEVICE_IN_VOICE_CALL) ||
                                 (is_single_device_type_equal(&usecase->device_list,
                                                     AUDIO_DEVICE_IN_USB_HEADSET) &&
                                 is_single_device_type_equal(&vc_usecase->device_list,
                                                        AUDIO_DEVICE_OUT_USB_HEADSET)))) {
                in_snd_device = vc_usecase->in_snd_device;
                out_snd_device = vc_usecase->out_snd_device;
            }
@@ -4549,6 +4554,17 @@ static int out_dump(const struct audio_stream *stream, int fd)
    dprintf(fd, "      Standby: %s\n", out->standby ? "yes" : "no");
    dprintf(fd, "      Frames written: %lld\n", (long long)out->written);

    char buffer[256]; // for statistics formatting
    if (!is_offload_usecase(out->usecase)) {
        simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
        dprintf(fd, "      Fifo frame underruns: %s\n", buffer);
    }

    if (out->start_latency_ms.n > 0) {
        simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
        dprintf(fd, "      Start latency ms: %s\n", buffer);
    }

    if (locked) {
        pthread_mutex_unlock(&out->lock);
    }
@@ -5705,6 +5721,8 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,

    if (out->standby) {
        out->standby = false;
        const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);

        pthread_mutex_lock(&adev->lock);
        if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
            ret = voice_extn_compress_voip_start_output_stream(out);
@@ -5717,6 +5735,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
            goto exit;
        }
        out->started = 1;
        out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
        if (last_known_cal_step != -1) {
            ALOGD("%s: retry previous failed cal level set", __func__);
            audio_hw_send_gain_dep_calibration(last_known_cal_step);
@@ -5731,6 +5750,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
        }
        if (out->set_dual_mono)
            audio_extn_send_dual_mono_mixing_coefficients(out);

        // log startup time in ms.
        simple_stats_log(
                &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
    }

    if (adev->is_channel_status_set == false &&
@@ -5885,6 +5908,30 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
                    bytes_to_write /= 2;
                }
            }

            // Note: since out_get_presentation_position() is called alternating with out_write()
            // by AudioFlinger, we can check underruns using the prior timestamp read.
            // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
            if (out->last_fifo_valid) {
                // compute drain to see if there is an underrun.
                const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
                const int64_t frames_by_time =
                        (current_ns - out->last_fifo_time_ns) * out->config.rate / NANOS_PER_SECOND;
                const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;

                if (underrun > 0) {
                    simple_stats_log(&out->fifo_underruns, underrun);

                    ALOGW("%s: underrun(%lld) "
                            "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
                            __func__,
                            (long long)out->fifo_underruns.n,
                            (long long)frames_by_time,
                            (long long)out->last_fifo_frames_remaining);
                }
                out->last_fifo_valid = false;  // we're writing below, mark fifo info as stale.
            }

            ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);

            long ns = 0;
@@ -6114,15 +6161,26 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
        if (out->pcm) {
            unsigned int avail;
            if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
                size_t kernel_buffer_size = out->config.period_size * out->config.period_count;

                uint64_t signed_frames = 0;
                uint64_t frames_temp = 0;

                frames_temp = (kernel_buffer_size > avail) ? (kernel_buffer_size - avail) : 0;
                if (out->kernel_buffer_size > avail) {
                    frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
                } else {
                    ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
                            __func__, avail, out->kernel_buffer_size);
                    avail = out->kernel_buffer_size;
                    frames_temp = out->last_fifo_frames_remaining = 0;
                }
                out->last_fifo_valid = true;
                out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);

                if (out->written >= frames_temp)
                    signed_frames = out->written - frames_temp;

                ALOGVV("%s: frames:%lld  avail:%u  kernel_buffer_size:%zu",
                        __func__, (long long)signed_frames, avail, out->kernel_buffer_size);

                // This adjustment accounts for buffering after app processor.
                // It is based on estimated DSP latency per use case, rather than exact.
                frames_temp = platform_render_latency(out->usecase) * out->sample_rate / 1000000LL;
@@ -6141,7 +6199,9 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
                *frames = signed_frames;
                ret = 0;
            }
        } else if (out->card_status == CARD_STATUS_OFFLINE) {
        } else if (out->card_status == CARD_STATUS_OFFLINE ||
            // audioflinger still needs position updates when A2DP is suspended
            (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
            *frames = out->written;
            clock_gettime(CLOCK_MONOTONIC, timestamp);
            if (is_offload_usecase(out->usecase))
@@ -6609,6 +6669,12 @@ static int in_dump(const struct audio_stream *stream,
    dprintf(fd, "      Frames read: %lld\n", (long long)in->frames_read);
    dprintf(fd, "      Frames muted: %lld\n", (long long)in->frames_muted);

    char buffer[256]; // for statistics formatting
    if (in->start_latency_ms.n > 0) {
        simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
        dprintf(fd, "      Start latency ms: %s\n", buffer);
    }

    if (locked) {
        pthread_mutex_unlock(&in->lock);
    }
@@ -6870,6 +6936,8 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
    }

    if (in->standby) {
        const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);

        pthread_mutex_lock(&adev->lock);
        if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
            ret = voice_extn_compress_voip_start_input_stream(in);
@@ -6884,6 +6952,10 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
            goto exit;
        }
        in->standby = 0;

        // log startup time in ms.
        simple_stats_log(
                &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
    }

    /* Avoid read if capture_stopped is set */
@@ -8256,6 +8328,8 @@ int adev_open_output_stream(struct audio_hw_device *dev,
    else
        out->af_period_multiplier = 1;

    out->kernel_buffer_size = out->config.period_size * out->config.period_count;

    out->standby = 1;
    /* out->muted = false; by calloc() */
    /* out->written = 0; by calloc() */
@@ -8772,6 +8846,7 @@ static char* adev_get_parameters(const struct audio_hw_device *dev,
    voice_get_parameters(adev, query, reply);
    audio_extn_a2dp_get_parameters(query, reply);
    platform_get_parameters(adev->platform, query, reply);
    audio_extn_ma_get_parameters(adev, query, reply);
    pthread_mutex_unlock(&adev->lock);

exit:
+14 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@

#include <audio_route/audio_route.h>
#include <audio_utils/ErrorLog.h>
#include <audio_utils/Statistics.h>
#include <audio_utils/clock.h>
#include "audio_defs.h"
#include "voice.h"
#include "audio_hw_extn_api.h"
@@ -454,6 +456,16 @@ struct stream_out {
            int stream;
        } cs;
    } extconn;

    size_t kernel_buffer_size;  // cached value of the alsa buffer size, const after open().

    // last out_get_presentation_position() cached info.
    bool         last_fifo_valid;
    unsigned int last_fifo_frames_remaining;
    int64_t      last_fifo_time_ns;

    simple_stats_t fifo_underruns;  // TODO: keep a list of the last N fifo underrun times.
    simple_stats_t start_latency_ms;
};

struct stream_in {
@@ -507,6 +519,8 @@ struct stream_in {
    int64_t frames_muted; /* total frames muted, not cleared when entering standby */

    error_log_t *error_log;

    simple_stats_t start_latency_ms;
};

typedef enum {
Loading