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

Commit f6318be8 authored by Derek Chen's avatar Derek Chen
Browse files

hal: support car audio stream for bus devices

Add support for car audio streams and usecases
including media, system notification, navigation
guidance and phone.
The car audio streams are routed to bus devices
with assigned address, which is defined in audio
policy configuration. This enables dynamic mixing
and routing done by Android car framework from
application to AudioFlinger and audio HAL.

Change-Id: I583fc7b5f2e8850b064a3cde5f93693b16c47841
parent af656061
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1216,6 +1216,10 @@ int audio_extn_utils_get_license_params(const struct audio_device *adev, struct
#define audio_extn_auto_hal_create_audio_patch(dev, num_sources,\
    sources, num_sinks, sinks, handle) (0)
#define audio_extn_auto_hal_release_audio_patch(dev, handle) (0)
#define audio_extn_auto_hal_get_car_audio_stream_from_address(address) (-1)
#define audio_extn_auto_hal_open_output_stream(out) (0)
#define audio_extn_auto_hal_is_bus_device_usecase(uc_id) (0)
#define audio_extn_auto_hal_get_snd_device_for_car_audio_stream(out) (0)
#else
int32_t audio_extn_auto_hal_init(struct audio_device *adev);
void audio_extn_auto_hal_deinit(void);
@@ -1229,6 +1233,10 @@ int audio_extn_auto_hal_create_audio_patch(struct audio_hw_device *dev,
                                audio_patch_handle_t *handle);
int audio_extn_auto_hal_release_audio_patch(struct audio_hw_device *dev,
                                audio_patch_handle_t handle);
int32_t audio_extn_auto_hal_get_car_audio_stream_from_address(const char *address);
int32_t audio_extn_auto_hal_open_output_stream(struct stream_out *out);
bool audio_extn_auto_hal_is_bus_device_usecase(audio_usecase_t uc_id);
snd_device_t audio_extn_auto_hal_get_snd_device_for_car_audio_stream(struct stream_out *out);
#endif

