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

Commit ba9fcfa2 authored by Manish Dewangan's avatar Manish Dewangan Committed by Gerrit - the friendly Code Review server
Browse files

hal: changes to support 24 bit record

-Changes to support 24 bit record if input format request is
 AUDIO_FORMAT_PCM_8_24_BIT or AUDIO_FORMAT_PCM_24_BIT_PACKED

Change-Id: I68076524ccccbf9f0be3c88bb01180ae7e4fd8b1
parent f6482a58
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -99,6 +99,12 @@ audio_hw_modules {
        formats AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_AMR_NB|AUDIO_FORMAT_AMR_WB|AUDIO_FORMAT_QCELP|AUDIO_FORMAT_EVRC|AUDIO_FORMAT_EVRCB|AUDIO_FORMAT_EVRCWB|AUDIO_FORMAT_EVRCNW
        devices AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_FM_TUNER|AUDIO_DEVICE_IN_VOICE_CALL
      }
      float {
        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000|96000|192000
        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_FRONT_BACK
        formats AUDIO_FORMAT_PCM_24_BIT_PACKED
        devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BACK_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET
      }
      surround_sound {
        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
        channel_masks AUDIO_CHANNEL_IN_5POINT1|AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_FRONT_BACK
+2 −1
Original line number Diff line number Diff line
@@ -344,7 +344,8 @@ int audio_extn_ssr_check_and_set_usecase(struct stream_in *in)
    if (audio_extn_ssr_get_enabled() &&
           ((channel_count == 2) || (channel_count == 6)) &&
           ((AUDIO_SOURCE_MIC == source) || (AUDIO_SOURCE_CAMCORDER == source)) &&
           ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices))) {
           ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
           (in->format == AUDIO_FORMAT_PCM_16_BIT)) {

        ALOGD("%s: Found SSR use case starting SSR lib with channel_count :%d",
                      __func__, channel_count);
+84 −19
Original line number Diff line number Diff line
@@ -751,7 +751,7 @@ static void check_usecases_codec_backend(struct audio_device *adev,
    }
}

