Loading hal/audio_hw.c +470 −88 Original line number Diff line number Diff line Loading @@ -83,6 +83,11 @@ static unsigned int configured_low_latency_capture_period_size = LOW_LATENCY_CAPTURE_PERIOD_SIZE; #define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000) #define MMAP_PERIOD_COUNT 512 /* This constant enables extended precision handling. * TODO The flag is off until more testing is done. */ Loading Loading @@ -135,6 +140,19 @@ struct pcm_config pcm_config_hdmi_multi = { .avail_min = 0, }; struct pcm_config pcm_config_mmap_playback = { .channels = DEFAULT_CHANNEL_COUNT, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, .period_size = MMAP_PERIOD_SIZE, .period_count = MMAP_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, .start_threshold = MMAP_PERIOD_SIZE*8, .stop_threshold = INT32_MAX, .silence_threshold = 0, .silence_size = 0, .avail_min = MMAP_PERIOD_SIZE, //1 ms }; struct pcm_config pcm_config_audio_capture = { .channels = DEFAULT_CHANNEL_COUNT, .period_count = AUDIO_CAPTURE_PERIOD_COUNT, Loading @@ -156,6 +174,19 @@ struct pcm_config pcm_config_audio_capture_rt = { .avail_min = ULL_PERIOD_SIZE, //1 ms }; struct pcm_config pcm_config_mmap_capture = { .channels = DEFAULT_CHANNEL_COUNT, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, .period_size = MMAP_PERIOD_SIZE, .period_count = MMAP_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, .start_threshold = 0, .stop_threshold = INT_MAX, .silence_threshold = 0, .silence_size = 0, .avail_min = MMAP_PERIOD_SIZE, //1 ms }; #define AFE_PROXY_CHANNEL_COUNT 2 #define AFE_PROXY_SAMPLING_RATE 48000 Loading Loading @@ -194,9 +225,11 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback", [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback", [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_AUDIO_RECORD_MMAP] = "mmap-record", [USECASE_AUDIO_HFP_SCO] = "hfp-sco", [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb", Loading Loading @@ -1276,9 +1309,21 @@ int start_input_stream(struct stream_in *in) 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); if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { if (!pcm_is_ready(in->pcm)) { ALOGE("%s: pcm stream not ready", __func__); goto error_open; } ret = pcm_prepare(in->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret); goto error_open; } ret = pcm_start(in->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret); goto error_open; } } else { unsigned int flags = PCM_IN | PCM_MONOTONIC; unsigned int pcm_open_retry_count = 0; Loading @@ -1289,6 +1334,9 @@ int start_input_stream(struct stream_in *in) flags |= PCM_MMAP | PCM_NOIRQ; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, in->pcm_device_id, in->config.channels); while (1) { in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, flags, &in->config); Loading Loading @@ -1325,11 +1373,12 @@ int start_input_stream(struct stream_in *in) goto error_open; } } } register_in_stream(in); audio_extn_perf_lock_release(); ALOGV("%s: exit", __func__); return ret; return 0; error_open: stop_input_stream(in); Loading Loading @@ -1667,7 +1716,39 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)", __func__, adev->snd_card, out->pcm_device_id, out->config.format); if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { out->pcm = NULL; out->compr = compress_open(adev->snd_card, out->pcm_device_id, COMPRESS_IN, &out->compr_config); if (out->compr && !is_compress_ready(out->compr)) { ALOGE("%s: %s", __func__, compress_get_error(out->compr)); compress_close(out->compr); out->compr = NULL; ret = -EIO; goto error_open; } if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) adev->offload_effects_start_output(out->handle, out->pcm_device_id); } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { if (!pcm_is_ready(out->pcm)) { ALOGE("%s: pcm stream not ready", __func__); goto error_open; } ret = pcm_prepare(out->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret); goto error_open; } ret = pcm_start(out->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret); goto error_open; } } else { unsigned int flags = PCM_OUT; unsigned int pcm_open_retry_count = 0; Loading Loading @@ -1707,26 +1788,6 @@ int start_output_stream(struct stream_out *out) goto error_open; } } } else { out->pcm = NULL; out->compr = compress_open(adev->snd_card, out->pcm_device_id, COMPRESS_IN, &out->compr_config); if (out->compr && !is_compress_ready(out->compr)) { ALOGE("%s: %s", __func__, compress_get_error(out->compr)); compress_close(out->compr); out->compr = NULL; ret = -EIO; goto error_open; } if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) adev->offload_effects_start_output(out->handle, out->pcm_device_id); } ret = 0; if (out->realtime) { ret = pcm_start(out->pcm); if (ret < 0) { Loading @@ -1736,12 +1797,13 @@ int start_output_stream(struct stream_out *out) goto error_open; } } } register_out_stream(out); audio_extn_perf_lock_release(); audio_extn_tfa_98xx_enable_speaker(); ALOGV("%s: exit", __func__); return ret; return 0; error_open: audio_extn_perf_lock_release(); stop_output_stream(out); Loading Loading @@ -1864,7 +1926,6 @@ static int out_standby(struct audio_stream *stream) if (!out->standby) { if (adev->adm_deregister_stream) adev->adm_deregister_stream(adev->adm_data, out->handle); pthread_mutex_lock(&adev->lock); out->standby = true; if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { Loading @@ -1872,6 +1933,9 @@ static int out_standby(struct audio_stream *stream) pcm_close(out->pcm); out->pcm = NULL; } if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { out->playback_started = false; } } else { stop_compressed_output_l(out); out->gapless_mdata.encoder_delay = 0; Loading Loading @@ -2111,7 +2175,8 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream) if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; else if (out->realtime) { else if ((out->realtime) || (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) { // since the buffer won't be filled up faster than realtime, // return a smaller number period_ms = (out->af_period_multiplier * out->config.period_size * Loading Loading @@ -2225,6 +2290,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, int error_code = ERROR_CODE_STANDBY; lock_output_stream(out); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { error_code = ERROR_CODE_WRITE; goto exit; } if (out->standby) { out->standby = false; pthread_mutex_lock(&adev->lock); Loading Loading @@ -2491,6 +2560,143 @@ static int out_flush(struct audio_stream_out* stream) return -ENOSYS; } static int out_stop(const struct audio_stream_out* stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby && out->playback_started && out->pcm != NULL) { pcm_stop(out->pcm); ret = stop_output_stream(out); if (ret == 0) { out->playback_started = false; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_start(const struct audio_stream_out* stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby && !out->playback_started && out->pcm != NULL) { ret = start_output_stream(out); if (ret == 0) { out->playback_started = true; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_create_mmap_buffer(const struct audio_stream_out *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = 0; unsigned int offset1; unsigned int frames1; const char *step = ""; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (info == NULL || min_size_frames == 0) { ret = -EINVAL; goto exit; } if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) { ret = -ENOSYS; goto exit; } 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)", __func__, out->pcm_device_id, out->usecase); ret = -EINVAL; goto exit; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, out->pcm_device_id, out->config.channels); out->pcm = pcm_open(adev->snd_card, out->pcm_device_id, (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config); if (out->pcm == NULL || !pcm_is_ready(out->pcm)) { step = "open"; ret = -ENODEV; goto exit; } ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1); if (ret < 0) { step = "begin"; goto exit; } info->buffer_size_frames = pcm_get_buffer_size(out->pcm); info->burst_size_frames = out->config.period_size; info->shared_memory_fd = pcm_get_poll_fd(out->pcm); memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm, info->buffer_size_frames)); ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE); if (ret < 0) { step = "commit"; goto exit; } ret = 0; ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d", __func__, info->shared_memory_address, info->buffer_size_frames); exit: if (ret != 0) { ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm)); if (out->pcm != NULL) { pcm_close(out->pcm); out->pcm = NULL; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_get_mmap_position(const struct audio_stream_out *stream, struct audio_mmap_position *position) { struct stream_out *out = (struct stream_out *)stream; ALOGVV("%s", __func__); if (position == NULL) { return -EINVAL; } if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) { return -ENOSYS; } if (out->pcm == NULL) { return -ENOSYS; } struct timespec ts = { 0, 0 }; int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts); if (ret < 0) { ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); return ret; } position->time_nanoseconds = ts2ns(&ts); return 0; } /** audio_stream_in implementation **/ static uint32_t in_get_sample_rate(const struct audio_stream *stream) { Loading Loading @@ -2551,6 +2757,9 @@ static int in_standby(struct audio_stream *stream) pthread_mutex_lock(&adev->lock); in->standby = true; if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { in->capture_started = false; } if (in->pcm) { pcm_close(in->pcm); in->pcm = NULL; Loading Loading @@ -2685,6 +2894,11 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, return bytes; } if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { ret = -ENOSYS; goto exit; } if (in->standby) { pthread_mutex_lock(&adev->lock); ret = start_input_stream(in); Loading Loading @@ -2845,6 +3059,146 @@ static int in_remove_audio_effect(const struct audio_stream *stream, return add_remove_audio_effect(stream, effect, false); } static int in_stop(const struct audio_stream_in* stream) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby && in->capture_started && in->pcm != NULL) { pcm_stop(in->pcm); ret = stop_input_stream(in); if (ret == 0) { in->capture_started = false; } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_start(const struct audio_stream_in* stream) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = -ENOSYS; ALOGV("%s in %p", __func__, in); pthread_mutex_lock(&adev->lock); if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby && !in->capture_started && in->pcm != NULL) { if (!in->capture_started) { ret = start_input_stream(in); if (ret == 0) { in->capture_started = true; } } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_create_mmap_buffer(const struct audio_stream_in *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = 0; unsigned int offset1; unsigned int frames1; const char *step = ""; pthread_mutex_lock(&adev->lock); ALOGV("%s in %p", __func__, in); if (info == NULL || min_size_frames == 0) { ALOGV("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames); ret = -EINVAL; goto exit; } if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) { ALOGV("%s in %p", __func__, in); ret = -ENOSYS; goto exit; } in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", __func__, in->pcm_device_id, in->usecase); ret = -EINVAL; goto exit; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, in->pcm_device_id, in->config.channels); in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config); if (in->pcm == NULL || !pcm_is_ready(in->pcm)) { step = "open"; ret = -ENODEV; goto exit; } ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1); if (ret < 0) { step = "begin"; goto exit; } info->buffer_size_frames = pcm_get_buffer_size(in->pcm); info->burst_size_frames = in->config.period_size; info->shared_memory_fd = pcm_get_poll_fd(in->pcm); memset(info->shared_memory_address, 0, pcm_frames_to_bytes(in->pcm, info->buffer_size_frames)); ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE); if (ret < 0) { step = "commit"; goto exit; } ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d", __func__, info->shared_memory_address, info->buffer_size_frames); ret = 0; exit: if (ret != 0) { ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm)); if (in->pcm != NULL) { pcm_close(in->pcm); in->pcm = NULL; } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_get_mmap_position(const struct audio_stream_in *stream, struct audio_mmap_position *position) { struct stream_in *in = (struct stream_in *)stream; ALOGVV("%s", __func__); if (position == NULL) { return -EINVAL; } if (in->usecase != USECASE_AUDIO_RECORD_MMAP) { return -ENOSYS; } if (in->pcm == NULL) { return -ENOSYS; } struct timespec ts = { 0, 0 }; int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts); if (ret < 0) { ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); return ret; } position->time_nanoseconds = ts2ns(&ts); return 0; } static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, Loading Loading @@ -2991,8 +3345,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) { out->usecase = USECASE_AUDIO_PLAYBACK_ULL; out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL, out->flags); out->usecase = USECASE_AUDIO_PLAYBACK_ULL; out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency; } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) { out->usecase = USECASE_AUDIO_PLAYBACK_MMAP; out->config = pcm_config_mmap_playback; out->stream.start = out_start; out->stream.stop = out_stop; out->stream.create_mmap_buffer = out_create_mmap_buffer; out->stream.get_mmap_position = out_get_mmap_position; } else { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; Loading Loading @@ -3060,7 +3420,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_next_write_timestamp = out_get_next_write_timestamp; out->stream.get_presentation_position = out_get_presentation_position; out->af_period_multiplier = out->realtime ? af_period_multiplier : 1; if (out->realtime) out->af_period_multiplier = af_period_multiplier; else out->af_period_multiplier = 1; out->standby = 1; /* out->muted = false; by calloc() */ /* out->written = 0; by calloc() */ Loading @@ -3087,6 +3451,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, pthread_mutex_unlock(&out->lock); *stream_out = &out->stream; ALOGV("%s: exit", __func__); return 0; Loading Loading @@ -3420,20 +3785,12 @@ static int adev_open_input_stream(struct audio_hw_device *dev, } else { in->usecase = USECASE_AUDIO_RECORD; if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE && (flags & AUDIO_INPUT_FLAG_FAST) != 0) { (in->flags & AUDIO_INPUT_FLAG_FAST) != 0) { is_low_latency = true; #if LOW_LATENCY_CAPTURE_USE_CASE in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY; #endif in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags); } in->config = in->realtime ? pcm_config_audio_capture_rt : pcm_config_audio_capture; if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) in->config.format = PCM_FORMAT_S24_LE; if (!in->realtime) { frame_size = audio_stream_in_frame_size(&in->stream); buffer_size = get_input_buffer_size(config->sample_rate, Loading @@ -3441,16 +3798,40 @@ static int adev_open_input_stream(struct audio_hw_device *dev, channel_count, is_low_latency); in->config.period_size = buffer_size / frame_size; } // period size is left untouched for rt mode playback } in->config.channels = channel_count; if (in->realtime) { in->config = pcm_config_audio_capture; in->config.rate = config->sample_rate; in->af_period_multiplier = 1; } else { // period size is left untouched for rt mode playback in->config = pcm_config_audio_capture_rt; in->af_period_multiplier = af_period_multiplier; } } else if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) && ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) { in->usecase = USECASE_AUDIO_RECORD_MMAP; in->config = pcm_config_mmap_capture; in->stream.start = in_start; in->stream.stop = in_stop; in->stream.create_mmap_buffer = in_create_mmap_buffer; in->stream.get_mmap_position = in_get_mmap_position; in->af_period_multiplier = 1; ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__); } else { in->config = pcm_config_audio_capture; frame_size = audio_stream_in_frame_size(&in->stream); buffer_size = get_input_buffer_size(config->sample_rate, config->format, channel_count, is_low_latency); in->config.period_size = buffer_size / frame_size; in->config.rate = config->sample_rate; in->af_period_multiplier = 1; } if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) in->config.format = PCM_FORMAT_S24_LE; } in->config.channels = channel_count; /* This stream could be for sound trigger lab, get sound trigger pcm if present */ Loading Loading @@ -3741,6 +4122,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->device.open_output_stream = adev_open_output_stream; adev->device.close_output_stream = adev_close_output_stream; adev->device.open_input_stream = adev_open_input_stream; adev->device.close_input_stream = adev_close_input_stream; adev->device.dump = adev_dump; Loading hal/audio_hw.h +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ enum { USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_TTS, USECASE_AUDIO_PLAYBACK_ULL, USECASE_AUDIO_PLAYBACK_MMAP, /* HFP Use case*/ USECASE_AUDIO_HFP_SCO, Loading @@ -79,6 +80,7 @@ enum { /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_LOW_LATENCY, USECASE_AUDIO_RECORD_MMAP, /* Voice extension usecases * Loading Loading @@ -238,6 +240,7 @@ struct stream_in { struct audio_device *dev; audio_format_t format; card_status_t card_status; int capture_started; }; typedef enum usecase_type_t { Loading hal/msm8974/platform.c +11 −1 Original line number Diff line number Diff line Loading @@ -158,12 +158,17 @@ static int pcm_device_table[AUDIO_USECASE_MAX][2] = { MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE, MULTIMEDIA3_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_MMAP] = {MMAP_PLAYBACK_PCM_DEVICE, MMAP_PLAYBACK_PCM_DEVICE}, [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE, MMAP_RECORD_PCM_DEVICE}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, Loading Loading @@ -499,8 +504,10 @@ static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = { {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MMAP)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD_MMAP)}, {TO_NAME_INDEX(USECASE_VOICE_CALL)}, {TO_NAME_INDEX(USECASE_VOICE2_CALL)}, {TO_NAME_INDEX(USECASE_VOLTE_CALL)}, Loading @@ -516,7 +523,8 @@ static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) #define ULL_PLATFORM_DELAY (7*1000LL) #define ULL_PLATFORM_DELAY (3*1000LL) #define MMAP_PLATFORM_DELAY (3*1000LL) static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; static bool is_tmus = false; Loading Loading @@ -2621,6 +2629,8 @@ int64_t platform_render_latency(audio_usecase_t usecase) return LOW_LATENCY_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_ULL: return ULL_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_MMAP: return MMAP_PLATFORM_DELAY; default: return 0; } Loading hal/msm8974/platform.h +3 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,9 @@ enum { #define MULTIMEDIA3_PCM_DEVICE 4 #define MMAP_PLAYBACK_PCM_DEVICE 18 #define MMAP_RECORD_PCM_DEVICE 18 #define QUAT_MI2S_PCM_DEVICE 44 #define PLAYBACK_OFFLOAD_DEVICE 9 #define LOWLATENCY_PCM_DEVICE 15 Loading Loading
hal/audio_hw.c +470 −88 Original line number Diff line number Diff line Loading @@ -83,6 +83,11 @@ static unsigned int configured_low_latency_capture_period_size = LOW_LATENCY_CAPTURE_PERIOD_SIZE; #define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000) #define MMAP_PERIOD_COUNT 512 /* This constant enables extended precision handling. * TODO The flag is off until more testing is done. */ Loading Loading @@ -135,6 +140,19 @@ struct pcm_config pcm_config_hdmi_multi = { .avail_min = 0, }; struct pcm_config pcm_config_mmap_playback = { .channels = DEFAULT_CHANNEL_COUNT, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, .period_size = MMAP_PERIOD_SIZE, .period_count = MMAP_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, .start_threshold = MMAP_PERIOD_SIZE*8, .stop_threshold = INT32_MAX, .silence_threshold = 0, .silence_size = 0, .avail_min = MMAP_PERIOD_SIZE, //1 ms }; struct pcm_config pcm_config_audio_capture = { .channels = DEFAULT_CHANNEL_COUNT, .period_count = AUDIO_CAPTURE_PERIOD_COUNT, Loading @@ -156,6 +174,19 @@ struct pcm_config pcm_config_audio_capture_rt = { .avail_min = ULL_PERIOD_SIZE, //1 ms }; struct pcm_config pcm_config_mmap_capture = { .channels = DEFAULT_CHANNEL_COUNT, .rate = DEFAULT_OUTPUT_SAMPLING_RATE, .period_size = MMAP_PERIOD_SIZE, .period_count = MMAP_PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, .start_threshold = 0, .stop_threshold = INT_MAX, .silence_threshold = 0, .silence_size = 0, .avail_min = MMAP_PERIOD_SIZE, //1 ms }; #define AFE_PROXY_CHANNEL_COUNT 2 #define AFE_PROXY_SAMPLING_RATE 48000 Loading Loading @@ -194,9 +225,11 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback", [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback", [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record", [USECASE_AUDIO_RECORD_MMAP] = "mmap-record", [USECASE_AUDIO_HFP_SCO] = "hfp-sco", [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb", Loading Loading @@ -1276,9 +1309,21 @@ int start_input_stream(struct stream_in *in) 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); if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { if (!pcm_is_ready(in->pcm)) { ALOGE("%s: pcm stream not ready", __func__); goto error_open; } ret = pcm_prepare(in->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret); goto error_open; } ret = pcm_start(in->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret); goto error_open; } } else { unsigned int flags = PCM_IN | PCM_MONOTONIC; unsigned int pcm_open_retry_count = 0; Loading @@ -1289,6 +1334,9 @@ int start_input_stream(struct stream_in *in) flags |= PCM_MMAP | PCM_NOIRQ; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, in->pcm_device_id, in->config.channels); while (1) { in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, flags, &in->config); Loading Loading @@ -1325,11 +1373,12 @@ int start_input_stream(struct stream_in *in) goto error_open; } } } register_in_stream(in); audio_extn_perf_lock_release(); ALOGV("%s: exit", __func__); return ret; return 0; error_open: stop_input_stream(in); Loading Loading @@ -1667,7 +1716,39 @@ int start_output_stream(struct stream_out *out) ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)", __func__, adev->snd_card, out->pcm_device_id, out->config.format); if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { out->pcm = NULL; out->compr = compress_open(adev->snd_card, out->pcm_device_id, COMPRESS_IN, &out->compr_config); if (out->compr && !is_compress_ready(out->compr)) { ALOGE("%s: %s", __func__, compress_get_error(out->compr)); compress_close(out->compr); out->compr = NULL; ret = -EIO; goto error_open; } if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) adev->offload_effects_start_output(out->handle, out->pcm_device_id); } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { if (!pcm_is_ready(out->pcm)) { ALOGE("%s: pcm stream not ready", __func__); goto error_open; } ret = pcm_prepare(out->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_prepare failed ret %d", __func__, ret); goto error_open; } ret = pcm_start(out->pcm); if (ret < 0) { ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret); goto error_open; } } else { unsigned int flags = PCM_OUT; unsigned int pcm_open_retry_count = 0; Loading Loading @@ -1707,26 +1788,6 @@ int start_output_stream(struct stream_out *out) goto error_open; } } } else { out->pcm = NULL; out->compr = compress_open(adev->snd_card, out->pcm_device_id, COMPRESS_IN, &out->compr_config); if (out->compr && !is_compress_ready(out->compr)) { ALOGE("%s: %s", __func__, compress_get_error(out->compr)); compress_close(out->compr); out->compr = NULL; ret = -EIO; goto error_open; } if (out->offload_callback) compress_nonblock(out->compr, out->non_blocking); if (adev->visualizer_start_output != NULL) adev->visualizer_start_output(out->handle, out->pcm_device_id); if (adev->offload_effects_start_output != NULL) adev->offload_effects_start_output(out->handle, out->pcm_device_id); } ret = 0; if (out->realtime) { ret = pcm_start(out->pcm); if (ret < 0) { Loading @@ -1736,12 +1797,13 @@ int start_output_stream(struct stream_out *out) goto error_open; } } } register_out_stream(out); audio_extn_perf_lock_release(); audio_extn_tfa_98xx_enable_speaker(); ALOGV("%s: exit", __func__); return ret; return 0; error_open: audio_extn_perf_lock_release(); stop_output_stream(out); Loading Loading @@ -1864,7 +1926,6 @@ static int out_standby(struct audio_stream *stream) if (!out->standby) { if (adev->adm_deregister_stream) adev->adm_deregister_stream(adev->adm_data, out->handle); pthread_mutex_lock(&adev->lock); out->standby = true; if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) { Loading @@ -1872,6 +1933,9 @@ static int out_standby(struct audio_stream *stream) pcm_close(out->pcm); out->pcm = NULL; } if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { out->playback_started = false; } } else { stop_compressed_output_l(out); out->gapless_mdata.encoder_delay = 0; Loading Loading @@ -2111,7 +2175,8 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream) if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) return COMPRESS_OFFLOAD_PLAYBACK_LATENCY; else if (out->realtime) { else if ((out->realtime) || (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) { // since the buffer won't be filled up faster than realtime, // return a smaller number period_ms = (out->af_period_multiplier * out->config.period_size * Loading Loading @@ -2225,6 +2290,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, int error_code = ERROR_CODE_STANDBY; lock_output_stream(out); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) { error_code = ERROR_CODE_WRITE; goto exit; } if (out->standby) { out->standby = false; pthread_mutex_lock(&adev->lock); Loading Loading @@ -2491,6 +2560,143 @@ static int out_flush(struct audio_stream_out* stream) return -ENOSYS; } static int out_stop(const struct audio_stream_out* stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby && out->playback_started && out->pcm != NULL) { pcm_stop(out->pcm); ret = stop_output_stream(out); if (ret == 0) { out->playback_started = false; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_start(const struct audio_stream_out* stream) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby && !out->playback_started && out->pcm != NULL) { ret = start_output_stream(out); if (ret == 0) { out->playback_started = true; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_create_mmap_buffer(const struct audio_stream_out *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info) { struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; int ret = 0; unsigned int offset1; unsigned int frames1; const char *step = ""; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (info == NULL || min_size_frames == 0) { ret = -EINVAL; goto exit; } if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) { ret = -ENOSYS; goto exit; } 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)", __func__, out->pcm_device_id, out->usecase); ret = -EINVAL; goto exit; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, out->pcm_device_id, out->config.channels); out->pcm = pcm_open(adev->snd_card, out->pcm_device_id, (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config); if (out->pcm == NULL || !pcm_is_ready(out->pcm)) { step = "open"; ret = -ENODEV; goto exit; } ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1); if (ret < 0) { step = "begin"; goto exit; } info->buffer_size_frames = pcm_get_buffer_size(out->pcm); info->burst_size_frames = out->config.period_size; info->shared_memory_fd = pcm_get_poll_fd(out->pcm); memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm, info->buffer_size_frames)); ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE); if (ret < 0) { step = "commit"; goto exit; } ret = 0; ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d", __func__, info->shared_memory_address, info->buffer_size_frames); exit: if (ret != 0) { ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm)); if (out->pcm != NULL) { pcm_close(out->pcm); out->pcm = NULL; } } pthread_mutex_unlock(&adev->lock); return ret; } static int out_get_mmap_position(const struct audio_stream_out *stream, struct audio_mmap_position *position) { struct stream_out *out = (struct stream_out *)stream; ALOGVV("%s", __func__); if (position == NULL) { return -EINVAL; } if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) { return -ENOSYS; } if (out->pcm == NULL) { return -ENOSYS; } struct timespec ts = { 0, 0 }; int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts); if (ret < 0) { ALOGE("%s: %s", __func__, pcm_get_error(out->pcm)); return ret; } position->time_nanoseconds = ts2ns(&ts); return 0; } /** audio_stream_in implementation **/ static uint32_t in_get_sample_rate(const struct audio_stream *stream) { Loading Loading @@ -2551,6 +2757,9 @@ static int in_standby(struct audio_stream *stream) pthread_mutex_lock(&adev->lock); in->standby = true; if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { in->capture_started = false; } if (in->pcm) { pcm_close(in->pcm); in->pcm = NULL; Loading Loading @@ -2685,6 +2894,11 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, return bytes; } if (in->usecase == USECASE_AUDIO_RECORD_MMAP) { ret = -ENOSYS; goto exit; } if (in->standby) { pthread_mutex_lock(&adev->lock); ret = start_input_stream(in); Loading Loading @@ -2845,6 +3059,146 @@ static int in_remove_audio_effect(const struct audio_stream *stream, return add_remove_audio_effect(stream, effect, false); } static int in_stop(const struct audio_stream_in* stream) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = -ENOSYS; ALOGV("%s", __func__); pthread_mutex_lock(&adev->lock); if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby && in->capture_started && in->pcm != NULL) { pcm_stop(in->pcm); ret = stop_input_stream(in); if (ret == 0) { in->capture_started = false; } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_start(const struct audio_stream_in* stream) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = -ENOSYS; ALOGV("%s in %p", __func__, in); pthread_mutex_lock(&adev->lock); if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby && !in->capture_started && in->pcm != NULL) { if (!in->capture_started) { ret = start_input_stream(in); if (ret == 0) { in->capture_started = true; } } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_create_mmap_buffer(const struct audio_stream_in *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int ret = 0; unsigned int offset1; unsigned int frames1; const char *step = ""; pthread_mutex_lock(&adev->lock); ALOGV("%s in %p", __func__, in); if (info == NULL || min_size_frames == 0) { ALOGV("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames); ret = -EINVAL; goto exit; } if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) { ALOGV("%s in %p", __func__, in); ret = -ENOSYS; goto exit; } in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE); if (in->pcm_device_id < 0) { ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)", __func__, in->pcm_device_id, in->usecase); ret = -EINVAL; goto exit; } ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d", __func__, adev->snd_card, in->pcm_device_id, in->config.channels); in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config); if (in->pcm == NULL || !pcm_is_ready(in->pcm)) { step = "open"; ret = -ENODEV; goto exit; } ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1); if (ret < 0) { step = "begin"; goto exit; } info->buffer_size_frames = pcm_get_buffer_size(in->pcm); info->burst_size_frames = in->config.period_size; info->shared_memory_fd = pcm_get_poll_fd(in->pcm); memset(info->shared_memory_address, 0, pcm_frames_to_bytes(in->pcm, info->buffer_size_frames)); ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE); if (ret < 0) { step = "commit"; goto exit; } ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d", __func__, info->shared_memory_address, info->buffer_size_frames); ret = 0; exit: if (ret != 0) { ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm)); if (in->pcm != NULL) { pcm_close(in->pcm); in->pcm = NULL; } } pthread_mutex_unlock(&adev->lock); return ret; } static int in_get_mmap_position(const struct audio_stream_in *stream, struct audio_mmap_position *position) { struct stream_in *in = (struct stream_in *)stream; ALOGVV("%s", __func__); if (position == NULL) { return -EINVAL; } if (in->usecase != USECASE_AUDIO_RECORD_MMAP) { return -ENOSYS; } if (in->pcm == NULL) { return -ENOSYS; } struct timespec ts = { 0, 0 }; int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts); if (ret < 0) { ALOGE("%s: %s", __func__, pcm_get_error(in->pcm)); return ret; } position->time_nanoseconds = ts2ns(&ts); return 0; } static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, Loading Loading @@ -2991,8 +3345,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) { out->usecase = USECASE_AUDIO_PLAYBACK_ULL; out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL, out->flags); out->usecase = USECASE_AUDIO_PLAYBACK_ULL; out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency; } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) { out->usecase = USECASE_AUDIO_PLAYBACK_MMAP; out->config = pcm_config_mmap_playback; out->stream.start = out_start; out->stream.stop = out_stop; out->stream.create_mmap_buffer = out_create_mmap_buffer; out->stream.get_mmap_position = out_get_mmap_position; } else { out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY; out->config = pcm_config_low_latency; Loading Loading @@ -3060,7 +3420,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_next_write_timestamp = out_get_next_write_timestamp; out->stream.get_presentation_position = out_get_presentation_position; out->af_period_multiplier = out->realtime ? af_period_multiplier : 1; if (out->realtime) out->af_period_multiplier = af_period_multiplier; else out->af_period_multiplier = 1; out->standby = 1; /* out->muted = false; by calloc() */ /* out->written = 0; by calloc() */ Loading @@ -3087,6 +3451,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, pthread_mutex_unlock(&out->lock); *stream_out = &out->stream; ALOGV("%s: exit", __func__); return 0; Loading Loading @@ -3420,20 +3785,12 @@ static int adev_open_input_stream(struct audio_hw_device *dev, } else { in->usecase = USECASE_AUDIO_RECORD; if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE && (flags & AUDIO_INPUT_FLAG_FAST) != 0) { (in->flags & AUDIO_INPUT_FLAG_FAST) != 0) { is_low_latency = true; #if LOW_LATENCY_CAPTURE_USE_CASE in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY; #endif in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags); } in->config = in->realtime ? pcm_config_audio_capture_rt : pcm_config_audio_capture; if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) in->config.format = PCM_FORMAT_S24_LE; if (!in->realtime) { frame_size = audio_stream_in_frame_size(&in->stream); buffer_size = get_input_buffer_size(config->sample_rate, Loading @@ -3441,16 +3798,40 @@ static int adev_open_input_stream(struct audio_hw_device *dev, channel_count, is_low_latency); in->config.period_size = buffer_size / frame_size; } // period size is left untouched for rt mode playback } in->config.channels = channel_count; if (in->realtime) { in->config = pcm_config_audio_capture; in->config.rate = config->sample_rate; in->af_period_multiplier = 1; } else { // period size is left untouched for rt mode playback in->config = pcm_config_audio_capture_rt; in->af_period_multiplier = af_period_multiplier; } } else if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) && ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) { in->usecase = USECASE_AUDIO_RECORD_MMAP; in->config = pcm_config_mmap_capture; in->stream.start = in_start; in->stream.stop = in_stop; in->stream.create_mmap_buffer = in_create_mmap_buffer; in->stream.get_mmap_position = in_get_mmap_position; in->af_period_multiplier = 1; ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__); } else { in->config = pcm_config_audio_capture; frame_size = audio_stream_in_frame_size(&in->stream); buffer_size = get_input_buffer_size(config->sample_rate, config->format, channel_count, is_low_latency); in->config.period_size = buffer_size / frame_size; in->config.rate = config->sample_rate; in->af_period_multiplier = 1; } if (config->format == AUDIO_FORMAT_PCM_8_24_BIT) in->config.format = PCM_FORMAT_S24_LE; } in->config.channels = channel_count; /* This stream could be for sound trigger lab, get sound trigger pcm if present */ Loading Loading @@ -3741,6 +4122,7 @@ static int adev_open(const hw_module_t *module, const char *name, adev->device.open_output_stream = adev_open_output_stream; adev->device.close_output_stream = adev_close_output_stream; adev->device.open_input_stream = adev_open_input_stream; adev->device.close_input_stream = adev_close_input_stream; adev->device.dump = adev_dump; Loading
hal/audio_hw.h +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ enum { USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_TTS, USECASE_AUDIO_PLAYBACK_ULL, USECASE_AUDIO_PLAYBACK_MMAP, /* HFP Use case*/ USECASE_AUDIO_HFP_SCO, Loading @@ -79,6 +80,7 @@ enum { /* Capture usecases */ USECASE_AUDIO_RECORD, USECASE_AUDIO_RECORD_LOW_LATENCY, USECASE_AUDIO_RECORD_MMAP, /* Voice extension usecases * Loading Loading @@ -238,6 +240,7 @@ struct stream_in { struct audio_device *dev; audio_format_t format; card_status_t card_status; int capture_started; }; typedef enum usecase_type_t { Loading
hal/msm8974/platform.c +11 −1 Original line number Diff line number Diff line Loading @@ -158,12 +158,17 @@ static int pcm_device_table[AUDIO_USECASE_MAX][2] = { MULTIMEDIA2_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE, MULTIMEDIA3_PCM_DEVICE}, [USECASE_AUDIO_PLAYBACK_MMAP] = {MMAP_PLAYBACK_PCM_DEVICE, MMAP_PLAYBACK_PCM_DEVICE}, [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE}, [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE, LOWLATENCY_PCM_DEVICE}, [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE, MMAP_RECORD_PCM_DEVICE}, [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE}, [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE}, Loading Loading @@ -499,8 +504,10 @@ static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = { {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)}, {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MMAP)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)}, {TO_NAME_INDEX(USECASE_AUDIO_RECORD_MMAP)}, {TO_NAME_INDEX(USECASE_VOICE_CALL)}, {TO_NAME_INDEX(USECASE_VOICE2_CALL)}, {TO_NAME_INDEX(USECASE_VOLTE_CALL)}, Loading @@ -516,7 +523,8 @@ static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) #define ULL_PLATFORM_DELAY (7*1000LL) #define ULL_PLATFORM_DELAY (3*1000LL) #define MMAP_PLATFORM_DELAY (3*1000LL) static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT; static bool is_tmus = false; Loading Loading @@ -2621,6 +2629,8 @@ int64_t platform_render_latency(audio_usecase_t usecase) return LOW_LATENCY_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_ULL: return ULL_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_MMAP: return MMAP_PLATFORM_DELAY; default: return 0; } Loading
hal/msm8974/platform.h +3 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,9 @@ enum { #define MULTIMEDIA3_PCM_DEVICE 4 #define MMAP_PLAYBACK_PCM_DEVICE 18 #define MMAP_RECORD_PCM_DEVICE 18 #define QUAT_MI2S_PCM_DEVICE 44 #define PLAYBACK_OFFLOAD_DEVICE 9 #define LOWLATENCY_PCM_DEVICE 15 Loading