Loading hal/audio_extn/audio_extn.h +1 −12 Original line number Diff line number Diff line /* * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project Loading Loading @@ -40,17 +40,6 @@ #include <cutils/str_parms.h> #ifndef PCM_OFFLOAD_ENABLED #define AUDIO_FORMAT_PCM_OFFLOAD 0x1A000000UL #define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT) #define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT) #define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" #define audio_is_offload_pcm(format) (0) #define OFFLOAD_USE_SMALL_BUFFER false #else #define OFFLOAD_USE_SMALL_BUFFER ((info->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD) #endif #ifndef AFE_PROXY_ENABLED #define AUDIO_DEVICE_OUT_PROXY 0x40000 #endif Loading hal/audio_extn/utils.c +3 −4 Original line number Diff line number Diff line Loading @@ -76,6 +76,8 @@ const struct string_to_enum s_flag_name_to_enum_table[] = { const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT), STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED), STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT), STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT), STRING_TO_ENUM(AUDIO_FORMAT_MP3), STRING_TO_ENUM(AUDIO_FORMAT_AAC), Loading @@ -97,8 +99,6 @@ const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_QCELP), STRING_TO_ENUM(AUDIO_FORMAT_MP2), STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW), STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD), STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD), STRING_TO_ENUM(AUDIO_FORMAT_FLAC), STRING_TO_ENUM(AUDIO_FORMAT_ALAC), STRING_TO_ENUM(AUDIO_FORMAT_APE), Loading Loading @@ -558,8 +558,7 @@ int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase) goto exit_send_app_type_cfg; } if ((24 == usecase->stream.out->bit_width) && (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) { if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) { sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; } else { sample_rate = out->app_type_cfg.sample_rate; Loading hal/audio_hw.c +147 −63 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ #include "sound/asound.h" #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 /*DIRECT PCM has same buffer sizes as DEEP Buffer*/ #define DIRECT_PCM_NUM_FRAGMENTS 2 /* ToDo: Check and update a proper value in msec */ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 Loading Loading @@ -168,8 +170,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback", [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", #ifdef MULTIPLE_OFFLOAD_ENABLED [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2", #ifdef MULTIPLE_OFFLOAD_ENABLED [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3", [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4", [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5", Loading @@ -178,7 +180,6 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8", [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9", #endif [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] = "compress-offload-playback2", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", Loading Loading @@ -213,8 +214,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { static const audio_usecase_t offload_usecases[] = { USECASE_AUDIO_PLAYBACK_OFFLOAD, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD2, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD3, USECASE_AUDIO_PLAYBACK_OFFLOAD4, USECASE_AUDIO_PLAYBACK_OFFLOAD5, Loading @@ -223,7 +224,6 @@ static const audio_usecase_t offload_usecases[] = { USECASE_AUDIO_PLAYBACK_OFFLOAD8, USECASE_AUDIO_PLAYBACK_OFFLOAD9, #endif USECASE_AUDIO_DIRECT_PCM_OFFLOAD, }; #define STRING_TO_ENUM(string) { #string, string } Loading Loading @@ -254,17 +254,16 @@ static pthread_mutex_t adev_init_lock; static unsigned int audio_device_ref_count; static int check_and_set_gapless_mode(struct audio_device *adev) { char value[PROPERTY_VALUE_MAX] = {0}; static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless) { bool gapless_enabled = false; const char *mixer_ctl_name = "Compress Gapless Playback"; struct mixer_ctl *ctl; ALOGV("%s:", __func__); property_get("audio.offload.gapless.enabled", value, NULL); gapless_enabled = atoi(value) || !strncmp("true", value, 4); gapless_enabled = property_get_bool("audio.offload.gapless.enabled", false); /*Disable gapless if its AV playback*/ gapless_enabled = gapless_enabled && enable_gapless; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { Loading @@ -287,8 +286,8 @@ static bool is_supported_format(audio_format_t format) format == AUDIO_FORMAT_AAC_LC || format == AUDIO_FORMAT_AAC_HE_V1 || format == AUDIO_FORMAT_AAC_HE_V2 || format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD || format == AUDIO_FORMAT_PCM_24_BIT_PACKED || format == AUDIO_FORMAT_PCM_8_24_BIT || format == AUDIO_FORMAT_PCM_16_BIT || format == AUDIO_FORMAT_FLAC || format == AUDIO_FORMAT_ALAC || Loading @@ -312,7 +311,6 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; case AUDIO_FORMAT_PCM_OFFLOAD: case AUDIO_FORMAT_PCM: id = SND_AUDIOCODEC_PCM; break; Loading Loading @@ -1196,26 +1194,33 @@ bool is_offload_usecase(audio_usecase_t uc_id) return false; } static audio_usecase_t get_offload_usecase(struct audio_device *adev) static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_direct_pcm) { audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD; unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]); char value[PROPERTY_VALUE_MAX] = {0}; property_get("audio.offload.multiple.enabled", value, NULL); if (!(atoi(value) || !strncmp("true", value, 4))) num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */ audio_usecase_t ret_uc = USECASE_INVALID; unsigned int offload_uc_index; unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]); if (!adev->multi_offload_enable) { if (is_direct_pcm) ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2; else ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD; pthread_mutex_lock(&adev->lock); if (get_usecase_from_list(adev, ret_uc) != NULL) ret_uc = USECASE_INVALID; pthread_mutex_unlock(&adev->lock); return ret_uc; } ALOGV("%s: num_usecase: %d", __func__, num_usecase); for (i = 0; i < num_usecase; i++) { if (!(adev->offload_usecases_state & (0x1<<i))) { adev->offload_usecases_state |= 0x1 << i; ret = offload_usecases[i]; for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) { if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) { adev->offload_usecases_state |= 0x1 << offload_uc_index; ret_uc = offload_usecases[offload_uc_index]; break; } } ALOGV("%s: offload usecase is %d", __func__, ret); return ret; ALOGV("%s: offload usecase is %d", __func__, ret_uc); return ret_uc; } static void free_offload_usecase(struct audio_device *adev, Loading Loading @@ -1647,7 +1652,7 @@ int start_output_stream(struct stream_out *out) for the default max poll time (20s) in the event of an SSR. Reduce the poll time to observe and deal with SSR faster. */ if (out->use_small_bufs) { if (!out->non_blocking) { compress_set_max_poll_wait(out->compr, 1000); } Loading @@ -1664,7 +1669,7 @@ int start_output_stream(struct stream_out *out) 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); adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer); audio_extn_check_and_set_dts_hpx_state(adev); } } Loading Loading @@ -1743,6 +1748,37 @@ static size_t get_input_buffer_size(uint32_t sample_rate, return size; } static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out) { uint64_t actual_frames_rendered = 0; size_t kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments; /* This adjustment accounts for buffering after app processor. * It is based on estimated DSP latency per use case, rather than exact. */ int64_t platform_latency = platform_render_latency(out->usecase) * out->sample_rate / 1000000LL; /* not querying actual state of buffering in kernel as it would involve an ioctl call * which then needs protection, this causes delay in TS query for pcm_offload usecase * hence only estimate. */ int64_t signed_frames = out->written - kernel_buffer_size; signed_frames = signed_frames / (audio_bytes_per_sample(out->format) * popcount(out->channel_mask)) - platform_latency; if (signed_frames > 0) actual_frames_rendered = signed_frames; ALOGVV("%s signed frames %lld out_written %lld kernel_buffer_size %d" "bytes/sample %zu channel count %d", __func__,(long long int)signed_frames, (long long int)out->written, (int)kernel_buffer_size, audio_bytes_per_sample(out->compr_config.codec->format), popcount(out->channel_mask)); return actual_frames_rendered; } static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; Loading Loading @@ -2203,6 +2239,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, out_standby(&out->stream.common); return ret; } if ( ret == (ssize_t)bytes && !out->non_blocking) out->written += bytes; if (!out->playback_started && ret >= 0) { compress_start(out->compr); audio_extn_dts_eagle_fade(adev, true, out); Loading Loading @@ -2277,8 +2316,18 @@ static int out_get_render_position(const struct audio_stream_out *stream, *dsp_frames = 0; if (is_offload_usecase(out->usecase)) { ssize_t ret = 0; /* Below piece of code is not guarded against any lock beacuse audioFliner serializes * this operation and adev_close_output_stream(where out gets reset). */ if (!out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { *dsp_frames = get_actual_pcm_frames_rendered(out); ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate); return 0; } lock_output_stream(out); if (out->compr != NULL) { if (out->compr != NULL && out->non_blocking) { ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, &out->sample_rate); if (ret < 0) Loading Loading @@ -2329,19 +2378,36 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, int ret = -1; unsigned long dsp_frames; /* below piece of code is not guarded against any lock because audioFliner serializes * this operation and adev_close_output_stream( where out gets reset). */ if (is_offload_usecase(out->usecase) && !out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { *frames = get_actual_pcm_frames_rendered(out); /* this is the best we can do */ clock_gettime(CLOCK_MONOTONIC, timestamp); ALOGVV("frames %lld playedat %lld",(long long int)*frames, timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000); return 0; } lock_output_stream(out); if (is_offload_usecase(out->usecase)) { if (out->compr != NULL) { compress_get_tstamp(out->compr, &dsp_frames, if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) { ret = compress_get_tstamp(out->compr, &dsp_frames, &out->sample_rate); ALOGVV("%s rendered frames %ld sample_rate %d", __func__, dsp_frames, out->sample_rate); *frames = dsp_frames; if (ret < 0) ret = -errno; if (-ENETRESET == ret) { ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver"); set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); ret = -EINVAL; } else ret = 0; /* this is the best we can do */ clock_gettime(CLOCK_MONOTONIC, timestamp); } } else { if (out->pcm) { unsigned int avail; Loading Loading @@ -2458,6 +2524,7 @@ static int out_flush(struct audio_stream_out* stream) ALOGD("copl(%p):calling compress flush", out); lock_output_stream(out); stop_compressed_output_l(out); out->written = 0; pthread_mutex_unlock(&out->lock); ALOGD("copl(%p):out of compress flush", out); return 0; Loading Loading @@ -2853,7 +2920,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; out->non_blocking = 0; out->use_small_bufs = false; /* Init use case and pcm_config */ if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) && Loading Loading @@ -2929,11 +2995,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { ALOGV("%s:: inserting DIRECT_PCM _USECASE", __func__); out->usecase = USECASE_AUDIO_DIRECT_PCM_OFFLOAD; out->stream.pause = out_pause; out->stream.flush = out_flush; out->stream.resume = out_resume; out->usecase = get_offload_usecase(adev, true); ALOGV("DIRECT_PCM usecase ... usecase selected %d ", out->usecase); } else { ALOGV("%s:: inserting OFFLOAD_USECASE", __func__); out->usecase = get_offload_usecase(adev); out->usecase = get_offload_usecase(adev, false); out->stream.set_callback = out_set_callback; out->stream.pause = out_pause; Loading @@ -2941,6 +3010,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.drain = out_drain; out->stream.flush = out_flush; } if (out->usecase == USECASE_INVALID) { if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL && config->format == 0 && config->sample_rate == 0 && config->channel_mask == 0) { ALOGI("%s dummy open to query sink capability",__func__); out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; } else { ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__); ret = -EEXIST; goto error_open; } } if (config->offload_info.channel_mask) out->channel_mask = config->offload_info.channel_mask; else if (config->channel_mask) { Loading @@ -2960,18 +3042,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); if (((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)|| ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM)) { if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) { out->compr_config.fragment_size = platform_get_pcm_offload_buffer_size(&config->offload_info); out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS; } else if (audio_extn_dolby_is_passthrough_stream(out->flags)) { out->compr_config.fragment_size = audio_extn_dolby_get_passt_buffer_size(&config->offload_info); out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; } else { out->compr_config.fragment_size = platform_get_compress_offload_buffer_size(&config->offload_info); } out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; } out->compr_config.codec->sample_rate = config->offload_info.sample_rate; out->compr_config.codec->bit_rate = Loading @@ -2985,16 +3068,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (config->offload_info.format == AUDIO_FORMAT_AAC) out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; if (out->bit_width == 24) { if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_3LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_8_24_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; } if (config->offload_info.format == AUDIO_FORMAT_FLAC) out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH; Loading @@ -3002,15 +3081,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; if (platform_use_small_buffer(&config->offload_info)) { //this flag is set from framework only if its for PCM formats //no need to check for PCM format again out->non_blocking = 0; out->use_small_bufs = true; ALOGI("Keep write blocking for small buff: non_blockling %d", out->non_blocking); } out->send_new_metadata = 1; out->send_next_track_params = false; out->is_compr_metadata_avail = false; Loading @@ -3023,8 +3093,21 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); //Decide if we need to use gapless mode by default check_and_set_gapless_mode(adev); /* Disable gapless if any of the following is true * passthrough playback * AV playback * Direct PCM playback */ if (audio_extn_dolby_is_passthrough_stream(out->flags) || config->offload_info.has_video || out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { check_and_set_gapless_mode(adev, false); } else check_and_set_gapless_mode(adev, true); if (audio_extn_dolby_is_passthrough_stream(out->flags)) { out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH; } } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); if (ret != 0) { Loading Loading @@ -3812,7 +3895,7 @@ static int adev_open(const hw_module_t *module, const char *name, ALOGV("%s: DLOPEN successful for %s", __func__, OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); adev->offload_effects_start_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib, "offload_effects_bundle_hal_start_output"); adev->offload_effects_stop_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, Loading Loading @@ -3874,6 +3957,7 @@ static int adev_open(const hw_module_t *module, const char *name, } } adev->multi_offload_enable = property_get_bool("audio.offload.multiple.enabled", false); pthread_mutex_unlock(&adev_init_lock); if (adev->adm_init) Loading hal/audio_hw.h +3 −6 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project Loading Loading @@ -85,7 +85,6 @@ enum { USECASE_AUDIO_PLAYBACK_LOW_LATENCY, USECASE_AUDIO_PLAYBACK_MULTI_CH, USECASE_AUDIO_PLAYBACK_OFFLOAD, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD2, USECASE_AUDIO_PLAYBACK_OFFLOAD3, USECASE_AUDIO_PLAYBACK_OFFLOAD4, Loading @@ -94,10 +93,8 @@ enum { USECASE_AUDIO_PLAYBACK_OFFLOAD7, USECASE_AUDIO_PLAYBACK_OFFLOAD8, USECASE_AUDIO_PLAYBACK_OFFLOAD9, #endif USECASE_AUDIO_PLAYBACK_ULL, USECASE_AUDIO_DIRECT_PCM_OFFLOAD, /* FM usecase */ USECASE_AUDIO_PLAYBACK_FM, Loading Loading @@ -206,7 +203,6 @@ struct stream_out { struct stream_app_type_cfg app_type_cfg; int non_blocking; bool use_small_bufs; int playback_started; int offload_state; pthread_cond_t offload_cond; Loading Loading @@ -334,7 +330,7 @@ struct audio_device { int (*visualizer_start_output)(audio_io_handle_t, int); int (*visualizer_stop_output)(audio_io_handle_t, int); void *offload_effects_lib; int (*offload_effects_start_output)(audio_io_handle_t, int); int (*offload_effects_start_output)(audio_io_handle_t, int, struct mixer *); int (*offload_effects_stop_output)(audio_io_handle_t, int); struct sound_card_status snd_card_status; Loading @@ -349,6 +345,7 @@ struct audio_device { adm_deregister_stream_t adm_deregister_stream; adm_request_focus_t adm_request_focus; adm_abandon_focus_t adm_abandon_focus; bool multi_offload_enable; }; int select_devices(struct audio_device *adev, Loading hal/msm8916/platform.c +12 −13 Original line number Diff line number Diff line Loading @@ -522,6 +522,7 @@ static int msm_device_to_be_id_external_codec [][NO_COLS] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) static void query_platform(const char *snd_card_name, Loading Loading @@ -2392,7 +2393,7 @@ void platform_get_parameters(void *platform, free(kv_pairs); } /* Delay in Us */ /* Delay in Us, only to be used for PCM formats */ int64_t platform_render_latency(audio_usecase_t usecase) { switch (usecase) { Loading @@ -2400,6 +2401,9 @@ int64_t platform_render_latency(audio_usecase_t usecase) return DEEP_BUFFER_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: return LOW_LATENCY_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_PLAYBACK_OFFLOAD2: return PCM_OFFLOAD_PLATFORM_DELAY; default: return 0; } Loading Loading @@ -2435,7 +2439,6 @@ bool platform_listen_usecase_needs_event(audio_usecase_t uc_id) case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: case USECASE_AUDIO_PLAYBACK_MULTI_CH: case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_DIRECT_PCM_OFFLOAD: needs_event = true; break; /* concurrent playback in low latency allowed */ Loading Loading @@ -2497,7 +2500,6 @@ bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id) case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: case USECASE_AUDIO_PLAYBACK_MULTI_CH: case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_DIRECT_PCM_OFFLOAD: needs_event = true; break; /* concurrent playback in low latency allowed */ Loading Loading @@ -2569,19 +2571,17 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) { uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; uint32_t bits_per_sample = 16; uint32_t bytes_per_sample; uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION; if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { bits_per_sample = 32; } bytes_per_sample = audio_bytes_per_sample(info->format); //duration is set to 40 ms worth of stereo data at 48Khz //with 16 bit per sample, modify this when the channel //configuration is different fragment_size = (pcm_offload_time * info->sample_rate * (bits_per_sample >> 3) * bytes_per_sample * popcount(info->channel_mask))/1000; fragment_size = ALIGN( fragment_size, 1024); Loading @@ -2590,15 +2590,14 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE) fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; // To have same PCM samples for all channels, the buffer size requires to // be multiple of (number of channels * bytes per sample) // For writes to succeed, the buffer must be written at address which is multiple of 32 fragment_size = ALIGN(fragment_size, ((bytes_per_sample) * popcount(info->channel_mask) * 32)); ALOGV("%s: fragment_size %d", __func__, fragment_size); return fragment_size; } bool platform_use_small_buffer(audio_offload_info_t* info) { return OFFLOAD_USE_SMALL_BUFFER; } void platform_get_device_to_be_id_map(int **device_to_be_id, int *length) { *device_to_be_id = msm_device_to_be_id; Loading Loading
hal/audio_extn/audio_extn.h +1 −12 Original line number Diff line number Diff line /* * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2013 The Android Open Source Project Loading Loading @@ -40,17 +40,6 @@ #include <cutils/str_parms.h> #ifndef PCM_OFFLOAD_ENABLED #define AUDIO_FORMAT_PCM_OFFLOAD 0x1A000000UL #define AUDIO_FORMAT_PCM_16_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_16_BIT) #define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT) #define AUDIO_OFFLOAD_CODEC_FORMAT "music_offload_codec_format" #define audio_is_offload_pcm(format) (0) #define OFFLOAD_USE_SMALL_BUFFER false #else #define OFFLOAD_USE_SMALL_BUFFER ((info->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD) #endif #ifndef AFE_PROXY_ENABLED #define AUDIO_DEVICE_OUT_PROXY 0x40000 #endif Loading
hal/audio_extn/utils.c +3 −4 Original line number Diff line number Diff line Loading @@ -76,6 +76,8 @@ const struct string_to_enum s_flag_name_to_enum_table[] = { const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT), STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED), STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT), STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT), STRING_TO_ENUM(AUDIO_FORMAT_MP3), STRING_TO_ENUM(AUDIO_FORMAT_AAC), Loading @@ -97,8 +99,6 @@ const struct string_to_enum s_format_name_to_enum_table[] = { STRING_TO_ENUM(AUDIO_FORMAT_QCELP), STRING_TO_ENUM(AUDIO_FORMAT_MP2), STRING_TO_ENUM(AUDIO_FORMAT_EVRCNW), STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD), STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD), STRING_TO_ENUM(AUDIO_FORMAT_FLAC), STRING_TO_ENUM(AUDIO_FORMAT_ALAC), STRING_TO_ENUM(AUDIO_FORMAT_APE), Loading Loading @@ -558,8 +558,7 @@ int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase) goto exit_send_app_type_cfg; } if ((24 == usecase->stream.out->bit_width) && (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) { if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) { sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE; } else { sample_rate = out->app_type_cfg.sample_rate; Loading
hal/audio_hw.c +147 −63 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ #include "sound/asound.h" #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4 /*DIRECT PCM has same buffer sizes as DEEP Buffer*/ #define DIRECT_PCM_NUM_FRAGMENTS 2 /* ToDo: Check and update a proper value in msec */ #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000 Loading Loading @@ -168,8 +170,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback", [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback", [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", #ifdef MULTIPLE_OFFLOAD_ENABLED [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2", #ifdef MULTIPLE_OFFLOAD_ENABLED [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3", [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4", [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5", Loading @@ -178,7 +180,6 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8", [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9", #endif [USECASE_AUDIO_DIRECT_PCM_OFFLOAD] = "compress-offload-playback2", [USECASE_AUDIO_RECORD] = "audio-record", [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress", Loading Loading @@ -213,8 +214,8 @@ const char * const use_case_table[AUDIO_USECASE_MAX] = { static const audio_usecase_t offload_usecases[] = { USECASE_AUDIO_PLAYBACK_OFFLOAD, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD2, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD3, USECASE_AUDIO_PLAYBACK_OFFLOAD4, USECASE_AUDIO_PLAYBACK_OFFLOAD5, Loading @@ -223,7 +224,6 @@ static const audio_usecase_t offload_usecases[] = { USECASE_AUDIO_PLAYBACK_OFFLOAD8, USECASE_AUDIO_PLAYBACK_OFFLOAD9, #endif USECASE_AUDIO_DIRECT_PCM_OFFLOAD, }; #define STRING_TO_ENUM(string) { #string, string } Loading Loading @@ -254,17 +254,16 @@ static pthread_mutex_t adev_init_lock; static unsigned int audio_device_ref_count; static int check_and_set_gapless_mode(struct audio_device *adev) { char value[PROPERTY_VALUE_MAX] = {0}; static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless) { bool gapless_enabled = false; const char *mixer_ctl_name = "Compress Gapless Playback"; struct mixer_ctl *ctl; ALOGV("%s:", __func__); property_get("audio.offload.gapless.enabled", value, NULL); gapless_enabled = atoi(value) || !strncmp("true", value, 4); gapless_enabled = property_get_bool("audio.offload.gapless.enabled", false); /*Disable gapless if its AV playback*/ gapless_enabled = gapless_enabled && enable_gapless; ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name); if (!ctl) { Loading @@ -287,8 +286,8 @@ static bool is_supported_format(audio_format_t format) format == AUDIO_FORMAT_AAC_LC || format == AUDIO_FORMAT_AAC_HE_V1 || format == AUDIO_FORMAT_AAC_HE_V2 || format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD || format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD || format == AUDIO_FORMAT_PCM_24_BIT_PACKED || format == AUDIO_FORMAT_PCM_8_24_BIT || format == AUDIO_FORMAT_PCM_16_BIT || format == AUDIO_FORMAT_FLAC || format == AUDIO_FORMAT_ALAC || Loading @@ -312,7 +311,6 @@ static int get_snd_codec_id(audio_format_t format) case AUDIO_FORMAT_AAC: id = SND_AUDIOCODEC_AAC; break; case AUDIO_FORMAT_PCM_OFFLOAD: case AUDIO_FORMAT_PCM: id = SND_AUDIOCODEC_PCM; break; Loading Loading @@ -1196,26 +1194,33 @@ bool is_offload_usecase(audio_usecase_t uc_id) return false; } static audio_usecase_t get_offload_usecase(struct audio_device *adev) static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_direct_pcm) { audio_usecase_t ret = USECASE_AUDIO_PLAYBACK_OFFLOAD; unsigned int i, num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]); char value[PROPERTY_VALUE_MAX] = {0}; property_get("audio.offload.multiple.enabled", value, NULL); if (!(atoi(value) || !strncmp("true", value, 4))) num_usecase = 1; /* If prop is not set, limit the num of offload usecases to 1 */ audio_usecase_t ret_uc = USECASE_INVALID; unsigned int offload_uc_index; unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]); if (!adev->multi_offload_enable) { if (is_direct_pcm) ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2; else ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD; pthread_mutex_lock(&adev->lock); if (get_usecase_from_list(adev, ret_uc) != NULL) ret_uc = USECASE_INVALID; pthread_mutex_unlock(&adev->lock); return ret_uc; } ALOGV("%s: num_usecase: %d", __func__, num_usecase); for (i = 0; i < num_usecase; i++) { if (!(adev->offload_usecases_state & (0x1<<i))) { adev->offload_usecases_state |= 0x1 << i; ret = offload_usecases[i]; for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) { if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) { adev->offload_usecases_state |= 0x1 << offload_uc_index; ret_uc = offload_usecases[offload_uc_index]; break; } } ALOGV("%s: offload usecase is %d", __func__, ret); return ret; ALOGV("%s: offload usecase is %d", __func__, ret_uc); return ret_uc; } static void free_offload_usecase(struct audio_device *adev, Loading Loading @@ -1647,7 +1652,7 @@ int start_output_stream(struct stream_out *out) for the default max poll time (20s) in the event of an SSR. Reduce the poll time to observe and deal with SSR faster. */ if (out->use_small_bufs) { if (!out->non_blocking) { compress_set_max_poll_wait(out->compr, 1000); } Loading @@ -1664,7 +1669,7 @@ int start_output_stream(struct stream_out *out) 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); adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer); audio_extn_check_and_set_dts_hpx_state(adev); } } Loading Loading @@ -1743,6 +1748,37 @@ static size_t get_input_buffer_size(uint32_t sample_rate, return size; } static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out) { uint64_t actual_frames_rendered = 0; size_t kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments; /* This adjustment accounts for buffering after app processor. * It is based on estimated DSP latency per use case, rather than exact. */ int64_t platform_latency = platform_render_latency(out->usecase) * out->sample_rate / 1000000LL; /* not querying actual state of buffering in kernel as it would involve an ioctl call * which then needs protection, this causes delay in TS query for pcm_offload usecase * hence only estimate. */ int64_t signed_frames = out->written - kernel_buffer_size; signed_frames = signed_frames / (audio_bytes_per_sample(out->format) * popcount(out->channel_mask)) - platform_latency; if (signed_frames > 0) actual_frames_rendered = signed_frames; ALOGVV("%s signed frames %lld out_written %lld kernel_buffer_size %d" "bytes/sample %zu channel count %d", __func__,(long long int)signed_frames, (long long int)out->written, (int)kernel_buffer_size, audio_bytes_per_sample(out->compr_config.codec->format), popcount(out->channel_mask)); return actual_frames_rendered; } static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct stream_out *out = (struct stream_out *)stream; Loading Loading @@ -2203,6 +2239,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, out_standby(&out->stream.common); return ret; } if ( ret == (ssize_t)bytes && !out->non_blocking) out->written += bytes; if (!out->playback_started && ret >= 0) { compress_start(out->compr); audio_extn_dts_eagle_fade(adev, true, out); Loading Loading @@ -2277,8 +2316,18 @@ static int out_get_render_position(const struct audio_stream_out *stream, *dsp_frames = 0; if (is_offload_usecase(out->usecase)) { ssize_t ret = 0; /* Below piece of code is not guarded against any lock beacuse audioFliner serializes * this operation and adev_close_output_stream(where out gets reset). */ if (!out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { *dsp_frames = get_actual_pcm_frames_rendered(out); ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate); return 0; } lock_output_stream(out); if (out->compr != NULL) { if (out->compr != NULL && out->non_blocking) { ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames, &out->sample_rate); if (ret < 0) Loading Loading @@ -2329,19 +2378,36 @@ static int out_get_presentation_position(const struct audio_stream_out *stream, int ret = -1; unsigned long dsp_frames; /* below piece of code is not guarded against any lock because audioFliner serializes * this operation and adev_close_output_stream( where out gets reset). */ if (is_offload_usecase(out->usecase) && !out->non_blocking && (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) { *frames = get_actual_pcm_frames_rendered(out); /* this is the best we can do */ clock_gettime(CLOCK_MONOTONIC, timestamp); ALOGVV("frames %lld playedat %lld",(long long int)*frames, timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000); return 0; } lock_output_stream(out); if (is_offload_usecase(out->usecase)) { if (out->compr != NULL) { compress_get_tstamp(out->compr, &dsp_frames, if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) { ret = compress_get_tstamp(out->compr, &dsp_frames, &out->sample_rate); ALOGVV("%s rendered frames %ld sample_rate %d", __func__, dsp_frames, out->sample_rate); *frames = dsp_frames; if (ret < 0) ret = -errno; if (-ENETRESET == ret) { ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver"); set_snd_card_state(adev,SND_CARD_STATE_OFFLINE); ret = -EINVAL; } else ret = 0; /* this is the best we can do */ clock_gettime(CLOCK_MONOTONIC, timestamp); } } else { if (out->pcm) { unsigned int avail; Loading Loading @@ -2458,6 +2524,7 @@ static int out_flush(struct audio_stream_out* stream) ALOGD("copl(%p):calling compress flush", out); lock_output_stream(out); stop_compressed_output_l(out); out->written = 0; pthread_mutex_unlock(&out->lock); ALOGD("copl(%p):out of compress flush", out); return 0; Loading Loading @@ -2853,7 +2920,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->handle = handle; out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH; out->non_blocking = 0; out->use_small_bufs = false; /* Init use case and pcm_config */ if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) && Loading Loading @@ -2929,11 +2995,14 @@ static int adev_open_output_stream(struct audio_hw_device *dev, } if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { ALOGV("%s:: inserting DIRECT_PCM _USECASE", __func__); out->usecase = USECASE_AUDIO_DIRECT_PCM_OFFLOAD; out->stream.pause = out_pause; out->stream.flush = out_flush; out->stream.resume = out_resume; out->usecase = get_offload_usecase(adev, true); ALOGV("DIRECT_PCM usecase ... usecase selected %d ", out->usecase); } else { ALOGV("%s:: inserting OFFLOAD_USECASE", __func__); out->usecase = get_offload_usecase(adev); out->usecase = get_offload_usecase(adev, false); out->stream.set_callback = out_set_callback; out->stream.pause = out_pause; Loading @@ -2941,6 +3010,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.drain = out_drain; out->stream.flush = out_flush; } if (out->usecase == USECASE_INVALID) { if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL && config->format == 0 && config->sample_rate == 0 && config->channel_mask == 0) { ALOGI("%s dummy open to query sink capability",__func__); out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD; } else { ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__); ret = -EEXIST; goto error_open; } } if (config->offload_info.channel_mask) out->channel_mask = config->offload_info.channel_mask; else if (config->channel_mask) { Loading @@ -2960,18 +3042,19 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format); if (((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD)|| ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM)) { if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) { out->compr_config.fragment_size = platform_get_pcm_offload_buffer_size(&config->offload_info); out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS; } else if (audio_extn_dolby_is_passthrough_stream(out->flags)) { out->compr_config.fragment_size = audio_extn_dolby_get_passt_buffer_size(&config->offload_info); out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; } else { out->compr_config.fragment_size = platform_get_compress_offload_buffer_size(&config->offload_info); } out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS; } out->compr_config.codec->sample_rate = config->offload_info.sample_rate; out->compr_config.codec->bit_rate = Loading @@ -2985,16 +3068,12 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (config->offload_info.format == AUDIO_FORMAT_AAC) out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW; if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE; if (out->bit_width == 24) { if (config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_PACKED) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_3LE; if (config->offload_info.format == AUDIO_FORMAT_PCM_8_24_BIT) out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE; } if (config->offload_info.format == AUDIO_FORMAT_FLAC) out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH; Loading @@ -3002,15 +3081,6 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) out->non_blocking = 1; if (platform_use_small_buffer(&config->offload_info)) { //this flag is set from framework only if its for PCM formats //no need to check for PCM format again out->non_blocking = 0; out->use_small_bufs = true; ALOGI("Keep write blocking for small buff: non_blockling %d", out->non_blocking); } out->send_new_metadata = 1; out->send_next_track_params = false; out->is_compr_metadata_avail = false; Loading @@ -3023,8 +3093,21 @@ static int adev_open_output_stream(struct audio_hw_device *dev, ALOGV("%s: offloaded output offload_info version %04x bit rate %d", __func__, config->offload_info.version, config->offload_info.bit_rate); //Decide if we need to use gapless mode by default check_and_set_gapless_mode(adev); /* Disable gapless if any of the following is true * passthrough playback * AV playback * Direct PCM playback */ if (audio_extn_dolby_is_passthrough_stream(out->flags) || config->offload_info.has_video || out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { check_and_set_gapless_mode(adev, false); } else check_and_set_gapless_mode(adev, true); if (audio_extn_dolby_is_passthrough_stream(out->flags)) { out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH; } } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) { ret = voice_check_and_set_incall_music_usecase(adev, out); if (ret != 0) { Loading Loading @@ -3812,7 +3895,7 @@ static int adev_open(const hw_module_t *module, const char *name, ALOGV("%s: DLOPEN successful for %s", __func__, OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); adev->offload_effects_start_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib, "offload_effects_bundle_hal_start_output"); adev->offload_effects_stop_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, Loading Loading @@ -3874,6 +3957,7 @@ static int adev_open(const hw_module_t *module, const char *name, } } adev->multi_offload_enable = property_get_bool("audio.offload.multiple.enabled", false); pthread_mutex_unlock(&adev_init_lock); if (adev->adm_init) Loading
hal/audio_hw.h +3 −6 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * Not a contribution. * * Copyright (C) 2013 The Android Open Source Project Loading Loading @@ -85,7 +85,6 @@ enum { USECASE_AUDIO_PLAYBACK_LOW_LATENCY, USECASE_AUDIO_PLAYBACK_MULTI_CH, USECASE_AUDIO_PLAYBACK_OFFLOAD, #ifdef MULTIPLE_OFFLOAD_ENABLED USECASE_AUDIO_PLAYBACK_OFFLOAD2, USECASE_AUDIO_PLAYBACK_OFFLOAD3, USECASE_AUDIO_PLAYBACK_OFFLOAD4, Loading @@ -94,10 +93,8 @@ enum { USECASE_AUDIO_PLAYBACK_OFFLOAD7, USECASE_AUDIO_PLAYBACK_OFFLOAD8, USECASE_AUDIO_PLAYBACK_OFFLOAD9, #endif USECASE_AUDIO_PLAYBACK_ULL, USECASE_AUDIO_DIRECT_PCM_OFFLOAD, /* FM usecase */ USECASE_AUDIO_PLAYBACK_FM, Loading Loading @@ -206,7 +203,6 @@ struct stream_out { struct stream_app_type_cfg app_type_cfg; int non_blocking; bool use_small_bufs; int playback_started; int offload_state; pthread_cond_t offload_cond; Loading Loading @@ -334,7 +330,7 @@ struct audio_device { int (*visualizer_start_output)(audio_io_handle_t, int); int (*visualizer_stop_output)(audio_io_handle_t, int); void *offload_effects_lib; int (*offload_effects_start_output)(audio_io_handle_t, int); int (*offload_effects_start_output)(audio_io_handle_t, int, struct mixer *); int (*offload_effects_stop_output)(audio_io_handle_t, int); struct sound_card_status snd_card_status; Loading @@ -349,6 +345,7 @@ struct audio_device { adm_deregister_stream_t adm_deregister_stream; adm_request_focus_t adm_request_focus; adm_abandon_focus_t adm_abandon_focus; bool multi_offload_enable; }; int select_devices(struct audio_device *adev, Loading
hal/msm8916/platform.c +12 −13 Original line number Diff line number Diff line Loading @@ -522,6 +522,7 @@ static int msm_device_to_be_id_external_codec [][NO_COLS] = { #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL) #define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL) #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL) static void query_platform(const char *snd_card_name, Loading Loading @@ -2392,7 +2393,7 @@ void platform_get_parameters(void *platform, free(kv_pairs); } /* Delay in Us */ /* Delay in Us, only to be used for PCM formats */ int64_t platform_render_latency(audio_usecase_t usecase) { switch (usecase) { Loading @@ -2400,6 +2401,9 @@ int64_t platform_render_latency(audio_usecase_t usecase) return DEEP_BUFFER_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_LOW_LATENCY: return LOW_LATENCY_PLATFORM_DELAY; case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_PLAYBACK_OFFLOAD2: return PCM_OFFLOAD_PLATFORM_DELAY; default: return 0; } Loading Loading @@ -2435,7 +2439,6 @@ bool platform_listen_usecase_needs_event(audio_usecase_t uc_id) case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: case USECASE_AUDIO_PLAYBACK_MULTI_CH: case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_DIRECT_PCM_OFFLOAD: needs_event = true; break; /* concurrent playback in low latency allowed */ Loading Loading @@ -2497,7 +2500,6 @@ bool platform_sound_trigger_usecase_needs_event(audio_usecase_t uc_id) case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER: case USECASE_AUDIO_PLAYBACK_MULTI_CH: case USECASE_AUDIO_PLAYBACK_OFFLOAD: case USECASE_AUDIO_DIRECT_PCM_OFFLOAD: needs_event = true; break; /* concurrent playback in low latency allowed */ Loading Loading @@ -2569,19 +2571,17 @@ uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info) uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) { uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE; uint32_t bits_per_sample = 16; uint32_t bytes_per_sample; uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION; if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { bits_per_sample = 32; } bytes_per_sample = audio_bytes_per_sample(info->format); //duration is set to 40 ms worth of stereo data at 48Khz //with 16 bit per sample, modify this when the channel //configuration is different fragment_size = (pcm_offload_time * info->sample_rate * (bits_per_sample >> 3) * bytes_per_sample * popcount(info->channel_mask))/1000; fragment_size = ALIGN( fragment_size, 1024); Loading @@ -2590,15 +2590,14 @@ uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info) else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE) fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE; // To have same PCM samples for all channels, the buffer size requires to // be multiple of (number of channels * bytes per sample) // For writes to succeed, the buffer must be written at address which is multiple of 32 fragment_size = ALIGN(fragment_size, ((bytes_per_sample) * popcount(info->channel_mask) * 32)); ALOGV("%s: fragment_size %d", __func__, fragment_size); return fragment_size; } bool platform_use_small_buffer(audio_offload_info_t* info) { return OFFLOAD_USE_SMALL_BUFFER; } void platform_get_device_to_be_id_map(int **device_to_be_id, int *length) { *device_to_be_id = msm_device_to_be_id; Loading