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

Commit e0548d41 authored by Siddartha Shaik's avatar Siddartha Shaik Committed by Garmond Leung
Browse files

audio: hal: Volume control support for transcode loopback

Changes to enable volume control for DSP HW
transcode loopback use case type.

CRs-Fixed: 2092579
Change-Id: I48b9020ec1f8137495ddf84151445f423d01a1ff
parent 343abc67
Loading
Loading
Loading
Loading
+75 −21
Original line number Diff line number Diff line
@@ -41,7 +41,10 @@
#define PATCH_HANDLE_INVALID 0xFFFF
#define MAX_SOURCE_PORTS_PER_PATCH 1
#define MAX_SINK_PORTS_PER_PATCH 1
#define HW_LOOPBACK_RX_VOLUME     "Trans Loopback RX Volume"
#define HW_LOOPBACK_RX_UNITY_GAIN 0x2000

#include <math.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
@@ -131,6 +134,34 @@ uint32_t format_to_bitwidth(audio_format_t format)
    }
}

/* Set loopback volume : for mute implementation */
static int hw_loopback_set_volume(struct audio_device *adev, int value)
{
    int32_t ret = 0;
    struct mixer_ctl *ctl;
    char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
            "Transcode Loopback Rx Volume");

    ALOGD("%s: (%d)\n", __func__, value);

    ALOGD("%s: Setting HW loopback volume to %d \n", __func__, value);
    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
    if (!ctl) {
        ALOGE("%s: Could not get ctl for mixer cmd - %s",
              __func__, mixer_ctl_name);
        return -EINVAL;
    }

    if(mixer_ctl_set_value(ctl, 0, value) < 0) {
        ALOGE("%s: Couldn't set HW Loopback Volume: [%d]", __func__, value);
        return -EINVAL;
    }

    ALOGV("%s: exit", __func__);
    return ret;
}