static void check_and_route_capture_usecases(struct audio_device *adev,
static void check_usecases_capture_codec_backend(struct audio_device *adev,
                                             struct audio_usecase *uc_info,
                                             snd_device_t snd_device)
{
@@ -760,6 +760,9 @@ static void check_and_route_capture_usecases(struct audio_device *adev,
    bool switch_device[AUDIO_USECASE_MAX];
    int i, num_uc_to_switch = 0;

    bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
                         snd_device);
    ALOGD("%s:becf: force routing %d", __func__, force_routing);
    /*
     * This function is to make sure that all the active capture usecases
     * are always routed to the same input sound device.
@@ -777,7 +780,7 @@ static void check_and_route_capture_usecases(struct audio_device *adev,
        usecase = node_to_item(node, struct audio_usecase, list);
        if (usecase->type != PCM_PLAYBACK &&
                usecase != uc_info &&
                usecase->in_snd_device != snd_device &&
                (usecase->in_snd_device != snd_device || force_routing) &&
                ((uc_info->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
                 (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
                  (usecase->type == VOICE_CALL))) &&
@@ -1149,7 +1152,7 @@ int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
    }

    if (in_snd_device != SND_DEVICE_NONE) {
        check_and_route_capture_usecases(adev, usecase, in_snd_device);
        check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
        enable_snd_device(adev, in_snd_device);
    }

@@ -1291,8 +1294,8 @@ int start_input_stream(struct stream_in *in)
                                 adev->perf_lock_opts_size);
    select_devices(adev, in->usecase);

    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
          __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
          __func__, adev->snd_card, in->pcm_device_id, in->config.channels, in->config.format);

    unsigned int flags = PCM_IN;
    unsigned int pcm_open_retry_count = 0;
@@ -1996,7 +1999,9 @@ static int check_input_parameters(uint32_t sample_rate,
{
    int ret = 0;

    if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
    if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
        (format != AUDIO_FORMAT_PCM_FLOAT)) &&
        !voice_extn_compress_voip_is_format_supported(format) &&
        !audio_extn_compr_cap_format_supported(format))  ret = -EINVAL;

@@ -2019,6 +2024,8 @@ static int check_input_parameters(uint32_t sample_rate,
    case 32000:
    case 44100:
    case 48000:
    case 96000:
    case 192000:
        break;
    default:
        ret = -EINVAL;
@@ -2040,9 +2047,8 @@ static size_t get_input_buffer_size(uint32_t sample_rate,
    size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
    if (is_low_latency)
        size = configured_low_latency_capture_period_size;
    /* ToDo: should use frame_size computed based on the format and
       channel_count here. */
    size *= sizeof(short) * channel_count;

    size *= audio_bytes_per_sample(format) * channel_count;

    /* make sure the size is multiple of 32 bytes
     * At 48 kHz mono 16-bit PCM:
@@ -3033,6 +3039,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
    struct audio_device *adev = in->dev;
    int ret = -1;
    int snd_scard_state = get_snd_card_state(adev);
    int *int_buf_stream = NULL;

    lock_input_stream(in);

@@ -3069,17 +3076,31 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
        adev->adm_request_focus(adev->adm_data, in->capture_handle);

    if (in->pcm) {
        if (audio_extn_ssr_get_stream() == in)
        if (audio_extn_ssr_get_stream() == in) {
            ret = audio_extn_ssr_read(stream, buffer, bytes);
        else if (audio_extn_compr_cap_usecase_supported(in->usecase))
        } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
            ret = audio_extn_compr_cap_read(in, buffer, bytes);
        else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY)
        } else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
            ret = pcm_mmap_read(in->pcm, buffer, bytes);
        else
        } else {
            ret = pcm_read(in->pcm, buffer, bytes);
        if (ret < 0)
            if ( !ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
                if (bytes % 4 == 0) {
                    /* data from DSP comes in 24_8 format, convert it to 8_24 */
                    int_buf_stream = buffer;
                    for (size_t itt=0; itt < bytes/4 ; itt++) {
                        int_buf_stream[itt] >>= 8;
                    }
                } else {
                    ALOGE("%s: !!! something wrong !!! ... data not 32 bit aligned ", __func__);
                    ret = -EINVAL;
                    goto exit;
                }
            } if (ret < 0) {
                ret = -errno;
            }
        }
    }

    if (adev->adm_abandon_focus)
        adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
@@ -3921,9 +3942,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
    }

    ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
        stream_handle(%p) io_handle(%d) source(%d)",__func__, config->sample_rate, config->channel_mask,
        devices, &in->stream, handle, source);

        stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
        config->channel_mask, devices, &in->stream, handle, source, config->format);
    pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);