bool audio_extn_edid_is_supported_sr(edid_audio_info* info, int sr);
+122 −0
Original line number Diff line number Diff line
@@ -60,6 +60,16 @@ typedef struct auto_hal_module {
/* Auto hal module struct */
static struct auto_hal_module *auto_hal = NULL;

extern struct pcm_config pcm_config_deep_buffer;
extern struct pcm_config pcm_config_low_latency;

static const audio_usecase_t bus_device_usecases[] = {
    USECASE_AUDIO_PLAYBACK_MEDIA,
    USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION,
    USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE,
    USECASE_AUDIO_PLAYBACK_PHONE,
};

/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are
 * both connected with CODEC and a single master is needed to provide
 * consistent CLK and FSYNC to slaves, hence configuring SoC TERT TDM as
@@ -310,6 +320,118 @@ int audio_extn_auto_hal_release_audio_patch(struct audio_hw_device *dev,
    return ret;
}

int32_t audio_extn_auto_hal_get_car_audio_stream_from_address(const char *address)
{
    int32_t bus_num = -1;
    char *str = NULL;
    char *last_r = NULL;
    char local_address[AUDIO_DEVICE_MAX_ADDRESS_LEN];

    /* bus device with null address error out */
    if (address == NULL) {
        ALOGE("%s: null address for car stream", __func__);
        return -1;
    }

    /* strtok will modify the original string. make a copy first */
    strlcpy(local_address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);

    /* extract bus number from address */
    str = strtok_r(local_address, "BUS_",&last_r);
    if (str != NULL)
        bus_num = (int32_t)strtol(str, (char **)NULL, 10);

    /* validate bus number */
    if ((bus_num < 0) || (bus_num >= MAX_CAR_AUDIO_STREAMS)) {
        ALOGE("%s: invalid bus number %d", __func__, bus_num);
        return -1;
    }

    return (0x1 << bus_num);
}

int32_t audio_extn_auto_hal_open_output_stream(struct stream_out *out)
{
    int ret = 0;
    unsigned int channels = audio_channel_count_from_out_mask(out->channel_mask);

    switch(out->car_audio_stream) {
    case CAR_AUDIO_STREAM_MEDIA:
        /* media bus stream shares pcm device with deep-buffer */
        out->usecase = USECASE_AUDIO_PLAYBACK_MEDIA;
        out->config = pcm_config_deep_buffer;
        out->config.period_size = get_output_period_size(out->sample_rate, out->format,
                                        channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
        if (out->config.period_size <= 0) {
            ALOGE("Invalid configuration period size is not valid");
            ret = -EINVAL;
            goto error;
        }
        break;
    case CAR_AUDIO_STREAM_SYS_NOTIFICATION:
        /* sys notification bus stream shares pcm device with low-latency */
        out->usecase = USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION;
        out->config = pcm_config_low_latency;
        break;
    case CAR_AUDIO_STREAM_NAV_GUIDANCE:
        out->usecase = USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE;
        out->config = pcm_config_deep_buffer;
        out->config.period_size = get_output_period_size(out->sample_rate, out->format,
                                        channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
        if (out->config.period_size <= 0) {
            ALOGE("Invalid configuration period size is not valid");
            ret = -EINVAL;
            goto error;
        }
        break;
    case CAR_AUDIO_STREAM_PHONE:
        out->usecase = USECASE_AUDIO_PLAYBACK_PHONE;
        out->config = pcm_config_low_latency;
        break;
    default:
        ALOGE("%s: Car audio stream %x not supported", __func__,
            out->car_audio_stream);
        ret = -EINVAL;
        goto error;
    }

error:
    return ret;
}

bool audio_extn_auto_hal_is_bus_device_usecase(audio_usecase_t uc_id)
{
    unsigned int i;
    for (i = 0; i < sizeof(bus_device_usecases)/sizeof(bus_device_usecases[0]); i++) {
        if (uc_id == bus_device_usecases[i])
            return true;
    }
    return false;
}

snd_device_t audio_extn_auto_hal_get_snd_device_for_car_audio_stream(struct stream_out *out)
{
    snd_device_t snd_device = SND_DEVICE_NONE;

    switch(out->car_audio_stream) {
    case CAR_AUDIO_STREAM_MEDIA:
        snd_device = SND_DEVICE_OUT_BUS_MEDIA;
        break;
    case CAR_AUDIO_STREAM_SYS_NOTIFICATION:
        snd_device = SND_DEVICE_OUT_BUS_SYS;
        break;
    case CAR_AUDIO_STREAM_NAV_GUIDANCE:
        snd_device = SND_DEVICE_OUT_BUS_NAV;
        break;
    case CAR_AUDIO_STREAM_PHONE:
        snd_device = SND_DEVICE_OUT_BUS_PHN;
        break;
    default:
        ALOGE("%s: Unknown car audio stream (%x)",
            __func__, out->car_audio_stream);
    }
    return snd_device;
}
int32_t audio_extn_auto_hal_init(struct audio_device *adev)
{
    int32_t ret = 0;
+8 −0
Original line number Diff line number Diff line
@@ -265,6 +265,8 @@ static int32_t ext_hw_plugin_check_plugin_usecase(audio_usecase_t hal_usecase,
    case USECASE_AUDIO_PLAYBACK_OFFLOAD8:
    case USECASE_AUDIO_PLAYBACK_OFFLOAD9:
    case USECASE_AUDIO_PLAYBACK_ULL:
    case USECASE_AUDIO_PLAYBACK_MEDIA:
    case USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION:
        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_DEFAULT_PLAYBACK;
        break;
    case USECASE_AUDIO_RECORD:
@@ -281,6 +283,12 @@ static int32_t ext_hw_plugin_check_plugin_usecase(audio_usecase_t hal_usecase,
    case USECASE_VOICEMMODE1_CALL:
        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_CS_VOICE_CALL;
        break;
    case USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE:
        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_DRIVER_SIDE_PLAYBACK;
        break;
    case USECASE_AUDIO_PLAYBACK_PHONE:
        *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_PHONE_PLAYBACK;
        break;
    default:
        ret = -EINVAL;
    }
+2 −1
Original line number Diff line number Diff line
@@ -1060,7 +1060,8 @@ static int send_app_type_cfg_for_device(struct audio_device *adev,
        (usecase->id != USECASE_AUDIO_TRANSCODE_LOOPBACK_RX) &&
        (!is_interactive_usecase(usecase->id)) &&
        (!is_offload_usecase(usecase->id)) &&
        (usecase->type != PCM_CAPTURE)) {
        (usecase->type != PCM_CAPTURE) &&
        (!audio_extn_auto_hal_is_bus_device_usecase(usecase->id))) {
        ALOGV("%s: a rx/tx/loopback path where app type cfg is not required %d", __func__, usecase->id);
        rc = 0;
        goto exit_send_app_type_cfg;
+37 −8
Original line number Diff line number Diff line
@@ -399,7 +399,12 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = {

    [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",

    [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback"
    [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",

    [USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",
    [USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
    [USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",
    [USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",
};

static const audio_usecase_t offload_usecases[] = {
@@ -3805,7 +3810,7 @@ static size_t get_input_buffer_size(uint32_t sample_rate,
                                  is_low_latency);
}

static size_t get_output_period_size(uint32_t sample_rate,
size_t get_output_period_size(uint32_t sample_rate,
                            audio_format_t format,
                            int channel_count,
                            int duration /*in millisecs*/)
@@ -6816,7 +6821,7 @@ int adev_open_output_stream(struct audio_hw_device *dev,
                            audio_output_flags_t flags,
                            struct audio_config *config,
                            struct audio_stream_out **stream_out,
                            const char *address __unused)
                            const char *address)
{
    struct audio_device *adev = (struct audio_device *)dev;
    struct stream_out *out;
@@ -6847,8 +6852,8 @@ int adev_open_output_stream(struct audio_hw_device *dev,
    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));

    ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
        stream_handle(%p)", __func__, config->format, config->sample_rate, config->channel_mask,
        devices, flags, &out->stream);
        stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
        devices, flags, &out->stream, address);


    if (!out) {
@@ -6971,6 +6976,23 @@ int adev_open_output_stream(struct audio_hw_device *dev,
        out->config.format = pcm_format_from_audio_format(out->format);
    }

    /* validate bus device address */
    if (out->devices & AUDIO_DEVICE_OUT_BUS) {
        /* extract car audio stream index */
        out->car_audio_stream =
            audio_extn_auto_hal_get_car_audio_stream_from_address(address);
        if (out->car_audio_stream < 0) {
            ALOGE("%s: invalid car audio stream %x",
                __func__, out->car_audio_stream);
            ret = -EINVAL;
            goto error_open;
        }
        /* save car audio stream and address for bus device */
        strlcpy(out->address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
        ALOGV("%s: address %s, car_audio_stream %x",
            __func__, out->address, out->car_audio_stream);
    }

    /* Check for VOIP usecase */
    if (is_voip_rx) {
        if (!voice_extn_is_compress_voip_supported()) {
@@ -7442,6 +7464,13 @@ int adev_open_output_stream(struct audio_hw_device *dev,
                adev->haptics_config.channels = 1;
            } else
                adev->haptics_config.channels = audio_channel_count_from_out_mask(out->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL);
        } else if (out->devices & AUDIO_DEVICE_OUT_BUS) {
            ret = audio_extn_auto_hal_open_output_stream(out);
            if (ret) {
                ALOGE("%s: Failed to open output stream for bus device", __func__);
                ret = -EINVAL;
                goto error_open;
            }
        } else {
            /* primary path is the default path selected if no other outputs are available/suitable */
            out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Loading