/* Initialize patch database */
int init_patch_database(patch_db_t* patch_db)
{
@@ -662,8 +693,7 @@ int audio_extn_hw_loopback_get_audio_port(struct audio_hw_device *dev,
                                    struct audio_port *port_in)
{
    int status = 0, n=0, patch_num=-1;
    loopback_patch_t *active_loopback_patch = NULL;
    port_info_t *port_info = NULL;
    port_info_t port_info;
    struct audio_port_config *port_out=NULL;
    ALOGV("%s %d", __func__, __LINE__);

@@ -675,10 +705,10 @@ int audio_extn_hw_loopback_get_audio_port(struct audio_hw_device *dev,

    pthread_mutex_lock(&audio_loopback_mod->lock);

    port_info->id = port_in->id;
    port_info->role = port_in->role;              /* sink or source */
    port_info->type = port_in->type;              /* device, mix ... */
    port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db,
    port_info.id = port_in->id;
    port_info.role = port_in->role;              /* sink or source */
    port_info.type = port_in->type;              /* device, mix ... */
    port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db,
                                      &patch_num);
    if (port_out == NULL) {
        ALOGE("%s, Unable to find a valid matching port in patch \
@@ -709,40 +739,64 @@ int audio_extn_hw_loopback_set_audio_port_config(struct audio_hw_device *dev,
                                        const struct audio_port_config *config)
{
    int status = 0, n=0, patch_num=-1;
    loopback_patch_t *active_loopback_patch = NULL;
    port_info_t *port_info = NULL;
    port_info_t port_info;
    struct audio_port_config *port_out=NULL;
    struct audio_device *adev = audio_loopback_mod->adev;
    int loopback_gain = HW_LOOPBACK_RX_UNITY_GAIN;

    ALOGV("%s %d", __func__, __LINE__);

    if ((audio_loopback_mod == NULL) || (dev == NULL)) {
        ALOGE("%s, Invalid device", __func__);
        status = -1;
        status = -EINVAL;
        return status;
    }

    pthread_mutex_lock(&audio_loopback_mod->lock);

    port_info->id = config->id;
    port_info->role = config->role;              /* sink or source */
    port_info->type = config->type;              /* device, mix  */
    port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db
    port_info.id = config->id;
    port_info.role = config->role;              /* sink or source */
    port_info.type = config->type;              /* device, mix  */
    port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db
                                    , &patch_num);

    if (port_out == NULL) {
        ALOGE("%s, Unable to find a valid matching port in patch \
        database,exiting", __func__);
        status = -1;
        return status;
        status = -EINVAL;
        goto exit_set_port_config;
    }

    port_out->config_mask = config->config_mask;
    port_out->config_mask |= config->config_mask;
    if(config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)
        port_out->channel_mask = config->channel_mask;
    if(config->config_mask & AUDIO_PORT_CONFIG_FORMAT)
        port_out->format = config->format;
    if(config->config_mask & AUDIO_PORT_CONFIG_GAIN)
        port_out->gain = config->gain;
    if(config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)
        port_out->sample_rate = config->sample_rate;

    /* Convert gain in millibels to ratio and convert to Q13 */
    loopback_gain = pow(10, (float)((float)port_out->gain.values[0]/2000)) *
                       (1 << 13);
    ALOGV("%s, Port config gain_in_mbells: %d, gain_in_q13 : %d", __func__,
          port_out->gain.values[0], loopback_gain);
    if((port_out->config_mask & AUDIO_PORT_CONFIG_GAIN) &&
        port_out->gain.mode == AUDIO_GAIN_MODE_JOINT ) {
        status = hw_loopback_set_volume(adev, loopback_gain);
        if (status) {
            ALOGE("%s, Error setting loopback gain config: status %d",
                  __func__, status);
        }
    } else {
        ALOGE("%s, Unsupported port config ,exiting", __func__);
        status = -EINVAL;
    }

    /* Currently, port config is not used for anything,
    need to restart session    */
exit_set_port_config:
    pthread_mutex_unlock(&audio_loopback_mod->lock);
    return status;
}
+30 −7
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <utils/Log.h>
#include <math.h>

#include <cutils/list.h>
#include "qahw_api.h"
@@ -87,6 +88,7 @@ qahw_module_handle_t *primary_hal_handle = NULL;

FILE * log_file = NULL;
volatile bool stop_loopback = false;
static float loopback_gain = 1.0;
const char *log_filename = NULL;

#define TRANSCODE_LOOPBACK_SOURCE_PORT_ID 0x4C00
@@ -394,6 +396,23 @@ int create_run_transcode_loopback(
                        &transcode_loopback_config->sink_config,
                        &transcode_loopback_config->patch_handle);
    fprintf(log_file,"\nCreate patch returned %d\n",rc);
    if(!rc) {
        struct audio_port_config sink_gain_config;
        /* Convert loopback gain to millibels */
        int loopback_gain_in_millibels = 2000 * log10(loopback_gain);
        sink_gain_config.gain.index = 0;
        sink_gain_config.gain.mode = AUDIO_GAIN_MODE_JOINT;
        sink_gain_config.gain.channel_mask = 1;
        sink_gain_config.gain.values[0] = loopback_gain_in_millibels;
        sink_gain_config.id = transcode_loopback_config->sink_config.id;
        sink_gain_config.role = transcode_loopback_config->sink_config.role;
        sink_gain_config.type = transcode_loopback_config->sink_config.type;
        sink_gain_config.config_mask = AUDIO_PORT_CONFIG_GAIN;

        (void)qahw_set_audio_port_config(transcode_loopback_config->hal_handle,
                    &sink_gain_config);
    }

    return rc;
}

@@ -543,7 +562,7 @@ void set_device(uint32_t device_type, uint32_t device_id)
int main(int argc, char *argv[]) {

    int status = 0;
    uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2;
    uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2, volume_in_millibels = 0;
    source_port_type_t source_port_type = SOURCE_PORT_NONE;
    log_file = stdout;
    transcode_loopback_config_t    *transcode_loopback_config = NULL;
@@ -553,6 +572,7 @@ int main(int argc, char *argv[]) {
        /* These options set a flag. */
        {"sink-device", required_argument,    0, 'd'},
        {"play-duration",  required_argument,    0, 'p'},
        {"play-volume",  required_argument,    0, 'v'},
        {"help",          no_argument,          0, 'h'},
        {0, 0, 0, 0}
    };
@@ -562,7 +582,7 @@ int main(int argc, char *argv[]) {

    while ((opt = getopt_long(argc,
                              argv,
                              "-d:p:h",
                              "-d:p:v:h",
                              long_options,
                              &option_index)) != -1) {

@@ -575,6 +595,9 @@ int main(int argc, char *argv[]) {
        case 'p':
            play_duration_in_seconds = atoi(optarg);
            break;
        case 'v':
            loopback_gain = atof(optarg);
            break;
        case 'h':
        default :
            usage();
@@ -584,9 +607,9 @@ int main(int argc, char *argv[]) {
    }

    fprintf(log_file,"\nTranscode loopback test begin\n");
    if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
    if (play_duration_in_seconds < 0 | play_duration_in_seconds > 360000) {
            fprintf(log_file,
                    "\nPlayback duration %d invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
                    "\nPlayback duration %d invalid or unsupported(range : 1 to 360000, defaulting to 600 seconds )\n",
                    play_duration_in_seconds);
            play_duration_in_seconds = 600;
    }
@@ -654,8 +677,8 @@ exit_transcode_loopback_test:

void usage()
{
    fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id>\n");
    fprintf(log_file,"\nExample to play for 1 minute on speaker device: trans_loopback_test -p 60 -d 2\n");
    fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id> -v <loopback_volume(range 0 to 4.0)>\n");
    fprintf(log_file,"\nExample to play for 1 minute on speaker device with volume unity: trans_loopback_test -p 60 -d 2 -v 1.0\n");
    fprintf(log_file,"\nExample to play for 5 minutes on headphone device: trans_loopback_test -p 300 -d 8\n");
    fprintf(log_file,"\nHelp : trans_loopback_test -h\n");
 }