@@ -3963,6 +3983,8 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
    in->config = pcm_config_audio_capture;
    in->config.rate = config->sample_rate;
    in->format = config->format;
    in->bit_width = 16;
    in->sample_rate = config->sample_rate;

    if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
        if (adev->mode != AUDIO_MODE_IN_CALL) {
@@ -3989,6 +4011,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
        in->config = pcm_config_afe_proxy_record;
        in->config.channels = channel_count;
        in->config.rate = config->sample_rate;
        in->sample_rate = config->sample_rate;
    } else if (!audio_extn_ssr_check_and_set_usecase(in)) {
        ALOGD("%s: created surround sound session succesfully",__func__);
    } else if (audio_extn_compr_cap_enabled() &&
@@ -3996,6 +4019,48 @@ static int adev_open_input_stream(struct audio_hw_device *dev,
            (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
        audio_extn_compr_cap_init(in);
    } else {
        /* restrict 24 bit capture for unprocessed source only
         * for other sources if 24 bit requested reject 24 and set 16 bit capture only
         */
        if (config->format == AUDIO_FORMAT_DEFAULT) {
            config->format = AUDIO_FORMAT_PCM_16_BIT;
        } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
                (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
                (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
                (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
            bool ret_error = false;
            in->bit_width = 24;
            /* 24 bit is restricted to UNPROCESSED source only,also format supported
               from HAL is 24_packed and 8_24
             *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
             24_packed return error indicating supported format is 24_packed
             *> In case of any other source requesting 24 bit or float return error
             indicating format supported is 16 bit only.

             on error flinger will retry with supported format passed
             */
            if ((source != AUDIO_SOURCE_UNPROCESSED) &&
                (source != AUDIO_SOURCE_CAMCORDER)) {
                config->format = AUDIO_FORMAT_PCM_16_BIT;
                if( config->sample_rate > 48000)
                    config->sample_rate = 48000;
                ret_error = true;
            } else if (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
                in->config.format = PCM_FORMAT_S24_3LE;
            } else if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) {
                in->config.format = PCM_FORMAT_S24_LE;
            } else {
                config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
                ret_error = true;
            }

            if (ret_error) {
                ret = -EINVAL;
                goto err_open;
            }
        }

        in->format = config->format;
        in->config.channels = channel_count;
        frame_size = audio_stream_in_frame_size(&in->stream);
        buffer_size = get_input_buffer_size(config->sample_rate,
+2 −1
Original line number Diff line number Diff line
@@ -247,7 +247,8 @@ struct stream_in {
    audio_input_flags_t flags;
    bool is_st_session;
    bool is_st_session_active;

    int sample_rate;
    int bit_width;
    struct audio_device *dev;
};

+215 −0
Original line number Diff line number Diff line
@@ -252,6 +252,7 @@ struct platform_data {
    void *edid_info;
    bool edid_valid;
    codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
    codec_backend_cfg_t current_tx_backend_cfg[MAX_CODEC_TX_BACKENDS];
    char ec_ref_mixer_path[64];
    char codec_version[CODEC_VERSION_MAX_LENGTH];
    int hw_dep_fd;
@@ -1809,6 +1810,11 @@ acdb_init_fail:
        my_data->current_backend_cfg[idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
    }

    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].sample_rate =
                                               CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bit_width =
                                               CODEC_BACKEND_DEFAULT_BIT_WIDTH;

    if (is_external_codec) {
        my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
            strdup("SLIM_0_RX Format");
@@ -1824,11 +1830,21 @@ acdb_init_fail:
            strdup("SLIM_6_RX Format");
        my_data->current_backend_cfg[HEADPHONE_BACKEND].samplerate_mixer_ctl =
            strdup("SLIM_6_RX SampleRate");

        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
            strdup("SLIM_0_TX Format");
        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
            strdup("SLIM_0_TX SampleRate");
    } else {
        my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
            strdup("MI2S_RX Format");
        my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
            strdup("MI2S_RX SampleRate");

        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
            strdup("MI2S_TX Format");
        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
            strdup("MI2S_TX SampleRate");
    }

    ret = audio_extn_utils_get_codec_version(snd_card_name,
@@ -4163,6 +4179,205 @@ bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
    return ret;
}

/*
 * configures afe with bit width and Sample Rate
 */

int platform_set_capture_codec_backend_cfg(struct audio_device* adev,
                         snd_device_t snd_device,
                         unsigned int bit_width, unsigned int sample_rate,
                         audio_format_t format)
{
    int ret = 0;
    int backend_idx = DEFAULT_CODEC_BACKEND;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
          __func__, bit_width, sample_rate, backend_idx,
          platform_get_snd_device_name(snd_device));

    if (bit_width !=
        my_data->current_tx_backend_cfg[backend_idx].bit_width) {

        struct  mixer_ctl *ctl = NULL;
        ctl = mixer_get_ctl_by_name(adev->mixer,
                        my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
        if (!ctl) {
            ALOGE("%s:txbecf: afe: Could not get ctl for mixer command - %s",
                  __func__,
                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
            return -EINVAL;
        }

        if (bit_width == 24) {
            if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
            else
                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
        } else {
            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
        }

        if (ret < 0) {
            ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
                  __func__,
                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
            return -EINVAL;
        }

        my_data->current_tx_backend_cfg[backend_idx].bit_width = bit_width;
        ALOGD("%s:txbecf: afe: %s mixer set to %d bit", __func__,
              my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width);
    }

    /*
     * Backend sample rate configuration follows:
     * 16 bit record - 48khz for streams at any valid sample rate
     * 24 bit record - 48khz for stream sample rate less than 48khz
     * 24 bit record - 96khz for sample rate range of 48khz to 96khz
     * 24 bit record - 192khz for sample rate range of 96khz to 192 khz
     * Upper limit is inclusive in the sample rate range.
     */
    // TODO: This has to be more dynamic based on policy file

    if (sample_rate != my_data->current_tx_backend_cfg[(int)backend_idx].sample_rate) {
            /*
             * sample rate update is needed only for hifi audio enabled platforms
             */
            char *rate_str = NULL;
            struct  mixer_ctl *ctl = NULL;

            switch (sample_rate) {
            case 8000:
            case 11025:
            case 16000:
            case 22050:
            case 32000:
            case 44100:
            case 48000:
                rate_str = "KHZ_48";
                break;
            case 64000:
            case 88200:
            case 96000:
                rate_str = "KHZ_96";
                break;
            case 176400:
            case 192000:
                rate_str = "KHZ_192";
                break;
            default:
                rate_str = "KHZ_48";
                break;
            }

            ctl = mixer_get_ctl_by_name(adev->mixer,
                my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);

            if (ctl < 0) {
                ALOGE("%s:txbecf: afe: Could not get ctl to set the Sample Rate for mixer command - %s",
                      __func__,
                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
                return -EINVAL;
            }

            ALOGD("%s:txbecf: afe: %s set to %s", __func__,
                  my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl,
                  rate_str);
            ret = mixer_ctl_set_enum_by_string(ctl, rate_str);
            if (ret < 0) {
                ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
                      __func__,
                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
                return -EINVAL;
            }

            my_data->current_tx_backend_cfg[backend_idx].sample_rate = sample_rate;
    }

    return ret;
}

/*
 * goes through all the current usecases and picks the highest
 * bitwidth & samplerate
 */
bool platform_check_capture_codec_backend_cfg(struct audio_device* adev,
                                   unsigned int* new_bit_width,
                                   unsigned int* new_sample_rate)
{
    bool backend_change = false;
    unsigned int bit_width;
    unsigned int sample_rate;
    int backend_idx = DEFAULT_CODEC_BACKEND;
    struct platform_data *my_data = (struct platform_data *)adev->platform;

    bit_width = *new_bit_width;
    sample_rate = *new_sample_rate;

    ALOGI("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
          "sample rate: %d",__func__,backend_idx, bit_width, sample_rate);

    // For voice calls use default configuration i.e. 16b/48K, only applicable to
    // default backend
    // force routing is not required here, caller will do it anyway
    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) ||
        (!is_external_codec)) {
        ALOGW("%s:txbecf: afe:Use default bw and sr for voice/voip calls",
              __func__);
        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
    }

    ALOGI("%s:txbecf: afe: Codec selected backend: %d updated bit width: %d and "
          "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
    // Force routing if the expected bitwdith or samplerate
    // is not same as current backend comfiguration
    if ((bit_width != my_data->current_tx_backend_cfg[backend_idx].bit_width) ||
        (sample_rate != my_data->current_tx_backend_cfg[backend_idx].sample_rate)) {
        *new_bit_width = bit_width;
        *new_sample_rate = sample_rate;
        backend_change = true;
        ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
              "new sample rate: %d", __func__, *new_bit_width, *new_sample_rate);
    }

    return backend_change;
}

bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
    struct audio_usecase *usecase, snd_device_t snd_device)
{
    unsigned int new_bit_width;
    unsigned int new_sample_rate;
    audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
    int backend_idx = DEFAULT_CODEC_BACKEND;
    int ret = 0;

    if(usecase->type == PCM_CAPTURE) {
        new_sample_rate = usecase->stream.in->sample_rate;
        new_bit_width = usecase->stream.in->bit_width;
        format = usecase->stream.in->format;
    } else {
        new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
        new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
    }

    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d"
          ", backend_idx %d usecase = %d device (%s)", __func__, new_bit_width,
          new_sample_rate, backend_idx, usecase->id,
          platform_get_snd_device_name(snd_device));
    if (platform_check_capture_codec_backend_cfg(adev, &new_bit_width,
                                       &new_sample_rate)) {
        ret = platform_set_capture_codec_backend_cfg(adev, snd_device,
                                       new_bit_width, new_sample_rate, format);
        if(!ret)
            return true;
    }

    return false;
}

int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
                                    const char * hw_interface)
{
Loading