9335 lines
369 KiB
C
9335 lines
369 KiB
C
/*
|
||
* Copyright (C) 2017 Amlogic Corporation.
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
#define LOG_TAG "audio_hw_hal_primary"
|
||
//#define LOG_NDEBUG 0
|
||
|
||
#include <errno.h>
|
||
#include <pthread.h>
|
||
#include <stdint.h>
|
||
#include <stdlib.h>
|
||
#include <fcntl.h>
|
||
#include <time.h>
|
||
#include <inttypes.h>
|
||
#include <sys/time.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/prctl.h>
|
||
#include "aml_audio_log.h"
|
||
#include <cutils/atomic.h>
|
||
#include <cutils/str_parms.h>
|
||
#include <linux/ioctl.h>
|
||
#include <hardware/hardware.h>
|
||
#include <system/audio.h>
|
||
#include <audio_utils/channels.h>
|
||
#include <memory.h>
|
||
#include <unistd.h>
|
||
#include "aml_dec_api.h"
|
||
#include "Virtualx.h"
|
||
|
||
|
||
#if ANDROID_PLATFORM_SDK_VERSION >= 25 //8.0
|
||
#include <system/audio-base.h>
|
||
#endif
|
||
|
||
#include <hardware/audio.h>
|
||
#include <audio_route/audio_route.h>
|
||
#include <aml_alsa_mixer.h>
|
||
#ifndef NO_AUDIO_CAP
|
||
#include <IpcBuffer/IpcBuffer_c.h>
|
||
#endif
|
||
#include "aml_capture_output.h"
|
||
#include "tv_patch_format_parser.h"
|
||
#include "SPDIFEncoderAD.h"
|
||
#include "aml_volume_utils.h"
|
||
#include "aml_data_utils.h"
|
||
#include "alsa_manager.h"
|
||
#include "aml_audio_stream.h"
|
||
#include "audio_hw.h"
|
||
#include "spdif_encoder_api.h"
|
||
#include "audio_hw_utils.h"
|
||
#include "audio_hw_profile.h"
|
||
#include "aml_dump_debug.h"
|
||
#include "alsa_manager.h"
|
||
#include "alsa_device_parser.h"
|
||
#include "aml_audio_stream.h"
|
||
#include "alsa_config_parameters.h"
|
||
#include "spdif_encoder_api.h"
|
||
#include "tv_patch_avsync.h"
|
||
#include "aml_ng.h"
|
||
#include "aml_audio_timer.h"
|
||
#include "aml_audio_ease.h"
|
||
#include "aml_audio_spdifout.h"
|
||
#include "aml_config_parser.h"
|
||
#include "audio_effect_if.h"
|
||
#include "aml_audio_nonms12_render.h"
|
||
#include "aml_audio_uevent.h"
|
||
#include "external_output_manager.h"
|
||
#include "external_output_handle.h"
|
||
#include "audio_mpegh.h"
|
||
#include "aml_audio_command_worker.h"
|
||
#include "aml_audio_ai_config.h"
|
||
|
||
//#ifdef ENABLE_MMAP
|
||
#ifndef BUILD_LINUX
|
||
#include "aml_mmap_audio.h"
|
||
#endif
|
||
// for invoke bluetooth rc hal
|
||
#ifndef BUILD_LINUX
|
||
#include "audio_hal_thunks.h"
|
||
#endif
|
||
#include "earc_utils.h"
|
||
#include <SPDIFEncoderAD.h>
|
||
#include "audio_hw_ms12_common.h"
|
||
#include "aml_audio_ms12_sync.h"
|
||
|
||
#include "tv_patch_ctrl.h"
|
||
#include "tv_patch.h"
|
||
#include "hdmirx_utils.h"
|
||
|
||
#include "dmx_audio_es.h"
|
||
#include "aml_audio_ms12_render.h"
|
||
#include "aml_audio_nonms12_render.h"
|
||
#include "aml_config_data.h"
|
||
#include "aml_audio_spdifdec.h"
|
||
#include "audio_hw_resource_mgr.h"
|
||
#include "device_patch.h"
|
||
#include "aml_noise_gate.h"
|
||
#include "tv_private_object.h"
|
||
#include "hdmirx_utils.h"
|
||
#include "dtv_private_object.h"
|
||
#include "aml_audio_output.h"
|
||
#include "audio_ms12_continuous_standby.h"
|
||
#include "audio_parser.h"
|
||
#include "aml_audio_parser.h"
|
||
#include "audio_mpegh.h"
|
||
#include "format.h"
|
||
#include "aml_audio_limiter.h"
|
||
#include "aml_policy.h"
|
||
|
||
#ifdef USE_MEDIAINFO
|
||
#include "aml_media_info.h"
|
||
#endif
|
||
|
||
// for dtv playback
|
||
#include "dtv_patch.h"
|
||
/*Google Voice Assistant channel_mask */
|
||
#define BUILT_IN_MIC 12
|
||
|
||
//#define SUBMIXER_V1_1
|
||
#define HDMI_LATENCY_MS 60
|
||
|
||
#include "amlAudioMixer.h"
|
||
#include "aml_malloc_debug.h"
|
||
|
||
#include <audio_effects/effect_aec.h>
|
||
#include <audio_utils/clock.h>
|
||
#include "audio_hal_version.h"
|
||
#include "audio_hw_ms12_v2.h"
|
||
#include "aml_audio_scaletempo.h"
|
||
#include "audio_mediasync.h"
|
||
#include "karaoke_manager.h"
|
||
#include "aml_audio_property.h"
|
||
#include "aml_hwmixer_manager.h"
|
||
#include "deep_buffer_unit.h"
|
||
#include "aml_dts_chmask_table.h"
|
||
#include "audio_llp.h"
|
||
#include "mixer_out_unit.h"
|
||
#include "deep_buffer_unit.h"
|
||
|
||
#ifdef L_PROJECT
|
||
#include "audio_controls.h"
|
||
#endif
|
||
|
||
#undef PLAYBACK_PERIOD_COUNT
|
||
#define PLAYBACK_PERIOD_COUNT 4
|
||
/* number of periods for capture */
|
||
#undef CAPTURE_PERIOD_COUNT
|
||
#define CAPTURE_PERIOD_COUNT 4
|
||
|
||
/*Google Voice Assistant channel_mask */
|
||
#define BUILT_IN_MIC 12
|
||
|
||
/* minimum sleep time in out_write() when write threshold is not reached */
|
||
#define MIN_WRITE_SLEEP_US 5000
|
||
#undef RESAMPLER_BUFFER_FRAMES
|
||
#define RESAMPLER_BUFFER_FRAMES (PERIOD_SIZE * 6)
|
||
#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES)
|
||
#define NSEC_PER_SECOND 1000000000ULL
|
||
|
||
/* sampling rate when using MM low power port */
|
||
#define MM_LOW_POWER_SAMPLING_RATE 44100
|
||
/* sampling rate when using MM full power port */
|
||
#define MM_FULL_POWER_SAMPLING_RATE 48000
|
||
/* sampling rate when using VX port for narrow band */
|
||
#define AEC_CAP_SAMPLING_RATE 16000
|
||
#define DOLBY_MS12_INPUT_FORMAT_TEST
|
||
|
||
#define IEC61937_PACKET_SIZE_OF_AC3 (0x1800)
|
||
#define IEC61937_PACKET_SIZE_OF_EAC3 (0x6000)
|
||
|
||
#define MAX_INPUT_STREAM_CNT (3)
|
||
#define AML_AEC_MIC_CHANNEL_NUM (2)
|
||
|
||
#define NETFLIX_DDP_BUFSIZE (768)
|
||
#define MAX_SPK_EXTRA_LATENCY_MS (100)
|
||
#define DEFAULT_SPK_EXTRA_LATENCY_MS (15)
|
||
#define SPDIF_RBUF_DATA_STORAGE_MS (256)
|
||
#define AML_LIMITER_PROC_FRAME (128)
|
||
|
||
/*Tunnel sync HEADER is 20 bytes*/
|
||
#define TUNNEL_SYNC_HEADER_SIZE (20)
|
||
|
||
#define DISABLE_CONTINUOUS_OUTPUT "persist.vendor.audio.continuous.disable"
|
||
|
||
static const struct pcm_config pcm_config_out = {
|
||
.channels = 2,
|
||
.rate = MM_FULL_POWER_SAMPLING_RATE,
|
||
.period_size = DEFAULT_PLAYBACK_PERIOD_SIZE,
|
||
.period_count = DEFAULT_PLAYBACK_PERIOD_CNT,
|
||
.format = PCM_FORMAT_S16_LE,
|
||
};
|
||
|
||
static const struct pcm_config pcm_config_out_direct = {
|
||
.channels = 2,
|
||
.rate = MM_FULL_POWER_SAMPLING_RATE,
|
||
.period_size = DEFAULT_PLAYBACK_PERIOD_SIZE,
|
||
.period_count = PLAYBACK_PERIOD_COUNT,
|
||
.format = PCM_FORMAT_S16_LE,
|
||
};
|
||
|
||
static const struct pcm_config pcm_config_aec = {
|
||
.channels = 4,
|
||
.rate = AEC_CAP_SAMPLING_RATE,
|
||
.period_size = DEFAULT_CAPTURE_PERIOD_SIZE,
|
||
.period_count = CAPTURE_PERIOD_COUNT,
|
||
.format = PCM_FORMAT_S16_LE,
|
||
.start_threshold = 0,
|
||
.stop_threshold = 0,
|
||
.avail_min = 0,
|
||
};
|
||
|
||
static int adev_set_voice_volume (struct audio_hw_device *dev, float volume);
|
||
//static int do_output_standby_l (struct audio_stream *out);
|
||
static uint32_t out_get_sample_rate (const struct audio_stream *stream);
|
||
static int stream_type_validate_l (struct aml_stream_out *aml_out, uint32_t flags);
|
||
static inline bool need_hw_mix(usecase_mask_t masks);
|
||
//static int out_standby_new(struct audio_stream *stream);
|
||
static int adev_open_output_stream(struct audio_hw_device *dev,
|
||
audio_io_handle_t handle __unused,
|
||
audio_devices_t devices,
|
||
audio_output_flags_t flags,
|
||
struct audio_config *config,
|
||
struct audio_stream_out **stream_out,
|
||
const char *address __unused);
|
||
static void adev_close_output_stream(struct audio_hw_device *dev,
|
||
struct audio_stream_out *stream);
|
||
static int set_hdmi_format(struct aml_audio_device *adev, int val);
|
||
|
||
static ssize_t out_write_new(struct audio_stream_out *stream,
|
||
const void *buffer,
|
||
size_t bytes);
|
||
static int out_get_presentation_position (const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp);
|
||
static int out_standby_new(struct audio_stream *stream);
|
||
|
||
static int adev_get_mic_mute(const struct audio_hw_device* dev, bool* state);
|
||
static int adev_get_microphones(const struct audio_hw_device* dev,
|
||
struct audio_microphone_characteristic_t* mic_array,
|
||
size_t* mic_count);
|
||
static void get_mic_characteristics(struct audio_microphone_characteristic_t* mic_data,
|
||
size_t* mic_count);
|
||
|
||
static int aml_audio_focus(struct aml_audio_device *adev, bool on);
|
||
static int adev_get_dvb_standards();
|
||
static int adev_remove_device_effect(struct audio_hw_device *dev, audio_port_handle_t device, effect_handle_t effect);
|
||
static void set_vol_ease_by_stream (struct aml_stream_out *aml_out, int gain, int duration, int shape);
|
||
|
||
static inline bool need_hw_mix(usecase_mask_t masks)
|
||
{
|
||
return (masks > 1);
|
||
}
|
||
|
||
static inline short CLIP (int r)
|
||
{
|
||
return (r > 0x7fff) ? 0x7fff :
|
||
(r < -0x8000) ? -0x8000 :
|
||
r;
|
||
}
|
||
|
||
static void select_mode (struct aml_audio_device *adev)
|
||
{
|
||
ALOGD ("%s(out_device=%#x)", __FUNCTION__, adev->out_device);
|
||
ALOGD ("%s(in_device=%#x)", __FUNCTION__, adev->in_device);
|
||
return;
|
||
|
||
/* force earpiece route for in call state if speaker is the
|
||
only currently selected route. This prevents having to tear
|
||
down the modem PCMs to change route from speaker to earpiece
|
||
after the ringtone is played, but doesn't cause a route
|
||
change if a headset or bt device is already connected. If
|
||
speaker is not the only thing active, just remove it from
|
||
the route. We'll assume it'll never be used initally during
|
||
a call. This works because we're sure that the audio policy
|
||
manager will update the output device after the audio mode
|
||
change, even if the device selection did not change. */
|
||
/*coverity[UNREACHABLE]*/
|
||
if ( (adev->out_device & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER) {
|
||
adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
|
||
} else {
|
||
adev->out_device &= ~AUDIO_DEVICE_OUT_SPEAKER;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count, audio_devices_t devices)
|
||
{
|
||
ALOGD("%s(sample_rate=%d, format=%d, channel_count=%d, devices = %x)", __FUNCTION__, sample_rate, format, channel_count, devices);
|
||
|
||
if(AUDIO_DEVICE_IN_DEFAULT == devices && AUDIO_CHANNEL_NONE == channel_count &&
|
||
AUDIO_FORMAT_DEFAULT == format && 0 == sample_rate) {
|
||
/* Add for Hidl6.0:CloseDeviceWithOpenedInputStreams test */
|
||
return -ENOSYS; /*Currently System Not Supported.*/
|
||
}
|
||
|
||
if (format != AUDIO_FORMAT_PCM_16_BIT && format != AUDIO_FORMAT_PCM_32_BIT) {
|
||
ALOGE("%s: unsupported AUDIO FORMAT (%d)", __func__, format);
|
||
return -EINVAL;
|
||
}
|
||
|
||
if (channel_count < 1 || channel_count > 4 || channel_count == 3) {
|
||
ALOGE("%s: unsupported channel count (%d) passed Min / Max (1 / 2)", __func__, channel_count);
|
||
return -EINVAL;
|
||
}
|
||
|
||
switch (sample_rate) {
|
||
case 8000:
|
||
case 11025:
|
||
/*fallthrough*/
|
||
case 12000:
|
||
case 16000:
|
||
case 17000:
|
||
case 22050:
|
||
case 24000:
|
||
case 32000:
|
||
case 44100:
|
||
case 48000:
|
||
case 96000:
|
||
break;
|
||
default:
|
||
ALOGE("%s: unsupported (%d) samplerate passed ", __func__, sample_rate);
|
||
return -EINVAL;
|
||
}
|
||
|
||
devices &= ~AUDIO_DEVICE_BIT_IN;
|
||
if ((devices & AUDIO_DEVICE_IN_LINE) ||
|
||
(devices & AUDIO_DEVICE_IN_SPDIF) ||
|
||
(devices & AUDIO_DEVICE_IN_TV_TUNER) ||
|
||
(devices & AUDIO_DEVICE_IN_HDMI) ||
|
||
(devices & AUDIO_DEVICE_IN_HDMI1) ||
|
||
(devices & AUDIO_DEVICE_IN_HDMI_ARC)) {
|
||
if ((format == AUDIO_FORMAT_PCM_16_BIT || format == AUDIO_FORMAT_PCM_32_BIT) &&
|
||
channel_count == 2 &&
|
||
sample_rate == 48000) {
|
||
ALOGD("%s: audio patch input device %x", __FUNCTION__, devices);
|
||
return 0;
|
||
} else {
|
||
ALOGE("%s: unspported audio patch input device %x", __FUNCTION__, devices);
|
||
return -EINVAL;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static size_t get_input_buffer_size(unsigned int period_size, uint32_t sample_rate, audio_format_t format, int channel_count)
|
||
{
|
||
size_t size;
|
||
|
||
ALOGD("%s(sample_rate=%d, format=%d, channel_count=%d)", __FUNCTION__, sample_rate, format, channel_count);
|
||
/*
|
||
if (check_input_parameters(sample_rate, format, channel_count, AUDIO_DEVICE_NONE) != 0) {
|
||
return 0;
|
||
}
|
||
*/
|
||
/* take resampling into account and return the closest majoring
|
||
multiple of 16 frames, as audioflinger expects audio buffers to
|
||
be a multiple of 16 frames */
|
||
if (period_size == 0)
|
||
period_size = (DEFAULT_CAPTURE_PERIOD_SIZE * sample_rate) / MM_FULL_POWER_SAMPLING_RATE;
|
||
size = (period_size + 15) / 16 * 16;
|
||
|
||
if (format == AUDIO_FORMAT_PCM_32_BIT)
|
||
return size * channel_count * sizeof(int32_t);
|
||
else
|
||
return size * channel_count * sizeof(int16_t);
|
||
}
|
||
|
||
static uint32_t out_get_sample_rate(const struct audio_stream *stream)
|
||
{
|
||
const struct aml_stream_out *out = (const struct aml_stream_out *) stream;
|
||
unsigned int rate = out->hal_rate;
|
||
ALOGV("Amlogic_HAL - out_get_sample_rate() = %d", rate);
|
||
return rate;
|
||
}
|
||
|
||
static int out_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static void unmute_after_eos_received(struct aml_stream_out *aml_out) {
|
||
struct aml_audio_device *aml_dev = aml_out->dev;
|
||
if (true == aml_out->with_header && true == aml_out->eos) {
|
||
audio_header_info_reset(aml_out->pheader);
|
||
aml_out->eos = false;
|
||
if (aml_dev->dolby_lib_type != eDolbyMS12Lib) {
|
||
set_aed_master_volume_mute(&aml_dev->alsa_mixer, false);
|
||
} else {
|
||
//unmute
|
||
ease_setting_t vol_setting;
|
||
vol_setting.duration = 32;
|
||
vol_setting.start_volume = aml_out->volume_l;
|
||
vol_setting.target_volume = aml_out->volume_l;
|
||
vol_setting.ease_shape = EaseLinear;
|
||
aml_audio_ease_config(aml_out->vol_process_handle, &vol_setting);
|
||
}
|
||
}
|
||
AM_LOGI("unmute after eos received done");
|
||
}
|
||
|
||
static uint32_t out_get_latency (const struct audio_stream_out *stream)
|
||
{
|
||
const struct aml_stream_out *out = (const struct aml_stream_out *) stream;
|
||
const struct aml_audio_device *adev = out->dev;
|
||
int buffer_frames = 0;
|
||
int ret = 0;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && out->is_normal_pcm) {
|
||
ret = dolby_ms12_get_system_buffer_frame(&buffer_frames);
|
||
if (ret < 0) {
|
||
AM_LOGE("get available system buffer error!");
|
||
}
|
||
} else {
|
||
ret = out_get_latency_frames (stream) * audio_stream_out_frame_size(stream);
|
||
}
|
||
return buffer_frames * 4;
|
||
}
|
||
|
||
static size_t out_get_buffer_size (const struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
ALOGI("%s(out->config.rate=%d, format %x,stream format %x)", __FUNCTION__,
|
||
out->config.rate, out->hal_internal_format, stream->get_format(stream));
|
||
/* take resampling into account and return the closest majoring
|
||
* multiple of 16 frames, as audioflinger expects audio buffers to
|
||
* be a multiple of 16 frames
|
||
*/
|
||
int size = out->config.period_size;
|
||
int ret = 0;
|
||
switch (out->hal_internal_format) {
|
||
case AUDIO_FORMAT_AC3:
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = AC3_PERIOD_SIZE;
|
||
ALOGI("%s AUDIO_FORMAT_IEC61937 %d)", __FUNCTION__, size);
|
||
if ((eDolbyDcvLib == adev->dolby_lib_type) &&
|
||
(out->flags & AUDIO_OUTPUT_FLAG_DIRECT)) {
|
||
// local file playback, data from audio flinger direct mode
|
||
// the data is packed by DCV decoder by OMX, 1536 samples per packet
|
||
// to match with it, set the size to 1536
|
||
// (ms12 decoder doesn't encounter this issue, so only handle with DCV decoder case)
|
||
size = AC3_PERIOD_SIZE / 4;
|
||
ALOGI("%s AUDIO_FORMAT_IEC61937(DIRECT) (eDolbyDcvLib) size = %d)", __FUNCTION__, size);
|
||
}
|
||
} else if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
|
||
size = AC3_PERIOD_SIZE;
|
||
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
|
||
size = (DEFAULT_PLAYBACK_PERIOD_SIZE << 1);
|
||
} else {
|
||
size = DEFAULT_PLAYBACK_PERIOD_SIZE;
|
||
}
|
||
break;
|
||
case AUDIO_FORMAT_E_AC3:
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = EAC3_PERIOD_SIZE;
|
||
} else if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
|
||
size = EAC3_PERIOD_SIZE;//one iec61937 packet size
|
||
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
|
||
size = (DEFAULT_PLAYBACK_PERIOD_SIZE << 3) + (DEFAULT_PLAYBACK_PERIOD_SIZE << 1);
|
||
} else {
|
||
/*frame align*/
|
||
if (1 /* adev->continuous_audio_mode */) {
|
||
/*Tunnel sync HEADER is 16 bytes*/
|
||
if ((out->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) && out->with_header) {
|
||
size = out->ddp_frame_size + 20;
|
||
} else {
|
||
size = out->ddp_frame_size * 4;
|
||
}
|
||
} else {
|
||
size = PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE; //PERIOD_SIZE;
|
||
}
|
||
}
|
||
|
||
if (eDolbyDcvLib == adev->dolby_lib_type_last) {
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE;
|
||
ALOGI("%s eac3 eDolbyDcvLib = size%d)", __FUNCTION__, size);
|
||
}
|
||
}
|
||
/*netflix ddp size is 768, if we change to a big value, then
|
||
*every process time is too long, it will cause such case failed SWPL-41439
|
||
*/
|
||
if (adev->is_netflix) {
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
|
||
size = NETFLIX_DDP_BUFSIZE + 20;
|
||
} else {
|
||
size = NETFLIX_DDP_BUFSIZE;
|
||
}
|
||
}
|
||
break;
|
||
case AUDIO_FORMAT_AC4:
|
||
/*
|
||
*1.offload write interval is 10ms
|
||
*2.AC4 datarate: ac4 frame size=16391 frame rate =23440 sample rate=48000
|
||
* 16391Bytes/42.6ms
|
||
*3.set the audio hal buffer size as 8192 Bytes, it is about 24ms
|
||
*/
|
||
size = (DEFAULT_PLAYBACK_PERIOD_SIZE << 4);
|
||
break;
|
||
case AUDIO_FORMAT_DOLBY_TRUEHD:
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) {
|
||
size = 16 * DEFAULT_PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
|
||
} else {
|
||
size = PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE;
|
||
}
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = 4 * PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE;
|
||
}
|
||
break;
|
||
case AUDIO_FORMAT_DTS:
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = DTS1_PERIOD_SIZE / 2;
|
||
} else {
|
||
size = DTS_OFFLOAD_BUFFER_MAX_SIZE;
|
||
}
|
||
ALOGI("%s AUDIO_FORMAT_DTS buffer size = %d frames", __FUNCTION__, size);
|
||
break;
|
||
case AUDIO_FORMAT_DTS_HD:
|
||
if (stream->get_format(stream) == AUDIO_FORMAT_IEC61937) {
|
||
size = 4 * PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE;
|
||
} else {
|
||
size = DTS_OFFLOAD_BUFFER_MAX_SIZE;
|
||
}
|
||
ALOGI("%s AUDIO_FORMAT_DTS_HD buffer size = %d frames", __FUNCTION__, size);
|
||
break;
|
||
#if 0
|
||
case AUDIO_FORMAT_PCM:
|
||
if (adev->continuous_audio_mode) {
|
||
/*Tunnel sync HEADER is 16 bytes*/
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
|
||
size = (8192 + 16) / 4;
|
||
}
|
||
}
|
||
#endif
|
||
default:
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if (out->is_normal_pcm) {
|
||
if (adev->dev_ms12_version == eDolbyMS12_V282) {
|
||
ret = dolby_ms12_get_system_buffer_avail(NULL) * audio_stream_out_frame_size((struct audio_stream_out *)stream);;
|
||
} else {
|
||
ret = dolby_ms12_get_system_buffer_avail(&size);
|
||
}
|
||
|
||
if (ret < 0) {
|
||
AM_LOGE("get available system buffer error!");
|
||
}
|
||
}
|
||
size += 5 * 48; //system buffer extra continuous buffer size
|
||
return size;
|
||
}
|
||
if (out->config.rate == 96000)
|
||
size = DEFAULT_PLAYBACK_PERIOD_SIZE * 2;
|
||
else
|
||
size = DEFAULT_PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT;
|
||
}
|
||
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC && audio_is_linear_pcm(out->hal_internal_format)) {
|
||
size = (size * audio_stream_out_frame_size((struct audio_stream_out *) stream)) + TUNNEL_SYNC_HEADER_SIZE;
|
||
} else {
|
||
size = (size * audio_stream_out_frame_size((struct audio_stream_out *) stream));
|
||
}
|
||
|
||
// remove alignment to have an accurate size
|
||
// size = ( (size + 15) / 16) * 16;
|
||
return size;
|
||
}
|
||
|
||
static audio_channel_mask_t out_get_channels(const struct audio_stream *stream __unused)
|
||
{
|
||
const struct aml_stream_out *out = (const struct aml_stream_out *)stream;
|
||
|
||
//ALOGV("Amlogic_HAL - out_get_channels return out->hal_channel_mask:%0x", out->hal_channel_mask);
|
||
return out->hal_channel_mask;
|
||
}
|
||
|
||
static audio_format_t out_get_format(const struct audio_stream *stream __unused)
|
||
{
|
||
const struct aml_stream_out *out = (const struct aml_stream_out *)stream;
|
||
//ALOGV("Amlogic_HAL - out_get_format() = %d", out->hal_format);
|
||
// if hal_format doesn't have a valid value,
|
||
// return default value AUDIO_FORMAT_PCM_16_BIT
|
||
if (out->hal_format == 0) {
|
||
return AUDIO_FORMAT_PCM_16_BIT;
|
||
}
|
||
return out->hal_format;
|
||
}
|
||
|
||
static int out_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int out_dump (const struct audio_stream *stream __unused, int fd __unused)
|
||
{
|
||
ALOGD ("%s(%p, %d)", __FUNCTION__, stream, fd);
|
||
return 0;
|
||
}
|
||
|
||
void set_rate_to_sync (struct aml_stream_out *aml_out, float rate)
|
||
{
|
||
switch (aml_out->avsync_type)
|
||
{
|
||
case AVSYNC_TYPE_MEDIASYNC:
|
||
if ((NULL == aml_out->avsync_ctx) ||
|
||
(NULL == aml_out->avsync_ctx->mediasync_ctx) ||
|
||
(NULL == aml_out->avsync_ctx->mediasync_ctx->handle)) {
|
||
AM_LOGE("mediasync handle NULL fail");
|
||
goto exit;
|
||
}
|
||
mediasync_wrap_setPlaybackRate(aml_out->avsync_ctx->mediasync_ctx->handle, rate);
|
||
break;
|
||
case AVSYNC_TYPE_MSYNC:
|
||
if ((NULL == aml_out->avsync_ctx) ||
|
||
(NULL == aml_out->avsync_ctx->msync_ctx) ||
|
||
(NULL == aml_out->avsync_ctx->msync_ctx->msync_session)) {
|
||
AM_LOGE("msync_session NULL fail");
|
||
goto exit;
|
||
}
|
||
av_sync_set_speed(aml_out->avsync_ctx->msync_ctx->msync_session, rate);
|
||
break;
|
||
default :
|
||
AM_LOGE("aml_out->avsync_type:%d, not support!", aml_out->avsync_type);
|
||
break;
|
||
}
|
||
exit:
|
||
return;
|
||
}
|
||
|
||
void out_set_playback_rate (struct audio_stream *stream, float rate)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
|
||
if (false == aml_out->enable_scaletempo)
|
||
{
|
||
AM_LOGI("set rate:%f, enable_scaletempo is 0", rate);
|
||
goto done;
|
||
}
|
||
|
||
if (NULL == aml_out->scaletempo) {
|
||
hal_scaletempo_init(&aml_out->scaletempo);
|
||
}
|
||
hal_scaletempo_update_rate(aml_out->scaletempo, rate);
|
||
if ((!adev->is_netflix) && aml_out->scaletempo) {
|
||
bool st_bypass = is_double_equal((double)rate, 1.0) ? true : false;
|
||
hal_scaletempo_set_bypass(aml_out->scaletempo, st_bypass);
|
||
}
|
||
|
||
done:
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && aml_out->rate != 0.0) {
|
||
aml_out->scale_state = SCALE_START;
|
||
} else {
|
||
set_rate_to_sync(aml_out, rate);
|
||
}
|
||
aml_out->rate = rate;
|
||
|
||
return;
|
||
}
|
||
|
||
void eos_timer_callback_handler(union sigval sigv)
|
||
{
|
||
uint32_t timer_id = sigv.sival_int;
|
||
struct audio_stream_out *out = audio_timer_get_privdata_by_id(timer_id);
|
||
AM_LOGI("sigv:%d, out:%p ~~~~~~~~~~", timer_id, out);
|
||
|
||
set_ms12_decoder_continuous_mute(out, 1);
|
||
return;
|
||
}
|
||
|
||
static int out_set_parameters (struct audio_stream *stream, const char *kvpairs)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
struct aml_stream_in *in;
|
||
struct str_parms *parms;
|
||
char value[32];
|
||
int ret;
|
||
uint32_t val = 0;
|
||
bool force_input_standby = false;
|
||
do_standby_func standby_func = NULL;
|
||
standby_func = do_output_standby_l;
|
||
|
||
ALOGD ("%s(kvpairs(%s), out_device=%#x)", __FUNCTION__, kvpairs, adev->out_device);
|
||
parms = str_parms_create_str (kvpairs);
|
||
|
||
ret = str_parms_get_str (parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
val = atoi (value);
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if ( ( (adev->out_device & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0) ) {
|
||
ALOGI ("audio hw select device!\n");
|
||
standby_func (stream);
|
||
/* a change in output device may change the microphone selection */
|
||
if (adev->active_input &&
|
||
adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
|
||
force_input_standby = true;
|
||
}
|
||
/* force standby if moving to/from HDMI */
|
||
if ( ( (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
|
||
(adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) ) ||
|
||
( (val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
|
||
(adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ) ) {
|
||
standby_func (stream);
|
||
}
|
||
adev->out_device &= ~AUDIO_DEVICE_OUT_ALL;
|
||
adev->out_device |= val;
|
||
//select_devices(adev);
|
||
}
|
||
pthread_mutex_unlock (&out->lock);
|
||
if (force_input_standby) {
|
||
in = adev->active_input;
|
||
pthread_mutex_lock (&in->lock);
|
||
do_input_standby (in);
|
||
pthread_mutex_unlock (&in->lock);
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is set successfully,
|
||
// or we can not pass VTS test.
|
||
ALOGI ("Amlogic_HAL - %s: change ret value to 0 in order to pass VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
|
||
goto exit;
|
||
}
|
||
int sr = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, &sr);
|
||
if (ret >= 0) {
|
||
if (sr > 0) {
|
||
struct pcm_config *config = &out->config;
|
||
ALOGI ("audio hw sampling_rate change from %d to %d \n", config->rate, sr);
|
||
config->rate = sr;
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if (!out->standby) {
|
||
//standy_func (out);
|
||
//startup_func (out);
|
||
out->standby = 0;
|
||
}
|
||
// set hal_rate to sr for passing VTS
|
||
ALOGI ("Amlogic_HAL - %s: set sample_rate to hal_rate.", __FUNCTION__);
|
||
out->hal_rate = sr;
|
||
pthread_mutex_unlock (&adev->lock);
|
||
pthread_mutex_unlock (&out->lock);
|
||
}
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is set successfully,
|
||
// or we can not pass VTS test.
|
||
ALOGI ("Amlogic_HAL - %s: change ret value to 0 in order to pass VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
|
||
goto exit;
|
||
}
|
||
// Detect and set AUDIO_PARAMETER_STREAM_FORMAT for passing VTS
|
||
audio_format_t fmt = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_FORMAT, (int *) &fmt);
|
||
if (ret >= 0) {
|
||
if (fmt > 0) {
|
||
struct pcm_config *config = &out->config;
|
||
ALOGI ("[%s:%d] audio hw format change from %#x to %#x", __func__, __LINE__, config->format, fmt);
|
||
config->format = fmt;
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if (!out->standby) {
|
||
standby_func (stream);
|
||
out->standby = 0;
|
||
}
|
||
// set hal_format to fmt for passing VTS
|
||
ALOGI ("Amlogic_HAL - %s: set format to hal_format. fmt = %d", __FUNCTION__, fmt);
|
||
out->hal_format = fmt;
|
||
pthread_mutex_unlock (&adev->lock);
|
||
pthread_mutex_unlock (&out->lock);
|
||
}
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is set successfully,
|
||
// or we can not pass VTS test.
|
||
ALOGI ("Amlogic_HAL - %s: change ret value to 0 in order to pass VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
|
||
goto exit;
|
||
}
|
||
// Detect and set AUDIO_PARAMETER_STREAM_CHANNELS for passing VTS
|
||
audio_channel_mask_t channels = AUDIO_CHANNEL_OUT_STEREO;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_CHANNELS, (int *) &channels);
|
||
if (ret >= 0) {
|
||
if (channels > AUDIO_CHANNEL_NONE) {
|
||
struct pcm_config *config = &out->config;
|
||
ALOGI ("audio hw channel_mask change from %d to %d \n", config->channels, channels);
|
||
config->channels = audio_channel_count_from_out_mask (channels);
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if (!out->standby) {
|
||
standby_func (stream);
|
||
out->standby = 0;
|
||
}
|
||
// set out->hal_channel_mask to channels for passing VTS
|
||
ALOGI ("Amlogic_HAL - %s: set out->hal_channel_mask to channels. fmt = %d", __FUNCTION__, channels);
|
||
out->hal_channel_mask = channels;
|
||
pthread_mutex_unlock (&adev->lock);
|
||
pthread_mutex_unlock (&out->lock);
|
||
}
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is set successfully,
|
||
// or we can not pass VTS test.
|
||
ALOGI ("Amlogic_HAL - %s: change ret value to 0 in order to pass VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
|
||
goto exit;
|
||
}
|
||
|
||
int input_eos_value = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_INPUT_END_OF_STREAM, &input_eos_value);
|
||
if (ret >= 0) {
|
||
if (input_eos_value == 0) {
|
||
out->eos = false;
|
||
} else {
|
||
out->eos = true;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
int codecbuf_frames = 0;
|
||
codecbuf_frames = get_ms12_codecbuf_frames((struct audio_stream_out *)out);
|
||
if (EOS_EASE_DURATION_FRAMES < codecbuf_frames) {
|
||
int diffms = (codecbuf_frames - EOS_EASE_DURATION_FRAMES) / 48;
|
||
AM_LOGI("eos_ease_timer start, timer_id:%d, out:%p, diffms:%d, codecbuf_frames:%d",
|
||
out->eos_ease_timer, out, diffms, codecbuf_frames);
|
||
audio_one_shot_timer_start(out->eos_ease_timer, diffms);
|
||
} else {
|
||
set_ms12_decoder_continuous_mute((struct audio_stream_out *)out, 1);
|
||
}
|
||
}
|
||
}
|
||
AM_LOGI (" Amlogic_HAL - input_eos value changed, value: %d ", out->eos);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
|
||
int frame_size = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT, &frame_size);
|
||
if (ret >= 0) {
|
||
if (frame_size > 0) {
|
||
struct pcm_config *config = &out->config;
|
||
ALOGI ("audio hw frame size change from %d to %d \n", config->period_size, frame_size);
|
||
config->period_size = frame_size;
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if (!out->standby) {
|
||
standby_func (stream);
|
||
out->standby = 0;
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
pthread_mutex_unlock (&out->lock);
|
||
}
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is set successfully,
|
||
// or we can not pass VTS test.
|
||
ALOGI("Amlogic_HAL - %s: change ret value to 0 in order to pass VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "adpcm_block_size", value, sizeof(value));
|
||
if (ret >=0 ) {
|
||
unsigned int block_size = atoi(value);
|
||
out->dec_param.hal_decode_block_size = block_size;
|
||
|
||
ALOGI("[%s:%d]:set block_size=%d", __FUNCTION__, __LINE__, block_size);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "hw_av_sync_type", value, sizeof(value));
|
||
if (ret >=0 ) {
|
||
int hw_sync_type = atoi(value);
|
||
out->avsync_type = hw_sync_type;
|
||
|
||
ALOGI("[%s:%d]:set av sync type=%d", __FUNCTION__, __LINE__, hw_sync_type);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "hw_av_sync", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int hw_sync_id = atoi(value);
|
||
int sync_enable = 0;
|
||
void *msync_session;
|
||
|
||
if (hw_sync_id < 0) {
|
||
ALOGE("[%s:%d]:The set parameter is abnormal, hw_sync_id=%d", __FUNCTION__, __LINE__, hw_sync_id);
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
|
||
if (hw_sync_id == 12345678) {
|
||
ALOGE("[%s:%d]:tsync not support anymore!", __FUNCTION__, __LINE__);
|
||
} else {
|
||
if (out->avsync_type == AVSYNC_TYPE_MEDIASYNC) {
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_HBBTV) {
|
||
int tem_id = adev->hbbtvsync_info.sync_id;
|
||
hw_sync_id = tem_id > 0 ? tem_id : hw_sync_id;
|
||
AM_LOGD("hw_av_sync id is replaced to %d in hbbtv case", hw_sync_id);
|
||
if (out->avsync_ctx && out->avsync_ctx->mediasync_ctx &&
|
||
hw_sync_id == out->avsync_ctx->mediasync_ctx->mediasync_id &&
|
||
out->avsync_ctx->mediasync_ctx->handle) {
|
||
AM_LOGD("hw_av_sync id is same as last, no need recreate");
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
hwsync_mediasync_outset(out, &sync_enable, hw_sync_id, out->hal_format);
|
||
} else {
|
||
if ((out->avsync_ctx->msync_ctx) && (out->avsync_ctx->msync_ctx->msync_session)) {
|
||
ALOGW("[%s:%d]:hw_av_sync id set w/o release previous session.", __FUNCTION__, __LINE__);
|
||
av_sync_destroy(out->avsync_ctx->msync_ctx->msync_session);
|
||
pthread_mutex_lock(&(out->avsync_ctx->lock));
|
||
/*coverity[LOCK_EVASION]: There will be no competition here*/
|
||
out->avsync_ctx->msync_ctx->msync_session = NULL;
|
||
pthread_mutex_unlock(&(out->avsync_ctx->lock));
|
||
avsync_ctx_reset(out->avsync_ctx);
|
||
}
|
||
else {
|
||
pthread_mutex_lock(&(out->avsync_ctx->lock));
|
||
out->avsync_ctx->msync_ctx = msync_ctx_init();
|
||
pthread_mutex_unlock(&(out->avsync_ctx->lock));
|
||
}
|
||
|
||
audio_msync_t *msync_ctx = out->avsync_ctx->msync_ctx;
|
||
msync_session = av_sync_attach(hw_sync_id, AV_SYNC_TYPE_AUDIO);
|
||
if (!msync_session) {
|
||
AM_LOGE("Cannot attach hw_sync_id %d, error!", hw_sync_id);
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
sync_enable = 1;
|
||
out->avsync_type = AVSYNC_TYPE_MSYNC;
|
||
out->with_header = true;
|
||
pthread_mutex_lock(&(out->avsync_ctx->lock));
|
||
out->avsync_ctx->get_tuning_latency = get_latency_pts;
|
||
msync_ctx->first_apts_flag = false;
|
||
msync_ctx->msync_first_insert_flag = false;
|
||
msync_ctx->msync_session = msync_session;
|
||
pthread_mutex_unlock(&(out->avsync_ctx->lock));
|
||
AM_LOGI("The current sync type:MSYNC, av_sync_attach success");
|
||
}
|
||
}
|
||
|
||
AM_LOGI("(%p)set hw_sync_id=%d, %s need_sync", out, hw_sync_id, sync_enable ? "enable" : "disable");
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
out->frame_write_sum = 0;
|
||
out->last_frames_position = 0;
|
||
|
||
pthread_mutex_unlock (&out->lock);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type || adev->ms12.dap_only_enable) {
|
||
ret = str_parms_get_str(parms, "ms12_runtime", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *parm = strstr(kvpairs, "=");
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (parm) {
|
||
if (strstr(parm+1, "-xa") || strstr(parm+1, "-xu") ||
|
||
strstr(parm+1, "-at") || strstr(parm+1, "-pat") || strstr(parm+1, "-lang") ||
|
||
strstr(parm+1, "-lang2") || strstr(parm+1, "-ac4_pres_group_idx")) {
|
||
set_ms12_decoder_parameters((struct audio_stream_out*)out, parm+1);
|
||
} else {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm+1);
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "playback_rate", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
float rate = atof(value);
|
||
ALOGI("change rate to %f, format:0x%x, enable %d", rate, out->hal_format, out->enable_scaletempo);
|
||
out_set_playback_rate(stream, rate);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "will_pause", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
int will_pause = atoi(value);
|
||
out->will_pause = will_pause ? true : false;
|
||
ALOGI("stream(%p) will pause: %d", out, out->will_pause);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str (parms, "will_flush", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
int will_flush = atoi(value);
|
||
out->will_flush = will_flush ? true : false;
|
||
ALOGI("stream(%p) will flush: %d", out, out->will_flush);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "enable_scaletempo", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
int enable_scaletempo = atoi(value);
|
||
out->enable_scaletempo = enable_scaletempo ? true : false;
|
||
ALOGI("change enable_scaletempo to %d", out->enable_scaletempo);
|
||
goto exit;
|
||
}
|
||
|
||
int m_val = -1;
|
||
ret = str_parms_get_int (parms, "decoder_id", &m_val);
|
||
if (ret >= 0) {
|
||
if (m_val >= 0) {
|
||
out->decoder_id = m_val;
|
||
} else {
|
||
AM_LOGI ("error. decoder_id: %d", m_val);
|
||
}
|
||
AM_LOGI ("set audio stream(%p) decoder_id:%d ", out, out->decoder_id);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "is_airplay", &m_val);
|
||
if (ret >= 0) {
|
||
out->is_airplay = m_val == 1? true : false;
|
||
adev->audio_hal_info.update_cnt = 0;
|
||
AM_LOGI ("is_airplay stream:%d", m_val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "hbbtv_mode", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
int hbbtv_mode = atoi(value);
|
||
if (hbbtv_mode) {
|
||
out->flags |= AUDIO_OUTPUT_FLAG_HBBTV;
|
||
AM_LOGI("stream(%p) add HBBTV flag: %x", out, out->flags);
|
||
if (out->scaletempo) {
|
||
hal_scaletempo_set_bypass(out->scaletempo, true);
|
||
}
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
ret = str_parms_get_str(parms, "vol_ease", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int gain, duration, shape;// shape(0: linear, 1: in cube, 2: out cube)
|
||
|
||
AM_LOGI("vol_ease: value= %s", value);
|
||
if (adev->master_volume < FLOAT_ZERO) {
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
if (sscanf(value, "%d,%d,%d", &gain, &duration, &shape) == 3) {
|
||
set_vol_ease_by_stream(out, gain, duration, shape);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "is_aacpcm", value, sizeof (value));
|
||
if (ret >= 0) {
|
||
int is_aacpcm = atoi(value);
|
||
out->is_aacpcm = is_aacpcm ? true : false;;
|
||
AM_LOGI("stream(%p) is_aacpcm: %d", out, out->is_aacpcm);
|
||
goto exit;
|
||
}
|
||
exit:
|
||
str_parms_destroy (parms);
|
||
|
||
// We shall return Result::OK, which is 0, if parameter is NULL,
|
||
// or we can not pass VTS test.
|
||
if (ret < 0) {
|
||
if (adev->debug_flag) {
|
||
ALOGW("Amlogic_HAL - %s: parameter is NULL, change ret value to 0 in order to pass VTS test.", __func__);
|
||
}
|
||
ret = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static char *out_get_parameters(const struct audio_stream *stream, const char *keys)
|
||
{
|
||
char temp_buf[1024] = {0};
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
aml_dec_t *aml_dec = aml_out->aml_dec;
|
||
|
||
if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) || \
|
||
strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS) || \
|
||
strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
|
||
return out_get_parameters_wrapper_about_sup_sampling_rates__channels__formats(stream, keys);
|
||
} else if (strstr (keys, "stream_sr") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_sr=%d", dec_info.dec_info.stream_sr);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "stream_ch") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_ch=%d", dec_info.dec_info.stream_ch);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "stream_bitrate") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_bitrate=%d", dec_info.dec_info.stream_bitrate);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "stream_error_frames") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_error_frames=%d", dec_info.dec_info.stream_error_num);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "stream_drop_frames") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_drop_frames=%d", dec_info.dec_info.stream_drop_num);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "stream_decode_frames") ) {
|
||
aml_dec_info_t dec_info;
|
||
memset(&dec_info, 0x00, sizeof(dec_info));
|
||
aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info);
|
||
sprintf (temp_buf, "stream_decode_frames=%d", dec_info.dec_info.stream_decode_num);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "alsa_device_config")) {
|
||
sprintf (temp_buf, "period_cnt=%d;period_sz=%d", aml_out->config.period_count, aml_out->config.period_size);
|
||
return strdup (temp_buf);
|
||
} /*else if (strstr (keys, "get_buffer_avail")) {
|
||
if ((is_dolby_ms12_support_compression_format(aml_out->hal_internal_format) || is_multi_channel_pcm((struct audio_stream_out *)stream))) {
|
||
sprintf (temp_buf, "remain_frame=%d", (dolby_ms12_get_main_buffer_avail(NULL)));
|
||
return strdup (temp_buf);
|
||
}
|
||
return strdup ("");
|
||
} */ else if (strstr (keys, "decoder_end_of_stream")) {
|
||
sprintf (temp_buf, "decoder_end_of_stream=%d", aml_out->eos);
|
||
AM_LOGI_IF(get_debug_value(AML_DEBUG_AUDIOHAL_DEBUG), "%s", temp_buf);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "get_metric_info")) {
|
||
if (eDolbyMS12Lib == aml_out->dev->dolby_lib_type) {
|
||
sprintf (temp_buf, "drop_start=%"PRId64",drop_duration=%"PRId64"", aml_out->drop_start, aml_out->drop_duration);
|
||
}
|
||
AM_LOGI_IF(get_debug_value(AML_DEBUG_AUDIOHAL_DEBUG), "%s", temp_buf);
|
||
aml_out->drop_start = -1;
|
||
aml_out->drop_duration = -1;
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "main_input_underrun")) {
|
||
if (eDolbyMS12Lib == aml_out->dev->dolby_lib_type) {
|
||
sprintf(temp_buf, "main_input_underrun=%d", get_ms12_main_underrun((struct audio_stream_out *)aml_out));
|
||
} else {
|
||
sprintf(temp_buf, "main_input_underrun=0");
|
||
}
|
||
AM_LOGI("%s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr(keys, "av_sync_id")) {
|
||
if (aml_out->avsync_ctx && aml_out->avsync_ctx->mediasync_ctx) {
|
||
sprintf (temp_buf, "av_sync_id=%d", aml_out->avsync_ctx->mediasync_ctx->mediasync_id);
|
||
}
|
||
AM_LOGI("%s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else {
|
||
ALOGE("%s() keys %s is not supported! TODO!\n", __func__, keys);
|
||
return strdup ("");
|
||
}
|
||
}
|
||
|
||
static int out_set_volume_l (struct audio_stream_out *stream, float left, float right)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
bool is_dolby_format = is_dolby_ms12_support_compression_format(out->hal_internal_format);
|
||
|
||
ALOGI("%s(), stream(%p), left:%f right:%f, master_volume:%f, format:%x, is dolby:%d, is_new_vol_ease:%d \n",
|
||
__func__, stream, left, right, adev->master_volume, out->hal_internal_format, is_dolby_format, out->stream_vol_setting.is_new_setting);
|
||
|
||
out->last_volume_l_org = left;
|
||
out->last_volume_r_org = right;
|
||
out->volume_l_org = left;
|
||
out->volume_r_org = right;
|
||
|
||
if (STREAM_MAIN_INPUT == out->stream_type) {
|
||
out->volume_l = out->volume_l_org * out->source_volume * adev->master_volume;
|
||
out->volume_r = out->volume_r_org * out->source_volume * adev->master_volume;
|
||
} else {
|
||
out->volume_l = out->volume_l_org * adev->master_volume;
|
||
out->volume_r = out->volume_r_org * adev->master_volume;
|
||
}
|
||
|
||
if (adev->audio_focus_enable && STREAM_APP_INPUT != out->stream_type) {
|
||
out->volume_l = out->volume_l * adev->audio_focus_ratio;
|
||
out->volume_r = out->volume_r * adev->audio_focus_ratio;
|
||
AM_LOGI("audio focus set vol to :%f ratio:%f", out->volume_l, adev->audio_focus_ratio);
|
||
}
|
||
|
||
AM_LOGI("last_volume(L:%f,R:%f) volume_org(L:%f,R:%f) volume(L:%f,R:%f)",
|
||
out->last_volume_l_org, out->last_volume_r_org, out->volume_l_org, out->volume_r_org, out->volume_l, out->volume_r);
|
||
|
||
/* for not use ms12 case, we can use spdif enc mute, other wise ms12 can handle it*/
|
||
if (is_dts_format(out->hal_internal_format) ||
|
||
(is_dolby_format && (eDolbyDcvLib == adev->dolby_lib_type || is_bypass_dolbyms12(stream) || adev->hdmi_format == BYPASS))) {
|
||
if (out->volume_l_org * adev->master_volume > FLOAT_ZERO) {
|
||
ALOGI("set offload mute: false");
|
||
out->offload_mute = false;
|
||
} else if (out->volume_l_org * adev->master_volume < FLOAT_ZERO) {
|
||
ALOGI("set offload mute: true");
|
||
out->offload_mute = true;
|
||
}
|
||
}
|
||
|
||
if (out->volume_l != out->volume_r) {
|
||
AM_LOGI("left:%f(%f) right:%f(%f) NOT match", left, out->volume_l, right, out->volume_r);
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if (out->is_normal_pcm) {
|
||
set_ms12_aux_audio_volume(&adev->ms12, out->volume_l); /* system sound */
|
||
} else if (STREAM_APP_INPUT == out->stream_type) {
|
||
set_ms12_app_audio_volume(&adev->ms12, out->volume_l); /* app sound */
|
||
} else { /* main sound*/
|
||
ease_setting_t vol_setting;
|
||
//NTS vol_ease
|
||
if (out->stream_vol_setting.is_new_setting && STREAM_MAIN_INPUT == out->stream_type) {
|
||
out->volume_l = out->volume_l * out->stream_vol_setting.ease_setting.target_volume;
|
||
vol_setting.duration = out->stream_vol_setting.ease_setting.duration;
|
||
vol_setting.start_volume = out->volume_l;// start_volume = target_volume, then ease_status will be VolProcess in aml_audio_ease_config
|
||
vol_setting.target_volume = out->volume_l;
|
||
vol_setting.ease_shape = out->stream_vol_setting.ease_setting.ease_shape;
|
||
out->stream_vol_setting.is_new_setting = false;
|
||
AM_LOGI("apply NTS vol_ease to %f", out->volume_l);
|
||
} else {// MS12 volume process
|
||
vol_setting.duration = 32;
|
||
vol_setting.start_volume = out->volume_l;// start_volume = target_volume, then ease_status will be VolProcess in aml_audio_ease_config
|
||
vol_setting.target_volume = out->volume_l;
|
||
vol_setting.ease_shape = EaseLinear;
|
||
AM_LOGI("dolby_ms12 set vol to %f", out->volume_l);
|
||
}
|
||
|
||
aml_audio_ease_config(out->vol_process_handle, &vol_setting);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int set_volume_by_decoder_id (int id, float left, float right) {
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
||
pthread_mutex_lock (&adev->active_outputs_lock);
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
//struct audio_stream_out *out = (struct audio_stream_out *)aml_out;
|
||
if (aml_out && STREAM_MAIN_INPUT == aml_out->stream_type && id == aml_out->decoder_id) {
|
||
out_set_volume_l((struct audio_stream_out *)aml_out, left, right);
|
||
//break; //if stream not set decoder_id, set vol for all main stream.
|
||
}
|
||
if (i == STREAM_NUM_MAX) {
|
||
AM_LOGI("can't find stream which id = %d", id);
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->active_outputs_lock);
|
||
return 0;
|
||
}
|
||
|
||
void set_ms12_focus_by_stream_volume (struct aml_audio_device *adev) {
|
||
int main_stream_cnt = 0;
|
||
int is_focus = 1;
|
||
struct aml_stream_out *main1_out = NULL;
|
||
struct aml_stream_out *main2_out = NULL;
|
||
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
if (aml_out && aml_out->stream_type == STREAM_MAIN_INPUT) {
|
||
main_stream_cnt++;
|
||
if (main_stream_cnt == 1) {
|
||
main1_out = aml_out;
|
||
} else if (main_stream_cnt == 2) {
|
||
main2_out = aml_out;
|
||
//Here is dual main ms12 focus stratrgy, it might not be quite correct
|
||
//1. main1 vol is 0 and main2 vol is 0, focus main1
|
||
//2. main1 vol is not 0, main2 vol is 0, focus main1
|
||
//3. main1 vol is 0 and main2 vol is not 0, focus main2
|
||
//4. main1 vol is not 0, main2 vol is not 0, focus main2
|
||
//note: if has more than 2 main stream, need change here.
|
||
if ((main1_out->vol_process_handle->current_volume <= FLOAT_ZERO && main2_out->vol_process_handle->current_volume <= FLOAT_ZERO) ||
|
||
(main1_out->vol_process_handle->current_volume > FLOAT_ZERO && main2_out->vol_process_handle->current_volume <= FLOAT_ZERO)) {
|
||
if (main1_out->ms12_dec_handle != NULL) {
|
||
aml_ms12_decoder_setparameter(&adev->ms12, main1_out->ms12_dec_handle, MS12_CODEC_PARAMETER_REQUEST_FOCUS, &is_focus, sizeof(int));
|
||
}
|
||
AM_LOGI("focus main1");
|
||
} else if ((main1_out->vol_process_handle->current_volume <= FLOAT_ZERO && main2_out->vol_process_handle->current_volume > FLOAT_ZERO) ||
|
||
(main1_out->vol_process_handle->current_volume > FLOAT_ZERO && main2_out->vol_process_handle->current_volume > FLOAT_ZERO)) {
|
||
if (main2_out->ms12_dec_handle != NULL) {
|
||
aml_ms12_decoder_setparameter(&adev->ms12, main2_out->ms12_dec_handle, MS12_CODEC_PARAMETER_REQUEST_FOCUS, &is_focus, sizeof(int));
|
||
}
|
||
AM_LOGI("focus main2");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
AM_LOGI("main stream cnt:%d", main_stream_cnt);
|
||
}
|
||
|
||
static void set_vol_ease_by_stream (struct aml_stream_out *aml_out, int gain, int duration, int shape) {
|
||
float vol;
|
||
|
||
vol = DbToAmpl(gain/128.0);
|
||
if (-12288 == gain) {//gain:(-12288~0) DbToAmpl(-12288/128.0) == 0.000016, it should be 0
|
||
vol = 0;
|
||
}
|
||
|
||
aml_out->stream_vol_setting.is_new_setting = true;
|
||
aml_out->stream_vol_setting.ease_setting.duration = duration;
|
||
aml_out->stream_vol_setting.ease_setting.start_volume = vol;
|
||
aml_out->stream_vol_setting.ease_setting.target_volume = vol;
|
||
aml_out->stream_vol_setting.ease_setting.ease_shape = EaseLinear;
|
||
if (1 == shape) {
|
||
aml_out->stream_vol_setting.ease_setting.ease_shape = EaseInCubic;
|
||
} else if (2 == shape) {
|
||
aml_out->stream_vol_setting.ease_setting.ease_shape = EaseOutCubic;
|
||
}
|
||
AM_LOGI("stream vol_ease gain:%d(%f) duration:%d shape:%d", gain, vol, duration, shape);
|
||
|
||
out_set_volume_l((struct audio_stream_out *)aml_out, aml_out->volume_l_org, aml_out->volume_r_org);
|
||
|
||
return;
|
||
}
|
||
|
||
static int set_vol_ease_by_decoder_id (int id, int gain, int duration, int shape) {
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
||
pthread_mutex_lock (&adev->active_outputs_lock);
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
if (aml_out && STREAM_MAIN_INPUT == aml_out->stream_type && id == aml_out->decoder_id) {
|
||
set_vol_ease_by_stream(aml_out, gain, duration, shape);
|
||
}
|
||
if (i == STREAM_NUM_MAX) {
|
||
AM_LOGI("can't find stream which id = %d", id);
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->active_outputs_lock);
|
||
return 0;
|
||
}
|
||
|
||
void out_set_stream_mute (struct audio_stream_out *stream, bool mute, bool is_external_mute)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *aml_dev = out->dev;
|
||
bool mute_status_change = false;
|
||
|
||
if (is_external_mute) {
|
||
out->external_mute = mute;
|
||
} else {
|
||
out->internal_mute = mute;
|
||
}
|
||
|
||
if (aml_dev->decoder_mute || out->internal_mute || out->external_mute) {
|
||
if (!out->final_mute) mute_status_change = true;
|
||
out->final_mute = true;
|
||
} else {
|
||
if (out->final_mute) mute_status_change = true;
|
||
out->final_mute = false;
|
||
}
|
||
|
||
if (mute_status_change && eDolbyMS12Lib == aml_dev->dolby_lib_type) {
|
||
if (out->stream_type == STREAM_AUX_INPUT) {
|
||
if (out->final_mute) {
|
||
set_ms12_aux_audio_volume(&aml_dev->ms12, 0.0f);
|
||
} else {
|
||
set_ms12_aux_audio_volume(&aml_dev->ms12, out->volume_l);
|
||
}
|
||
} else if (out->stream_type == STREAM_APP_INPUT) {
|
||
if (out->final_mute) {
|
||
set_ms12_app_audio_volume(&aml_dev->ms12, 0.0f);
|
||
} else {
|
||
set_ms12_app_audio_volume(&aml_dev->ms12, out->volume_l);
|
||
}
|
||
}
|
||
}
|
||
|
||
AM_LOGI("stream:%p, final_mute:%d (decoder_mute:%d internal_mute:%d external_mute:%d)",
|
||
out, out->final_mute, aml_dev->decoder_mute, out->internal_mute, is_external_mute);
|
||
}
|
||
|
||
static int out_set_volume (struct audio_stream_out *stream, float left, float right)
|
||
{
|
||
return out_set_volume_l(stream, left, right);
|
||
}
|
||
|
||
/* use standby instead of pause to fix background pcm playback */
|
||
static int out_pause_new (struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *aml_dev = aml_out->dev;
|
||
bool is_standby = aml_out->standby;
|
||
int ret = 0;
|
||
|
||
ALOGI("%s(), stream(%p), pause_status = %d,dolby_lib_type = %d, with_header = %d,ms12_enable = %d,ms_conti_paused = %d\n",
|
||
__func__, stream, aml_out->pause_status, aml_dev->dolby_lib_type, aml_out->with_header, aml_dev->ms12.dolby_ms12_enable, aml_dev->ms12.is_continuous_paused);
|
||
|
||
aml_audio_trace_int("out_pause_new", 1);
|
||
if (aml_out->stream_type == STREAM_AD_INPUT) {
|
||
ALOGI("%s(), do nothing for AD stream\n", __func__);
|
||
return 0;
|
||
}
|
||
pthread_mutex_lock (&aml_dev->lock);
|
||
pthread_mutex_lock (&aml_out->lock);
|
||
|
||
/* a stream should fail to pause if not previously started */
|
||
if (aml_out->pause_status == true) {
|
||
// If output stream is standby or paused,
|
||
// we should return Result::INVALID_STATE (3),
|
||
// thus we can pass VTS test.
|
||
ALOGE ("%s: stream in wrong status. standby(%d) or paused(%d)",
|
||
__func__, aml_out->standby, aml_out->pause_status);
|
||
ret = INVALID_STATE;
|
||
goto exit;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {
|
||
if ((aml_dev->ms12.dolby_ms12_enable == true) &&
|
||
(aml_out->stream_type == STREAM_MAIN_INPUT)) {
|
||
aml_out->async_resume = false;
|
||
dolby_ms12_main_pause(stream);
|
||
}
|
||
} else if (aml_dev->useSubMix) {
|
||
mixer_pause_inport(aml_dev->audio_mixer, aml_out->inputPortID);
|
||
}
|
||
|
||
exit:
|
||
aml_out->pause_status = true;
|
||
aml_out->position_update = 0;
|
||
|
||
/* do avsync pause after 32ms sleep for to avoid the system clock stop early than dolby fading out finish in dolby continue mode. ##SWPL-108005 */
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MSYNC == aml_out->avsync_type) && aml_out->avsync_ctx->msync_ctx) {
|
||
av_sync_pause(aml_out->avsync_ctx->msync_ctx->msync_session, true);
|
||
}
|
||
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MEDIASYNC == aml_out->avsync_type) && aml_out->avsync_ctx->mediasync_ctx && !(aml_out->flags & AUDIO_OUTPUT_FLAG_HBBTV)) {
|
||
mediasync_wrap_setPause(aml_out->avsync_ctx->mediasync_ctx->handle, true);
|
||
}
|
||
|
||
pthread_mutex_unlock(&aml_out->lock);
|
||
pthread_mutex_unlock(&aml_dev->lock);
|
||
|
||
//1.audio easing duration is 32ms,
|
||
//2.one loop for schedule_run cost about 32ms(contains the hardware costing),
|
||
//3.if [pause, vol_ease(in adev_set_parameters by Netflix)] too short, means it need more time to do audio easing
|
||
//so, the delay time for 32ms(pause is completed after audio easing is done) is enough.
|
||
aml_audio_sleep(32000);
|
||
|
||
if (is_standby) {
|
||
ALOGD("%s(), stream(%p) already in standy, return INVALID_STATE", __func__, stream);
|
||
ret = INVALID_STATE;
|
||
}
|
||
aml_out->will_pause = false;
|
||
aml_audio_trace_int("out_pause_new", 0);
|
||
ALOGI("%s(), stream(%p) exit", __func__, stream);
|
||
return ret;
|
||
}
|
||
|
||
static int out_resume_new (struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *aml_dev = aml_out->dev;
|
||
int ret = 0;
|
||
|
||
ALOGI("%s(), stream(%p),standby = %d,pause_status = %d\n", __func__, stream, aml_out->standby, aml_out->pause_status);
|
||
aml_audio_trace_int("out_resume_new", 1);
|
||
if (aml_out->stream_type == STREAM_AD_INPUT) {
|
||
ALOGI("%s(), do nothing for AD stream\n", __func__);
|
||
return 0;
|
||
}
|
||
pthread_mutex_lock(&aml_dev->lock);
|
||
pthread_mutex_lock(&aml_out->lock);
|
||
|
||
unmute_after_eos_received (aml_out);
|
||
|
||
/* a stream should fail to resume if not previously paused */
|
||
// aml_out->standby is always "1" in ms12 continuous mode, which will cause fail to resume here
|
||
if (/*aml_out->standby || */aml_out->pause_status == false) {
|
||
// If output stream is not standby or not paused,
|
||
// we should return Result::INVALID_STATE (3),
|
||
// thus we can pass VTS test.
|
||
ALOGE ("Amlogic_HAL - %s: cannot resume, because output stream isn't in standby or paused state.", __FUNCTION__);
|
||
ret = 3;
|
||
goto exit;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {
|
||
if ((aml_dev->ms12.dolby_ms12_enable == true) &&
|
||
(aml_out->stream_type == STREAM_MAIN_INPUT)) {
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MEDIASYNC == aml_out->avsync_type) && aml_out->avsync_ctx->mediasync_ctx) {
|
||
aml_out->async_resume = true;
|
||
} else {
|
||
dolby_ms12_main_resume(stream);
|
||
}
|
||
}
|
||
} else if (aml_dev->useSubMix) {
|
||
mixer_resume_inport(aml_dev->audio_mixer, aml_out->inputPortID);
|
||
}
|
||
if (aml_out->pause_status == false) {
|
||
ALOGE("%s(), stream status %d\n", __func__, aml_out->pause_status);
|
||
goto exit;
|
||
}
|
||
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MSYNC == aml_out->avsync_type) && aml_out->avsync_ctx->msync_ctx) {
|
||
av_sync_pause(aml_out->avsync_ctx->msync_ctx->msync_session, false);
|
||
}
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MEDIASYNC == aml_out->avsync_type) && aml_out->avsync_ctx->mediasync_ctx) {
|
||
mediasync_wrap_setPause(aml_out->avsync_ctx->mediasync_ctx->handle, false);
|
||
}
|
||
|
||
exit:
|
||
aml_out->pause_status = false;
|
||
pthread_mutex_unlock (&aml_out->lock);
|
||
pthread_mutex_unlock (&aml_dev->lock);
|
||
|
||
aml_audio_trace_int("out_resume_new", 0);
|
||
return ret;
|
||
}
|
||
|
||
static int out_flush_new (struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
struct dolby_ms12_desc *ms12 = &(adev->ms12);
|
||
bool is_patch_stream = false;
|
||
ALOGI("%s(), stream(%p)\n", __func__, stream);
|
||
out->frame_write_sum = 0;
|
||
out->last_frames_position = 0;
|
||
out->input_bytes_size = 0;
|
||
|
||
aml_audio_trace_int("out_flush_new", 1);
|
||
if (out->stream_type == STREAM_AD_INPUT) {
|
||
ALOGI("%s(), do nothing for AD stream\n", __func__);
|
||
return 0;
|
||
}
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
unmute_after_eos_received (out);
|
||
if (out->total_write_size == 0) {
|
||
out->pause_status = false;
|
||
ALOGI("%s not writing, do nothing", __func__);
|
||
aml_audio_trace_int("out_flush_new", 0);
|
||
return 0;
|
||
}
|
||
if (AVSYNC_TYPE_NULL != out->avsync_type) {
|
||
if ((!out->pause_status) &&
|
||
(adev->ms12.dolby_ms12_enable == true) &&
|
||
(adev->ms12.is_continuous_paused == false) &&
|
||
(out->stream_type == STREAM_MAIN_INPUT) &&
|
||
(!out->eos)) {
|
||
|
||
ALOGI("flush easing pause");
|
||
|
||
/* issue a pause for flush to get easing out w/o stopping msync clock */
|
||
pthread_mutex_lock(&adev->lock);
|
||
pthread_mutex_lock(&out->lock);
|
||
|
||
/*coverity[LOCK_EVASION]: There will be no competition here*/
|
||
ms12->is_continuous_paused = true;
|
||
dolby_ms12_main_pause(stream);
|
||
/*coverity[LOCK_EVASION]: There will be no competition here*/
|
||
out->pause_status = true;
|
||
pthread_mutex_unlock(&out->lock);
|
||
pthread_mutex_unlock(&adev->lock);
|
||
//audio easing duration is 32ms.
|
||
aml_audio_sleep(32000);
|
||
}
|
||
audio_header_info_reset(out->pheader);
|
||
avsync_ctx_reset(out->avsync_ctx);
|
||
|
||
adev->gap_passthrough_state = GAP_PASSTHROUGH_STATE_IDLE;
|
||
adev->gap_offset = 0;
|
||
}
|
||
//normal pcm(mixer thread) do not flush dolby ms12 input buffer
|
||
if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT) {
|
||
if (adev->ms12.dolby_ms12_enable)
|
||
dolby_ms12_main_flush(stream);
|
||
out->continuous_audio_offset = 0;
|
||
/*SWPL-39814, when using exo do seek, sometimes audio track will be reused, then the
|
||
*sequece will be pause->flush->writing data, we need to handle this.
|
||
*It may causes problem for normal pause/flush/resume
|
||
*/
|
||
if ((out->pause_status || adev->ms12.is_continuous_paused) && adev->ms12.dolby_ms12_enable) {
|
||
//audiohal_send_msg_2_ms12(ms12, MS12_MESG_TYPE_RESUME);
|
||
out->async_resume = false;
|
||
dolby_ms12_main_resume(stream);
|
||
}
|
||
}
|
||
hal_clip_meta_cleanup(out->clip_meta);
|
||
|
||
if (NULL != out->scaletempo) {
|
||
hal_scaletempo_force_init(out->scaletempo);
|
||
}
|
||
} else if (adev->useSubMix) {
|
||
aml_decoder_set_config(out->aml_dec, AML_DEC_CONFIG_FLUSH, &out->dec_config);
|
||
mixer_flush_inport(adev->audio_mixer, out->inputPortID);
|
||
}
|
||
|
||
if (out->aml_parser) {
|
||
aml_audio_parser_reset(out->aml_parser);
|
||
}
|
||
|
||
if (true == out->pause_status) {
|
||
if ((NULL != out->avsync_ctx) && (AVSYNC_TYPE_MEDIASYNC == out->avsync_type) && out->avsync_ctx->mediasync_ctx) {
|
||
mediasync_wrap_setPause(out->avsync_ctx->mediasync_ctx->handle, false);
|
||
}
|
||
}
|
||
|
||
out->pause_status = false;
|
||
out->will_flush = false;
|
||
out->u64DecOutFrame = 0;
|
||
|
||
ALOGI("%s(), stream(%p) is_patch_stream(%d) exit\n", __func__, stream, is_patch_stream);
|
||
aml_audio_trace_int("out_flush_new", 0);
|
||
return 0;
|
||
}
|
||
|
||
enum hwsync_status check_hwsync_status (uint32_t apts_gap)
|
||
{
|
||
enum hwsync_status sync_status;
|
||
|
||
if (apts_gap < APTS_DISCONTINUE_THRESHOLD_MIN)
|
||
sync_status = CONTINUATION;
|
||
else if (apts_gap > APTS_DISCONTINUE_THRESHOLD_MAX)
|
||
sync_status = RESYNC;
|
||
else
|
||
sync_status = ADJUSTMENT;
|
||
|
||
return sync_status;
|
||
}
|
||
|
||
static int out_get_render_position (const struct audio_stream_out *stream,
|
||
uint32_t *dsp_frames)
|
||
{
|
||
int ret = 0;
|
||
uint64_t dsp_frame_uint64 = 0;
|
||
struct timespec timetamp = {0};
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
*dsp_frames = 0;
|
||
ret = out_get_presentation_position(stream, &dsp_frame_uint64,&timetamp);
|
||
if (ret == 0)
|
||
{
|
||
*dsp_frames = (uint32_t)(dsp_frame_uint64 & 0xffffffff);
|
||
} else {
|
||
ret = -ENOSYS;
|
||
}
|
||
|
||
if (adev->debug_flag) {
|
||
ALOGD("%s,pos %d ret =%d \n",__func__,*dsp_frames, ret);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*support list return format e.g. Balance Hpeq*/
|
||
static int aml_report_audio_support_list_to_ui (struct aml_audio_device *adev, char *effect_support_list, int max_len) {
|
||
effect_handle_t effect;
|
||
int remaining = max_len;
|
||
char *pos = effect_support_list;
|
||
if (effect_support_list != NULL) {
|
||
memset(effect_support_list, 0, remaining);
|
||
} else {
|
||
return -EINVAL;
|
||
}
|
||
|
||
//1:get amlogic sound effect config
|
||
for (int i = 0 ;i < adev->native_postprocess.num_postprocessors; i++) {
|
||
effect = adev->native_postprocess.postprocessors[i];
|
||
if (!effect || !*effect || !(*effect)->get_descriptor) {
|
||
continue;
|
||
}
|
||
effect_descriptor_t tmpdesc;
|
||
(*effect)->get_descriptor(effect, &tmpdesc);
|
||
int written = snprintf(pos, remaining, " %s", tmpdesc.name);
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store amlogic sound effect type");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
}
|
||
|
||
//2:get dolby config type config
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type_last) {
|
||
int written = snprintf(pos, remaining, " Dolby_MS12_Audio_Config_%s",
|
||
(adev->dolby_ms12_audio_config == MS12_CONFIG_Z ? "Z" :\
|
||
(adev->dolby_ms12_audio_config == MS12_CONFIG_X ? "X" : "Y")));
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store config type");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
}
|
||
|
||
//3:get dolby drc mode config
|
||
int written = snprintf(pos, remaining, " Drc_%s", dolby_lib_decode_enable(adev->dolby_lib_type)? "Show" : "Hide");
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store drc mode");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
|
||
//4. get dts x decoder support
|
||
if (adev->dts_lib_type == eDTSXLib) {
|
||
int written = snprintf(pos, remaining, " dts_x");
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store dts x");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
}
|
||
|
||
// get mpegh decoder support
|
||
if (adev->mpegh_decode_enable) {
|
||
int written = snprintf(pos, remaining, " mpegh");
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store mpegh string");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
}
|
||
|
||
//get ai audio support
|
||
if (adev->aml_ai_audio_type != eAmlAiAudioUnsupported) {
|
||
int written = snprintf(pos, remaining, " aml_ai_support_type=%d", adev->aml_ai_audio_type);
|
||
if (written < 0 || (size_t)written >= remaining) {
|
||
AM_LOGE("not enough space to store aml_ai_support_type string");
|
||
return -EINVAL;
|
||
}
|
||
pos += written;
|
||
remaining -= written;
|
||
}
|
||
return 0;
|
||
}
|
||
static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *dev = out->dev;
|
||
int i;
|
||
int status = 0;
|
||
|
||
pthread_mutex_lock (&dev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
|
||
if (dev->native_postprocess.num_postprocessors >= MAX_POSTPROCESSORS) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
|
||
/* save audio effect handle in audio hal. if it is saved, skip this. */
|
||
for (i = 0; i < dev->native_postprocess.num_postprocessors; i++) {
|
||
if (dev->native_postprocess.postprocessors[i] == effect) {
|
||
status = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
dev->native_postprocess.postprocessors[dev->native_postprocess.num_postprocessors] = effect;
|
||
|
||
effect_descriptor_t tmpdesc;
|
||
(*effect)->get_descriptor(effect, &tmpdesc);
|
||
//Set dts vx sound effect to the first in the sound effect array
|
||
if (0 == strncmp(tmpdesc.name, "VirtualX",strlen("VirtualX"))) {
|
||
dev->native_postprocess.libvx_exist = Check_VX_lib();
|
||
ALOGI("%s, add audio effect: '%s' exist flag : %s", __FUNCTION__, VIRTUALX_LICENSE_LIB_PATH,
|
||
(dev->native_postprocess.libvx_exist) ? "true" : "false");
|
||
/* specify effect order for virtualx. VX does downmix from 5.1 to 2.0 */
|
||
i = dev->native_postprocess.num_postprocessors;
|
||
if (dev->native_postprocess.num_postprocessors >= 1) {
|
||
effect_handle_t tmp;
|
||
tmp = dev->native_postprocess.postprocessors[i];
|
||
dev->native_postprocess.postprocessors[i] = dev->native_postprocess.postprocessors[0];
|
||
dev->native_postprocess.postprocessors[0] = tmp;
|
||
ALOGI("%s, add audio effect: Reorder VirtualX at the first of the effect chain.", __FUNCTION__);
|
||
}
|
||
}
|
||
/*Since HPEQ attenuates the signal, full band drc is used for signal compensation*/
|
||
if (0 == strncmp(tmpdesc.name, "Hpeq", strlen("Hpeq"))) {
|
||
aml_mixer_ctrl_set_int(&dev->alsa_mixer, AML_MIXER_ID_AED_FULL_DRC_ENABLE, 1);
|
||
}
|
||
dev->native_postprocess.num_postprocessors++;
|
||
|
||
ALOGI("%s, add audio effect: %s in audio hal, effect_handle: %p, total num of effects: %d",
|
||
__FUNCTION__, tmpdesc.name, effect, dev->native_postprocess.num_postprocessors);
|
||
|
||
exit:
|
||
pthread_mutex_unlock (&out->lock);
|
||
pthread_mutex_unlock (&dev->lock);
|
||
return status;
|
||
}
|
||
|
||
static int out_remove_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
|
||
{
|
||
/*struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *dev = out->dev;
|
||
int i;
|
||
int status = -EINVAL;
|
||
bool found = false;
|
||
|
||
pthread_mutex_lock (&dev->lock);
|
||
pthread_mutex_lock (&out->lock);
|
||
if (dev->native_postprocess.num_postprocessors <= 0) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
|
||
for (i = 0; i < dev->native_postprocess.num_postprocessors; i++) {
|
||
if (found) {
|
||
dev->native_postprocess.postprocessors[i - 1] = dev->native_postprocess.postprocessors[i];
|
||
continue;
|
||
}
|
||
|
||
if (dev->native_postprocess.postprocessors[i] == effect) {
|
||
dev->native_postprocess.postprocessors[i] = NULL;
|
||
status = 0;
|
||
found = true;
|
||
}
|
||
}
|
||
|
||
if (status != 0)
|
||
goto exit;
|
||
|
||
dev->native_postprocess.num_postprocessors--;
|
||
|
||
effect_descriptor_t tmpdesc;
|
||
(*effect)->get_descriptor(effect, &tmpdesc);
|
||
ALOGI("%s, remove audio effect: %s in audio hal, effect_handle: %p, total num of effects: %d",
|
||
__FUNCTION__, tmpdesc.name, effect, dev->native_postprocess.num_postprocessors);
|
||
|
||
exit:
|
||
pthread_mutex_unlock (&out->lock);
|
||
pthread_mutex_unlock (&dev->lock);
|
||
return status;*/
|
||
return 0;
|
||
}
|
||
|
||
static int out_get_next_write_timestamp (const struct audio_stream_out *stream __unused,
|
||
int64_t *timestamp __unused)
|
||
{
|
||
// return -EINVAL;
|
||
|
||
// VTS can only recognizes Result:OK or Result:INVALID_STATE, which is 0 or 3.
|
||
// So we return ESRCH (3) in order to pass VTS.
|
||
ALOGI ("Amlogic_HAL - %s: return ESRCH (3) instead of -EINVAL (-22)", __FUNCTION__);
|
||
return ESRCH;
|
||
}
|
||
|
||
//actually maybe it be not useful now except pass CTS_TEST:
|
||
// run cts -c android.media.cts.AudioTrackTest -m testGetTimestamp
|
||
static int out_get_presentation_position (const struct audio_stream_out *stream, uint64_t *frames, struct timespec *timestamp)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
uint64_t frames_written_hw = out->last_frames_position;
|
||
int frame_latency = 0,timems_latency = 0;
|
||
int ret = 0;
|
||
|
||
if (!frames || !timestamp) {
|
||
ALOGI("%s, !frames || !timestamp\n", __FUNCTION__);
|
||
return -EINVAL;
|
||
}
|
||
|
||
/* add this code for VTS. */
|
||
if (0 == frames_written_hw) {
|
||
*frames = frames_written_hw;
|
||
*timestamp = out->lasttimestamp;
|
||
return ret;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
ret = aml_audio_get_ms12_presentation_position(stream, frames, timestamp);
|
||
} else if (eDolbyDcvLib == adev->dolby_lib_type) {
|
||
bool is_audio_type_dolby = (adev->audio_type == EAC3 || adev->audio_type == AC3);
|
||
bool is_hal_format_dolby = (out->hal_format == AUDIO_FORMAT_AC3 || out->hal_format == AUDIO_FORMAT_E_AC3);
|
||
/* Fixme, use the tinymix inside aml_audio_earctx_get_type() everytime!!! */
|
||
bool is_earc = (ATTEND_TYPE_EARC == aml_audio_earctx_get_type(adev));
|
||
if (is_audio_type_dolby || is_hal_format_dolby) {
|
||
timems_latency = aml_audio_get_latency_offset(adev->active_outport,
|
||
out->hal_internal_format,
|
||
adev->sink_format,
|
||
adev->ms12.dolby_ms12_enable,
|
||
is_earc);
|
||
frame_latency = timems_latency * (out->hal_rate / 1000);
|
||
}
|
||
if ((frame_latency < 0) && (frames_written_hw < abs(frame_latency))) {
|
||
ALOGV("%s(), not ready yet", __func__);
|
||
return -EINVAL;
|
||
}
|
||
|
||
if (frame_latency >= 0)
|
||
*frames = frame_latency + frames_written_hw;
|
||
else if (frame_latency < 0) {
|
||
if (frames_written_hw >= abs(frame_latency))
|
||
*frames = frame_latency + frames_written_hw;
|
||
else
|
||
*frames = 0;
|
||
}
|
||
|
||
unsigned int output_sr = (out->config.rate) ? (out->config.rate) : (MM_FULL_POWER_SAMPLING_RATE);
|
||
*frames = *frames * out->hal_rate / output_sr;
|
||
*timestamp = out->lasttimestamp;
|
||
} else {
|
||
*frames = out->frame_write_sum;
|
||
*timestamp = out->lasttimestamp;
|
||
}
|
||
|
||
if (adev->debug_flag) {
|
||
#if (_TIME_BITS == 64)
|
||
AM_LOGI("out %p %"PRIu64", sec = %"PRId64", nanosec = %ld tunned_latency_ms %d frame_latency %d",
|
||
out, *frames, timestamp->tv_sec, timestamp->tv_nsec, timems_latency, frame_latency);
|
||
#else
|
||
AM_LOGI("out %p %"PRIu64", sec = %ld, nanosec = %ld tunned_latency_ms %d frame_latency %d",
|
||
out, *frames, timestamp->tv_sec, timestamp->tv_nsec, timems_latency, frame_latency);
|
||
#endif
|
||
int64_t frame_diff_ms = (*frames - out->last_frame_reported) * 1000 / out->hal_rate;
|
||
int64_t system_time_ms = 0;
|
||
if (timestamp->tv_nsec < out->last_timestamp_reported.tv_nsec) {
|
||
system_time_ms = (timestamp->tv_nsec + 1000000000 - out->last_timestamp_reported.tv_nsec)/1000000;
|
||
}
|
||
else
|
||
system_time_ms = (timestamp->tv_nsec - out->last_timestamp_reported.tv_nsec)/1000000;
|
||
int64_t jitter_diff = llabs(frame_diff_ms - system_time_ms);
|
||
if (jitter_diff > JITTER_DURATION_MS) {
|
||
#if (_TIME_BITS == 64)
|
||
AM_LOGI("last pos info: %p %"PRIu64", sec = %"PRId64", nanosec = %ld", out, out->last_frame_reported,
|
||
out->last_timestamp_reported.tv_sec, out->last_timestamp_reported.tv_nsec);
|
||
#else
|
||
AM_LOGI("last pos info: %p %"PRIu64", sec = %ld, nanosec = %ld", out, out->last_frame_reported,
|
||
out->last_timestamp_reported.tv_sec, out->last_timestamp_reported.tv_nsec);
|
||
#endif
|
||
AM_LOGI("system time diff %"PRIu64" ms, position diff %"PRIu64" ms, jitter %"PRIu64" ms",
|
||
system_time_ms,frame_diff_ms,jitter_diff);
|
||
}
|
||
out->last_frame_reported = *frames;
|
||
out->last_timestamp_reported = *timestamp;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/* must be called with hw device and input stream mutexes locked */
|
||
int start_input_stream(struct aml_stream_in *in)
|
||
{
|
||
struct aml_audio_device *adev = in->dev;
|
||
audio_input_config_t config;
|
||
memset(&config, 0, sizeof(audio_input_config_t));
|
||
|
||
config.sample_rate = MM_FULL_POWER_SAMPLING_RATE;
|
||
config.channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
config.format = in->hal_format;
|
||
|
||
adev->active_input = in;
|
||
if (adev->mode != AUDIO_MODE_IN_CALL) {
|
||
adev->in_device &= ~AUDIO_DEVICE_IN_ALL;
|
||
adev->in_device |= in->device;
|
||
}
|
||
|
||
if (in->input_type == AUDIO_INPUT_TYPE_BUILTIN_MIC) {
|
||
config.sample_rate = in->requested_rate;
|
||
}
|
||
|
||
audio_input_open(in->input_type, &config);
|
||
AM_LOGI("input type: %d", in->input_type);
|
||
|
||
#ifndef ANDROID_BUILD
|
||
/* if no supported sample rate is available, use the resampler */
|
||
if (in->resampler) {
|
||
in->resampler->reset(in->resampler);
|
||
in->frames_in = 0;
|
||
}
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
static uint32_t in_get_sample_rate(const struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
|
||
return in->requested_rate;
|
||
}
|
||
|
||
static int in_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static size_t in_get_buffer_size(const struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
size_t size;
|
||
|
||
ALOGD("%s: enter: channel_mask(%#x) rate(%d) format(%#x)", __func__,
|
||
in->hal_channel_mask, in->requested_rate, in->hal_format);
|
||
size = get_input_buffer_size(in->config.period_size, in->requested_rate,
|
||
in->hal_format,
|
||
audio_channel_count_from_in_mask(in->hal_channel_mask));
|
||
/*coverity[missing_lock]:in->source does not need to be lock*/
|
||
if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
|
||
size_t frames = CAPTURE_PERIOD_SIZE;
|
||
frames = CAPTURE_PERIOD_SIZE * PLAYBACK_CODEC_SAMPLING_RATE / CAPTURE_CODEC_SAMPLING_RATE;
|
||
size = get_input_buffer_size(frames, in->requested_rate,
|
||
in->hal_format,
|
||
audio_channel_count_from_in_mask(in->hal_channel_mask));
|
||
}
|
||
|
||
ALOGD("%s: exit: buffer_size = %zu", __func__, size);
|
||
|
||
return size;
|
||
}
|
||
|
||
static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
|
||
return in->hal_channel_mask;
|
||
}
|
||
|
||
static audio_format_t in_get_format(const struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
|
||
ALOGV("%s(%p) in->hal_format=%d", __FUNCTION__, in, in->hal_format);
|
||
return in->hal_format;
|
||
}
|
||
|
||
static int in_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
|
||
{
|
||
return -ENOSYS;
|
||
}
|
||
|
||
/* must be called with hw device and input stream mutexes locked */
|
||
int do_input_standby(struct aml_stream_in *in)
|
||
{
|
||
struct aml_audio_device *adev = in->dev;
|
||
|
||
ALOGD ("%s(%p) in->standby = %d", __FUNCTION__, in, in->standby);
|
||
if (!in->standby) {
|
||
audio_input_close(in->input_type);
|
||
|
||
adev->active_input = NULL;
|
||
in->standby = 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int in_standby(struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
int status;
|
||
|
||
ALOGD("%s: enter: stream(%p)", __func__, stream);
|
||
pthread_mutex_lock(&in->dev->lock);
|
||
pthread_mutex_lock(&in->lock);
|
||
status = do_input_standby(in);
|
||
pthread_mutex_unlock(&in->lock);
|
||
pthread_mutex_unlock(&in->dev->lock);
|
||
ALOGD("%s: exit", __func__);
|
||
|
||
return status;
|
||
}
|
||
|
||
static int in_dump (const struct audio_stream *stream __unused, int fd __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int in_set_parameters (struct audio_stream *stream, const char *kvpairs)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *) stream;
|
||
struct aml_audio_device *adev = in->dev;
|
||
struct str_parms *parms;
|
||
char value[32];
|
||
int ret, val = 0;
|
||
bool do_standby = false;
|
||
|
||
ALOGD ("%s(%p, %s)", __FUNCTION__, stream, kvpairs);
|
||
parms = str_parms_create_str (kvpairs);
|
||
|
||
ret = str_parms_get_str (parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof (value) );
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&in->lock);
|
||
if (ret >= 0) {
|
||
val = atoi (value);
|
||
/* no audio source uses val == 0 */
|
||
if ( (in->source != val) && (val != 0) ) {
|
||
in->source = val;
|
||
do_standby = true;
|
||
}
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
val = atoi (value) & ~AUDIO_DEVICE_BIT_IN;
|
||
if ( (in->device != (unsigned)val) && (val != 0) ) {
|
||
in->device = val;
|
||
do_standby = true;
|
||
}
|
||
}
|
||
|
||
if (do_standby) {
|
||
do_input_standby (in);
|
||
}
|
||
pthread_mutex_unlock (&in->lock);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
|
||
int framesize = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_FRAME_COUNT, &framesize);
|
||
|
||
if (ret >= 0) {
|
||
if (framesize > 0) {
|
||
ALOGI ("Reset audio input hw frame size from %d to %d\n",
|
||
in->config.period_size * in->config.period_count, framesize);
|
||
in->config.period_size = framesize / in->config.period_count;
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&in->lock);
|
||
|
||
if (!in->standby && (in == adev->active_input) ) {
|
||
do_input_standby (in);
|
||
start_input_stream (in);
|
||
in->standby = 0;
|
||
}
|
||
|
||
pthread_mutex_unlock (&in->lock);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
}
|
||
}
|
||
|
||
int format = 0;
|
||
ret = str_parms_get_int (parms, AUDIO_PARAMETER_STREAM_FORMAT, &format);
|
||
|
||
if (ret >= 0) {
|
||
if (format != AUDIO_FORMAT_INVALID) {
|
||
in->hal_format = (audio_format_t)format;
|
||
ALOGV(" in->hal_format:%d <== format:%d\n",
|
||
in->hal_format, format);
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
pthread_mutex_lock (&in->lock);
|
||
if (!in->standby && (in == adev->active_input) ) {
|
||
do_input_standby (in);
|
||
start_input_stream (in);
|
||
in->standby = 0;
|
||
}
|
||
pthread_mutex_unlock (&in->lock);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
}
|
||
}
|
||
|
||
str_parms_destroy (parms);
|
||
|
||
// VTS can only recognizes Result::OK, which is 0x0.
|
||
// So we change ret value to 0 when ret isn't equal to 0
|
||
if (ret > 0) {
|
||
ALOGI ("Amlogic_HAL - %s: change ret value to 0 if it's greater than 0 for passing VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
} else if (ret < 0) {
|
||
ALOGI ("Amlogic_HAL - %s: parameter is NULL, change ret value to 0 if it's greater than 0 for passing VTS test.", __FUNCTION__);
|
||
ret = 0;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
static char * in_get_parameters (const struct audio_stream *stream, const char *keys)
|
||
{
|
||
char *cap = NULL;
|
||
char *para = NULL;
|
||
char temp_buf[AUDIO_HAL_CHAR_MAX_LEN] = {0};
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
|
||
ALOGI ("in_get_parameters %s,in %p\n", keys, in);
|
||
if (strstr (keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS) ) {
|
||
ALOGV ("Amlogic - return hard coded sup_formats list for in stream.\n");
|
||
cap = strdup ("sup_formats=AUDIO_FORMAT_PCM_16_BIT|AUDIO_FORMAT_PCM_32_BIT");
|
||
if (cap) {
|
||
para = strdup (cap);
|
||
aml_audio_free (cap);
|
||
return para;
|
||
}
|
||
} else if (strstr (keys, "alsa_device_config")) {
|
||
sprintf (temp_buf, "period_cnt=%d;period_sz=%d", in->config.period_count, in->config.period_size);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "get_aml_source_latency")) {
|
||
ALOGI ("Error: in_get_parameters can not get_aml_source_latency ");
|
||
return strdup (temp_buf);
|
||
}
|
||
return strdup ("");
|
||
}
|
||
|
||
static int in_set_gain (struct audio_stream_in *stream __unused, float gain __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
#define DEBUG_AEC_VERBOSE (0)
|
||
#define DEBUG_AEC (0) // Remove after AEC is fine-tuned
|
||
#define TIMESTAMP_LEN (8)
|
||
|
||
static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
|
||
{
|
||
int ret = 0;
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
struct aml_audio_device *adev = in->dev;
|
||
size_t in_frames = bytes / audio_stream_in_frame_size(&in->stream);
|
||
size_t size_aec = 0;
|
||
void *buffer_aec = NULL;
|
||
size_t read_size = 0;
|
||
size_t total_read_size = 0;
|
||
|
||
AM_LOGV("stream: %d, bytes %zu", in->source, bytes);
|
||
|
||
/* acquiring hw device mutex systematically is useful if a low priority thread is waiting
|
||
* on the input stream mutex - e.g. executing select_mode() while holding the hw device
|
||
* mutex
|
||
*/
|
||
pthread_mutex_lock(&in->lock);
|
||
|
||
if (in->source == AUDIO_SOURCE_MIXER_OUT || in->source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
if (in->source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
adev->encoder_ctx.enc_buf_space = bytes;
|
||
if (bytes > adev->encoder_ctx.frame_len * audio_stream_in_frame_size(&in->stream)) {
|
||
bytes = adev->encoder_ctx.frame_len * audio_stream_in_frame_size(&in->stream);
|
||
}
|
||
}
|
||
do {
|
||
if (aml_port_get_avail(in->capture_port) > bytes) {
|
||
struct audio_buffer abuffer;
|
||
memset(&abuffer, 0, sizeof(abuffer));
|
||
abuffer.buffer = buffer;
|
||
abuffer.size = bytes;
|
||
read_size = aml_port_pull_buffer(in->capture_port, &abuffer);
|
||
}
|
||
|
||
total_read_size += read_size;
|
||
if (total_read_size < bytes) {
|
||
aml_audio_sleep(1000000 * (bytes - total_read_size) / audio_stream_in_frame_size(&in->stream) /
|
||
MIXER_OUT_DEFAULT_SAMPLE_RATE);
|
||
}
|
||
} while (total_read_size < bytes);
|
||
if (in->source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
bytes = aml_encoder_capture(&adev->encoder_ctx, buffer, total_read_size, buffer);
|
||
}
|
||
} else {
|
||
if (in->standby) {
|
||
ret = start_input_stream(in);
|
||
if (ret < 0)
|
||
goto exit;
|
||
in->standby = 0;
|
||
}
|
||
|
||
/*if need mute input source, don't read data from hardware anymore*/
|
||
if (adev->mic_mute) {
|
||
memset(buffer, 0, bytes);
|
||
/*coverity[sleep]*/
|
||
aml_audio_sleep(bytes * 1000000 / audio_stream_in_frame_size(stream) / in_get_sample_rate(&stream->common));
|
||
ret = 0;
|
||
} else {
|
||
/*if (in->resampler) {
|
||
ret = read_frames(in, buffer, in_frames);
|
||
} else */{
|
||
if (in->device & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
|
||
size_aec = bytes * 2; /* 2ch mic + 2ch loopback */
|
||
buffer_aec = (char *)aml_audio_malloc(size_aec);
|
||
if (buffer_aec == NULL) {
|
||
ret = -ENOMEM;
|
||
goto exit;
|
||
}
|
||
memset(buffer_aec, 0, size_aec);
|
||
|
||
/*coverity[sleep]*/
|
||
ret = audio_input_read(in->input_type, buffer_aec, size_aec);
|
||
aml_dump_audio_bitstreams("dump_pre.raw", buffer_aec, size_aec);
|
||
aec_process(adev->aml_aec, buffer_aec, buffer);
|
||
aml_dump_audio_bitstreams("dump_post.raw", buffer, bytes);
|
||
aml_audio_free(buffer_aec);
|
||
} else {
|
||
ret = audio_input_read(in->input_type, buffer, bytes);
|
||
}
|
||
}
|
||
if (ret < 0)
|
||
goto exit;
|
||
}
|
||
|
||
if (ret >= 0) {
|
||
in->frames_read += in_frames;
|
||
in->timestamp_nsec = audio_input_get_timestamp(in->input_type);
|
||
}
|
||
bool mic_muted = false;
|
||
adev_get_mic_mute((struct audio_hw_device*)adev, &mic_muted);
|
||
if (mic_muted) {
|
||
memset(buffer, 0, bytes);
|
||
}
|
||
}
|
||
exit:
|
||
if (ret < 0) {
|
||
AM_LOGE("%s: read failed - sleeping for buffer duration", __func__);
|
||
/*coverity[sleep]*/
|
||
aml_audio_sleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /in_get_sample_rate(&stream->common));
|
||
}
|
||
pthread_mutex_unlock(&in->lock);
|
||
|
||
if (ret >= 0 && get_debug_value(AML_DUMP_AUDIOHAL_IN)) {
|
||
aml_dump_audio_bitstreams("alsa_read.raw", buffer, bytes);
|
||
}
|
||
return bytes;
|
||
}
|
||
|
||
static int in_get_capture_position (const struct audio_stream_in* stream, int64_t* frames,
|
||
int64_t* time) {
|
||
if (stream == NULL || frames == NULL || time == NULL) {
|
||
return -EINVAL;
|
||
}
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
if ((is_STB(in->dev)) && (in->device & AUDIO_DEVICE_IN_HDMI)) {
|
||
return -ENOSYS;
|
||
}
|
||
/*coverity[missing_lock]:in->frames_read does not need to be lock*/
|
||
*frames = in->frames_read;
|
||
/*coverity[missing_lock]:in->timestamp_nsec does not need to be lock*/
|
||
*time = in->timestamp_nsec;
|
||
|
||
return 0;
|
||
}
|
||
|
||
static uint32_t in_get_input_frames_lost (struct audio_stream_in *stream __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int in_add_audio_effect(const struct audio_stream *stream __unused, effect_handle_t effect __unused)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
int status;
|
||
effect_descriptor_t desc;
|
||
|
||
pthread_mutex_lock(&in->dev->lock);
|
||
pthread_mutex_lock(&in->lock);
|
||
if (in->num_preprocessors >= MAX_PREPROCESSORS) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
|
||
status = (*effect)->get_descriptor(effect, &desc);
|
||
if (status != 0)
|
||
goto exit;
|
||
|
||
in->preprocessors[in->num_preprocessors++] = effect;
|
||
|
||
if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
|
||
in->need_echo_reference = true;
|
||
do_input_standby(in);
|
||
}
|
||
|
||
exit:
|
||
|
||
pthread_mutex_unlock(&in->lock);
|
||
pthread_mutex_unlock(&in->dev->lock);
|
||
return status;
|
||
}
|
||
|
||
static int in_remove_audio_effect(const struct audio_stream *stream,
|
||
effect_handle_t effect)
|
||
{
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
int i;
|
||
int status = -EINVAL;
|
||
bool found = false;
|
||
effect_descriptor_t desc;
|
||
|
||
pthread_mutex_lock(&in->dev->lock);
|
||
pthread_mutex_lock(&in->lock);
|
||
if (in->num_preprocessors <= 0) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
|
||
for (i = 0; i < in->num_preprocessors; i++) {
|
||
if (found) {
|
||
in->preprocessors[i - 1] = in->preprocessors[i];
|
||
continue;
|
||
}
|
||
if (in->preprocessors[i] == effect) {
|
||
in->preprocessors[i] = NULL;
|
||
status = 0;
|
||
found = true;
|
||
}
|
||
}
|
||
|
||
if (status != 0)
|
||
goto exit;
|
||
|
||
in->num_preprocessors--;
|
||
|
||
status = (*effect)->get_descriptor(effect, &desc);
|
||
if (status != 0)
|
||
goto exit;
|
||
if (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
|
||
in->need_echo_reference = false;
|
||
do_input_standby(in);
|
||
}
|
||
|
||
exit:
|
||
|
||
pthread_mutex_unlock(&in->lock);
|
||
pthread_mutex_unlock(&in->dev->lock);
|
||
return status;
|
||
}
|
||
|
||
static int in_get_active_microphones (const struct audio_stream_in *stream,
|
||
struct audio_microphone_characteristic_t *mic_array,
|
||
size_t *mic_count) {
|
||
ALOGV("in_get_active_microphones");
|
||
if ((mic_array == NULL) || (mic_count == NULL)) {
|
||
return -EINVAL;
|
||
}
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
struct audio_hw_device* dev = (struct audio_hw_device*)in->dev;
|
||
bool mic_muted = false;
|
||
adev_get_mic_mute(dev, &mic_muted);
|
||
/*coverity[missing_lock]:in->source does not need to be lock*/
|
||
if ((in->source == AUDIO_SOURCE_ECHO_REFERENCE) || mic_muted) {
|
||
*mic_count = 0;
|
||
return 0;
|
||
}
|
||
adev_get_microphones(dev, mic_array, mic_count);
|
||
return 0;
|
||
}
|
||
|
||
static int adev_get_microphones (const struct audio_hw_device* dev __unused,
|
||
struct audio_microphone_characteristic_t* mic_array,
|
||
size_t* mic_count) {
|
||
ALOGV("adev_get_microphones");
|
||
if ((mic_array == NULL) || (mic_count == NULL)) {
|
||
return -EINVAL;
|
||
}
|
||
get_mic_characteristics(mic_array, mic_count);
|
||
return 0;
|
||
}
|
||
|
||
static void get_mic_characteristics (struct audio_microphone_characteristic_t* mic_data,
|
||
size_t* mic_count) {
|
||
*mic_count = 1;
|
||
memset(mic_data, 0, sizeof(struct audio_microphone_characteristic_t));
|
||
strncpy(mic_data->device_id, "builtin_mic", sizeof(mic_data->device_id));
|
||
strncpy(mic_data->address, "top", sizeof(mic_data->address));
|
||
|
||
memset(mic_data->channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED,
|
||
sizeof(mic_data->channel_mapping));
|
||
mic_data->device = AUDIO_DEVICE_IN_BUILTIN_MIC;
|
||
mic_data->sensitivity = -37.0;
|
||
mic_data->max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
|
||
mic_data->min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
|
||
mic_data->orientation.x = 0.0f;
|
||
mic_data->orientation.y = 0.0f;
|
||
mic_data->orientation.z = 0.0f;
|
||
mic_data->geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
|
||
mic_data->geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
|
||
mic_data->geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
|
||
}
|
||
|
||
static int aml_is_audio_playing(struct aml_audio_device *adev) {
|
||
pthread_mutex_lock (&adev->lock);
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
if (aml_out) {
|
||
if (aml_out->stream_type == STREAM_MAIN_INPUT && (false == aml_out->pause_status)) {
|
||
ALOGI("main stream(%p) is playing", aml_out);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
return 1;
|
||
} else if (aml_out->stream_type == STREAM_AUX_INPUT && aml_out->is_airplay) {
|
||
ALOGI("aux airplay stream(%p) is playing", aml_out);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
ALOGI("main audio is not playing");
|
||
return 0;
|
||
}
|
||
|
||
char * get_output_port_information(struct aml_audio_device *adev, char *output_port_info) {
|
||
if (output_port_info == NULL)
|
||
return "";
|
||
|
||
int output_channel = 2;
|
||
if (adev->active_outport == OUTPORT_SPEAKER || adev->active_outport == OUTPORT_HEADPHONE) {
|
||
sprintf(output_port_info, "%s,2,pcm", audioActivePort2NetflixStandardStr(adev->active_outport));
|
||
} else {
|
||
if ((adev->optical_format == AUDIO_FORMAT_PCM_16_BIT) && (adev->output_multipcm_ch != 0)) {
|
||
output_channel = adev->output_multipcm_ch;
|
||
} else if (adev->optical_format == AUDIO_FORMAT_E_AC3) {
|
||
output_channel = adev->output_ddp_ch;
|
||
} else if (adev->optical_format == AUDIO_FORMAT_AC3) {
|
||
output_channel = adev->output_dd_ch;
|
||
} else if (adev->optical_format == AUDIO_FORMAT_MAT) {
|
||
output_channel = adev->output_mat_ch;
|
||
}
|
||
sprintf(output_port_info, "%s,%d,%s", audioActivePort2NetflixStandardStr(adev->active_outport), output_channel, audioFormat2NetflixStandardStr(adev->optical_format));
|
||
}
|
||
return output_port_info;
|
||
}
|
||
|
||
static int out_set_event_callback(struct audio_stream_out *stream __unused,
|
||
stream_event_callback_t callback, void *cookie /*StreamOut*/)
|
||
{
|
||
ALOGD("func:%s callback:%p cookie:%p", __func__, callback, cookie);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static inline int set_stream_config(struct aml_stream_out *out, struct audio_config *config, audio_output_flags_t flags)
|
||
{
|
||
struct aml_audio_device *adev = out->dev;
|
||
out->config.channels = audio_channel_count_from_out_mask(config->channel_mask);
|
||
out->config.rate = config->sample_rate;
|
||
switch (config->format) {
|
||
case AUDIO_FORMAT_PCM_16_BIT:
|
||
out->config.format = PCM_FORMAT_S16_LE;
|
||
break;
|
||
case AUDIO_FORMAT_PCM_FLOAT:
|
||
case AUDIO_FORMAT_PCM_32_BIT:
|
||
out->config.format = PCM_FORMAT_S32_LE;
|
||
break;
|
||
case AUDIO_FORMAT_IEC61937:
|
||
if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
|
||
if (out->config.channels == 2 && (out->config.rate == 192000 || out->config.rate == 176400 || out->config.rate == 128000)) {
|
||
out->config.rate /= 4;
|
||
out->hal_internal_format = AUDIO_FORMAT_E_AC3;
|
||
} else if (out->config.channels == 2 && out->config.rate >= 32000 && out->config.rate <= 48000) {
|
||
if (adev->audio_type == DTS) {
|
||
out->hal_internal_format = AUDIO_FORMAT_DTS;
|
||
//adev->dts_hd.is_dtscd = false;
|
||
adev->dolby_lib_type = eDolbyDcvLib;
|
||
out->restore_dolby_lib_type = true;
|
||
} else {
|
||
out->hal_internal_format = AUDIO_FORMAT_AC3;
|
||
}
|
||
} else if (out->config.channels >= 6 && out->config.rate == 192000) {
|
||
out->hal_internal_format = AUDIO_FORMAT_DTS_HD;
|
||
}
|
||
ALOGI("convert format IEC61937 to 0x%x\n", out->hal_internal_format);
|
||
}
|
||
break;
|
||
case AUDIO_FORMAT_AC3:
|
||
case AUDIO_FORMAT_E_AC3:
|
||
case AUDIO_FORMAT_AC4:
|
||
case AUDIO_FORMAT_DTS:
|
||
case AUDIO_FORMAT_DTS_HD:
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
if (codec_type_is_raw_data(out->codec_type)) {
|
||
ALOGI("%s: for raw audio output,force alsa stereo output", __func__);
|
||
out->config.channels = 2;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int get_stream_source_volume(struct aml_stream_out *aml_out)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
||
switch (aml_out->source_type) {
|
||
case DTV_SRC:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_TUNER);
|
||
break;
|
||
case ATV_SRC:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_ATV);
|
||
break;
|
||
case AV_SRC:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_LINEIN);
|
||
break;
|
||
case HDMI_SRC:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_HDMIIN);
|
||
break;
|
||
case HDMI1_SRC:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_HDMIIN1);
|
||
break;
|
||
default:
|
||
aml_out->source_volume = get_inport_gain(adev, INPORT_MEDIA);
|
||
break;
|
||
}
|
||
AM_LOGI("stream:%p, source_type:%s, source_volume:%f",aml_out, StreamSourceType2Str(aml_out->source_type), aml_out->source_volume);
|
||
return 0;
|
||
}
|
||
|
||
// open corresponding stream by flags, formats and others params
|
||
static int adev_open_output_stream(struct audio_hw_device *dev,
|
||
audio_io_handle_t handle __unused,
|
||
audio_devices_t devices,
|
||
audio_output_flags_t flags,
|
||
struct audio_config *config,
|
||
struct audio_stream_out **stream_out,
|
||
const char *address)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
struct aml_stream_out *out;
|
||
int ret = 0;
|
||
|
||
AM_LOGD("enter: devices(%#x) channel_mask(%#x) rate(%d) format(%#x) flags(%#x) address:%s",
|
||
devices, config->channel_mask, config->sample_rate, config->format, flags, (address?address:"NULL"));
|
||
ALOGI("%s: enter, ver:%s", __func__, libVersion_audio_hal);
|
||
out = (struct aml_stream_out *)aml_audio_calloc(1, sizeof(struct aml_stream_out));
|
||
if (!out) {
|
||
ALOGE("%s malloc error", __func__);
|
||
return -ENOMEM;
|
||
}
|
||
|
||
if (flags == AUDIO_OUTPUT_FLAG_NONE)
|
||
flags = AUDIO_OUTPUT_FLAG_PRIMARY;
|
||
if (config->channel_mask == AUDIO_CHANNEL_NONE)
|
||
config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
|
||
if (config->sample_rate == 0)
|
||
config->sample_rate = 48000;
|
||
|
||
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||
if (config->format == AUDIO_FORMAT_DEFAULT) {
|
||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||
}
|
||
out->config = pcm_config_out;
|
||
} else if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
|
||
out->config = pcm_config_out_direct;
|
||
} else {
|
||
out->config = pcm_config_out;
|
||
}
|
||
out->hal_channel_mask = config->channel_mask;
|
||
out->hal_rate = config->sample_rate;
|
||
out->hal_format = config->format;
|
||
out->hal_internal_format = out->hal_format;
|
||
out->hal_input_is_float = false;
|
||
if (config->format == AUDIO_FORMAT_PCM_FLOAT) {
|
||
out->hal_input_is_float = true;
|
||
out->hal_format = AUDIO_FORMAT_PCM_32_BIT;
|
||
out->hal_internal_format = AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
if (out->hal_internal_format == AUDIO_FORMAT_E_AC3_JOC) {
|
||
out->hal_internal_format = AUDIO_FORMAT_E_AC3;
|
||
ALOGD("config hal_format %#x change to hal_internal_format(%#x)!", out->hal_format, out->hal_internal_format);
|
||
}
|
||
out->codec_type = get_codec_type(out->hal_internal_format);
|
||
set_stream_config(out, config, flags);
|
||
|
||
|
||
if (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
|
||
out->need_sync = true;
|
||
} else {
|
||
out->need_sync = false;
|
||
}
|
||
AM_LOGI("Set out->need_sync:%d", out->need_sync);
|
||
|
||
out->dev = adev;
|
||
if (address) {
|
||
AM_LOGI("address: %s", address);
|
||
if (!strncmp(address, "AML_", 4)) {
|
||
ALOGI("%s(): aml TV source stream = %s", __func__, address);
|
||
out->tv_src_stream = true;
|
||
}
|
||
|
||
//set source_type, this must be set before stream_type_validate_l
|
||
if (!strncmp(address, "AML_ATV", 7)) {
|
||
out->source_type = ATV_SRC;
|
||
} else if (!strncmp(address, "AML_DTV", 7)) {
|
||
out->source_type = DTV_SRC;
|
||
} else if (!strncmp(address, "AML_AV", 6)) {
|
||
out->source_type = AV_SRC;
|
||
} else if (!strncmp(address, "AML_HDMI1", 9)) {
|
||
out->source_type = HDMI1_SRC;
|
||
} else if (!strncmp(address, "AML_HDMI", 8)) {
|
||
out->source_type = HDMI_SRC;
|
||
}
|
||
|
||
if (!strcmp(address, LLP_BUFFER_NAME)) {
|
||
int nChannel = audio_channel_count_from_out_mask(out->hal_channel_mask);
|
||
if (0 != llp_init(adev, nChannel)) {
|
||
goto err;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (adev->dolby_lib_type_last == eDolbyMS12Lib && !(flags & AUDIO_OUTPUT_FLAG_AD_STREAM)) {
|
||
/*if these format can't be supported by ms12, we can bypass it*/
|
||
if (is_bypass_dolbyms12((struct audio_stream_out *)out)) {
|
||
if (adev->ms12.dolby_ms12_enable) {
|
||
AM_LOGI("bypass aml_ms12, clean up aml_ms12");
|
||
adev_ms12_cleanup((struct audio_hw_device *)adev);
|
||
}
|
||
adev->dolby_lib_type = eDolbyDcvLib;
|
||
out->restore_dolby_lib_type = true;
|
||
AM_LOGI("bypass aml_ms12 change aml_dolby dcv lib type");
|
||
}
|
||
}
|
||
|
||
out->stream.common.get_sample_rate = out_get_sample_rate;
|
||
out->stream.common.set_sample_rate = out_set_sample_rate;
|
||
out->stream.common.get_buffer_size = out_get_buffer_size;
|
||
out->stream.common.set_format = out_set_format;
|
||
out->stream.common.dump = out_dump;
|
||
out->stream.common.set_parameters = out_set_parameters;
|
||
out->stream.common.get_parameters = out_get_parameters;
|
||
out->stream.common.add_audio_effect = out_add_audio_effect;
|
||
out->stream.common.remove_audio_effect = out_remove_audio_effect;
|
||
out->stream.common.standby = out_standby_new;
|
||
out->stream.common.get_channels = out_get_channels;
|
||
out->stream.common.get_format = out_get_format;
|
||
/* Assign value to out->flags, out->stream_type, out->write, and decide whether enable scaletempo */
|
||
if (stream_type_validate_l(out, flags) < 0) {
|
||
AM_LOGE("stream_type_validate_l failed");
|
||
aml_audio_trace_int("adev_open_output_stream_new", 0);
|
||
ret = -ENOMEM;
|
||
goto err;
|
||
}
|
||
out->stream.get_latency = out_get_latency;
|
||
out->stream.set_volume = out_set_volume;
|
||
out->stream.get_render_position = out_get_render_position;
|
||
out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
|
||
out->stream.get_presentation_position = out_get_presentation_position;
|
||
out->stream.set_event_callback = out_set_event_callback;
|
||
out->stream.write = out_write_new;
|
||
out->stream.pause = out_pause_new;
|
||
out->stream.resume = out_resume_new;
|
||
out->stream.flush = out_flush_new;
|
||
out->out_device = devices;
|
||
out->is_normal_pcm = (out->stream_type == STREAM_AUX_INPUT || out->stream_type == STREAM_DEEP_INPUT) ? 1 : 0;
|
||
out->hal_ch = audio_channel_count_from_out_mask(out->hal_channel_mask);
|
||
out->hal_frame_size = audio_bytes_per_frame(out->hal_ch, out->hal_internal_format);
|
||
if (out->hal_ch == 0) {
|
||
out->hal_ch = 2;
|
||
}
|
||
if (out->hal_frame_size == 0) {
|
||
out->hal_frame_size = 1;
|
||
}
|
||
|
||
if (out->stream_type == STREAM_MAIN_INPUT) {
|
||
adev->audio_hal_info.format = AUDIO_FORMAT_PCM;
|
||
adev->audio_hal_info.is_dolby_atmos = 0;
|
||
adev->audio_hal_info.update_type = TYPE_PCM;
|
||
adev->audio_hal_info.first_decoding_frame = false;
|
||
adev->audio_hal_info.dts_type_is_updated = false;
|
||
}
|
||
|
||
if (out->stream_type == STREAM_MAIN_INPUT || out->stream_type == STREAM_AD_INPUT) {
|
||
get_stream_source_volume(out);
|
||
} else {
|
||
out->source_volume = 1.0;
|
||
}
|
||
|
||
if (out->stream_type == STREAM_HWMIXER_INPUT) {
|
||
aml_audio_hwmixer_out_open(adev);
|
||
}
|
||
if (adev->enable_deep_unit && out->stream_type == STREAM_DEEP_INPUT) {
|
||
audio_unit_acquire_port(adev->deep_unit, &out->deep_inport, AUDIO_PORT_INPUT);
|
||
}
|
||
|
||
if (out->source_type == DTV_SRC) {
|
||
out->volume_l_org = get_dtv_volume(adev);
|
||
out->volume_r_org = get_dtv_volume(adev);
|
||
} else {
|
||
out->volume_l_org = 1.0;//stream volume
|
||
out->volume_r_org = 1.0;
|
||
}
|
||
|
||
out->last_volume_l_org = out->volume_l_org;
|
||
out->last_volume_r_org = out->volume_r_org;
|
||
out->volume_l = adev->master_volume * out->volume_l_org;//out volume
|
||
out->volume_r = adev->master_volume * out->volume_r_org;
|
||
out->last_volume_l = 0.0;
|
||
out->last_volume_r = 0.0;
|
||
out->drc_mode_volume = 1.0;
|
||
out->last_drc_mode_volume = 1.0;
|
||
out->standby = true;
|
||
out->frame_write_sum = 0;
|
||
out->need_convert = false;
|
||
out->position_update = 0;
|
||
out->inputPortID = -1;
|
||
out->will_pause = false;
|
||
out->will_flush = false;
|
||
out->eos = false;
|
||
out->output_speed = 1.0f;
|
||
out->clip_offset = 0;
|
||
out->clip_meta = NULL;
|
||
out->drop_start = -1;
|
||
out->drop_duration = -1;
|
||
out->ddp_frame_size = aml_audio_get_ddp_frame_size();
|
||
out->resample_handle = NULL;
|
||
out->set_init_avsync_policy = false;
|
||
out->unique_ID = adev->next_unique_ID;
|
||
adev->next_unique_ID++;
|
||
out->scale_state = SCALE_NULL;
|
||
out->rate = 0.0;
|
||
out->decoder_id = -1;
|
||
out->u64DecOutFrame = 0;
|
||
out->is_aacpcm = false;
|
||
out->async_resume = false;
|
||
//#ifdef ENABLE_MMAP
|
||
#ifndef BUILD_LINUX
|
||
if (out->stream_type == STREAM_APP_INPUT) {
|
||
outMmapInit(out);
|
||
}
|
||
#endif
|
||
if (out->stream_type != STREAM_AD_INPUT) {
|
||
out->avsync_ctx = avsync_ctx_init();
|
||
if (NULL == out->avsync_ctx) {
|
||
ret = -ENOMEM;
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
/* set param to ms12, then mcn can be processed correctly when aux input. */
|
||
if (out->stream_type == STREAM_AUX_INPUT && eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
char parm1[32] = "\0";
|
||
char parm2[32] = "\0";
|
||
int chs = 2, ls = 0;
|
||
if (6 == audio_channel_count_from_out_mask(out->hal_channel_mask)) {
|
||
chs = 7;
|
||
ls = 1;
|
||
}
|
||
sprintf(parm1, "%s %d", "-chs", chs);
|
||
sprintf(parm2, "%s %d", "-ls", ls);
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm1);
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm2);
|
||
}
|
||
|
||
if (adev->user_setting_scaletempo && out->enable_scaletempo) {
|
||
hal_scaletempo_init(&out->scaletempo);
|
||
if ((out->flags & AUDIO_OUTPUT_FLAG_HBBTV || is_dts_format(out->hal_internal_format)) && out->scaletempo) {
|
||
hal_scaletempo_set_bypass(out->scaletempo, true);
|
||
}
|
||
AM_LOGI("enable scaletempo %p", out);
|
||
}
|
||
init_aml_pcm_downmix(&out->pcm_downmix);
|
||
out->downmix_tmp_buf_size = 2048 * audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT) * 2;
|
||
out->downmix_tmp_buf = aml_audio_malloc(out->downmix_tmp_buf_size);
|
||
out->float_to_s32_tmp_buf_size = 2048 * audio_bytes_per_sample(AUDIO_FORMAT_PCM_32_BIT) * 2;
|
||
out->float_to_s32_tmp_buf = aml_audio_malloc(out->float_to_s32_tmp_buf_size);
|
||
|
||
/*if tunnel mode pcm is not 48Khz, resample to 48K*/
|
||
if (out->stream_type == STREAM_MAIN_INPUT) {
|
||
ALOGD("%s format=%d rate=%d", __func__, out->hal_internal_format, out->config.rate);
|
||
if (audio_is_linear_pcm(out->hal_internal_format) && out->config.rate != 48000) {
|
||
ALOGI("init resampler from %d to 48000!\n", out->config.rate);
|
||
out->aml_resample.input_sr = out->config.rate;
|
||
out->aml_resample.output_sr = 48000;
|
||
out->aml_resample.channels = 2;
|
||
resampler_init (&out->aml_resample);
|
||
/*max buffer from 32K to 48K*/
|
||
if (!out->resample_outbuf) {
|
||
out->resample_outbuf = (unsigned char*) aml_audio_malloc (8192 * 10);
|
||
if (!out->resample_outbuf) {
|
||
ALOGE ("malloc buffer failed\n");
|
||
ret = -1;
|
||
goto err;
|
||
}
|
||
}
|
||
} else {
|
||
if (out->resample_outbuf)
|
||
aml_audio_free(out->resample_outbuf);
|
||
out->resample_outbuf = NULL;
|
||
}
|
||
|
||
if (adev->is_netflix) {
|
||
adev->gap_passthrough_state = GAP_PASSTHROUGH_STATE_IDLE;
|
||
adev->gap_offset = 0;
|
||
}
|
||
}
|
||
out->eos_ease_timer = aml_audio_timer_create(eos_timer_callback_handler, (void *)out);
|
||
|
||
*stream_out = &out->stream;
|
||
AM_LOGD("exit!!");
|
||
return 0;
|
||
err:
|
||
llp_deinit(adev);
|
||
if (out->avsync_ctx)
|
||
aml_audio_free(out->avsync_ctx);
|
||
aml_audio_free(out);
|
||
ALOGE("%s exit failed =%d", __func__, ret);
|
||
return ret;
|
||
}
|
||
|
||
static void close_ms12_output_main_stream(struct audio_stream_out *stream) {
|
||
struct aml_stream_out *out = (struct aml_stream_out *)stream;
|
||
struct aml_audio_device *adev = out->dev;
|
||
|
||
/*main stream is closed, close the ms12 main decoder*/
|
||
if (out->is_ms12_main_decoder) {
|
||
pthread_mutex_lock(&adev->ms12.lock);
|
||
/*after ms12 lock, dolby_ms12_enable may be cleared with clean up function*/
|
||
if (adev->ms12.dolby_ms12_enable) {
|
||
adev->ms12.need_ms12_resume = false;
|
||
adev->ms12.need_resync = 0;
|
||
audiohal_send_msg_2_ms12(&adev->ms12, MS12_MESG_TYPE_FLUSH);
|
||
/*coverity[missing_lock]*/
|
||
adev->ms12.ms12_resume_state = MS12_RESUME_FROM_CLOSE;
|
||
audiohal_send_msg_2_ms12(&adev->ms12, MS12_MESG_TYPE_RESUME);
|
||
}
|
||
/*coverity[double_unlock]*/
|
||
pthread_mutex_unlock(&adev->ms12.lock);
|
||
|
||
/*main stream is closed, wait mesg processed*/
|
||
{
|
||
int wait_cnt = 0;
|
||
while (!ms12_msg_list_is_empty(&adev->ms12)) {
|
||
aml_audio_sleep(5000);
|
||
wait_cnt++;
|
||
if (wait_cnt >= 200) {
|
||
break;
|
||
}
|
||
}
|
||
AM_LOGI("main stream message is processed cost =%d ms", wait_cnt * 5);
|
||
}
|
||
if (out->pheader) {
|
||
/*we only support one stream hw sync and MS12 always attach with it.
|
||
So when it is released, ms12 also need set pheader to NULL*/
|
||
out->need_sync = 0;
|
||
}
|
||
dolby_ms12_main_close(stream);
|
||
out->is_ms12_main_decoder = false;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
//static int out_standby_new(struct audio_stream *stream);
|
||
static void adev_close_output_stream(struct audio_hw_device *dev,
|
||
struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *out = (struct aml_stream_out *)stream;
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
|
||
if (dev == NULL || stream == NULL) {
|
||
ALOGE("%s: Input parameter error!!!", __func__);
|
||
return;
|
||
}
|
||
|
||
AM_LOGI("enter: dev(%p) stream(%p) stream ID(%d)", dev, stream, out->unique_ID);
|
||
|
||
if (out->aml_dec) {
|
||
aml_decoder_release(out->aml_dec);
|
||
out->aml_dec = NULL;
|
||
}
|
||
stream->common.standby(&stream->common);
|
||
pthread_mutex_lock(&adev->audio_mixer_lock);
|
||
if (out->inputPortID != -1 && adev->useSubMix) {
|
||
delete_mixer_input_port(adev->audio_mixer, out->inputPortID);
|
||
out->inputPortID = -1;
|
||
}
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
|
||
pthread_mutex_lock(&out->lock);
|
||
|
||
aml_audio_timer_delete(out->eos_ease_timer);
|
||
|
||
if (out->is_ms12_main_decoder) {
|
||
close_ms12_output_main_stream(stream);
|
||
}
|
||
|
||
if (out->spdifenc_init) {
|
||
aml_spdif_encoder_close(out->spdifenc_handle);
|
||
out->spdifenc_handle = NULL;
|
||
out->spdifenc_init = false;
|
||
}
|
||
|
||
if (out->avsync_ctx) {
|
||
pthread_mutex_lock(&(out->avsync_ctx->lock));
|
||
if (out->avsync_ctx->msync_ctx) {
|
||
if (out->avsync_ctx->msync_ctx->msync_session) {
|
||
msync_unblock_start(out->avsync_ctx->msync_ctx);
|
||
av_sync_destroy(out->avsync_ctx->msync_ctx->msync_session);
|
||
}
|
||
aml_audio_free(out->avsync_ctx->msync_ctx);
|
||
out->avsync_ctx->msync_ctx = NULL;
|
||
}
|
||
if (out->avsync_ctx->mediasync_ctx) {
|
||
if (out->avsync_ctx->mediasync_ctx->handle) {
|
||
mediasync_wrap_destroy(out->avsync_ctx->mediasync_ctx->handle);
|
||
}
|
||
aml_audio_free(out->avsync_ctx->mediasync_ctx);
|
||
out->avsync_ctx->mediasync_ctx = NULL;
|
||
}
|
||
pthread_mutex_unlock(&(out->avsync_ctx->lock));
|
||
aml_audio_free(out->avsync_ctx);
|
||
out->avsync_ctx = NULL;
|
||
}
|
||
|
||
#ifdef USE_MEDIAINFO
|
||
if (adev->minfo_h) {
|
||
if (adev->info_rid != -1) {
|
||
minfo_retrieve_record(adev->minfo_h, adev->info_rid);
|
||
adev->info_rid = -1;
|
||
adev->minfo_atmos_flag = -1;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//#ifdef ENABLE_MMAP
|
||
#ifndef BUILD_LINUX
|
||
if (out->stream_type == STREAM_APP_INPUT) {
|
||
outMmapDeInit(out);
|
||
}
|
||
#endif
|
||
|
||
if (out->restore_hdmitx_selection) {
|
||
/* switch back to spdifa when the dual stream is done */
|
||
aml_audio_select_spdif_to_hdmi(AML_SPDIF_A_TO_HDMITX);
|
||
out->restore_hdmitx_selection = false;
|
||
}
|
||
if (out->resample_outbuf) {
|
||
aml_audio_free(out->resample_outbuf);
|
||
out->resample_outbuf = NULL;
|
||
}
|
||
|
||
if (out->aml_parser) {
|
||
aml_audio_parser_close(out->aml_parser);
|
||
out->aml_parser = NULL;
|
||
}
|
||
|
||
if (out->pheader) {
|
||
aml_audio_free(out->pheader);
|
||
out->pheader = NULL;
|
||
}
|
||
if (adev->dolby_lib_type != eDolbyMS12Lib) {
|
||
aml_audio_spdif_output_close_all();
|
||
}
|
||
|
||
if (out->resample_handle) {
|
||
aml_audio_resample_close(out->resample_handle);
|
||
out->resample_handle = NULL;
|
||
}
|
||
|
||
if (out->scaletempo) {
|
||
ALOGI("%s %d, release scaletempo %p", __FUNCTION__, __LINE__, out);
|
||
out->enable_scaletempo = false;
|
||
hal_scaletempo_release(out->scaletempo);
|
||
out->scaletempo = NULL;
|
||
}
|
||
deinit_aml_pcm_downmix(&out->pcm_downmix);
|
||
if (out->downmix_tmp_buf) {
|
||
aml_audio_free(out->downmix_tmp_buf);
|
||
out->downmix_tmp_buf = NULL;
|
||
}
|
||
if (out->float_to_s32_tmp_buf) {
|
||
aml_audio_free(out->float_to_s32_tmp_buf);
|
||
out->float_to_s32_tmp_buf = NULL;
|
||
}
|
||
|
||
if (out->clip_meta) {
|
||
hal_clip_meta_release(out->clip_meta);
|
||
out->clip_meta = NULL;
|
||
out->clip_offset = 0;
|
||
//dolby_ms12_register_callback_by_type(CALLBACK_CLIP_META, NULL, NULL);
|
||
}
|
||
|
||
if (out->mpegh_uimanager_handle) {
|
||
aml_mpegh_close(adev, out->mpegh_uimanager_handle);
|
||
AM_LOGI("mpegh stream will close");
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AUDIO_HAL_FORMAT, TYPE_MPEGH_CLOSE);
|
||
out->mpegh_uimanager_handle = NULL;
|
||
}
|
||
|
||
llp_deinit(adev);
|
||
out->need_sync = false;
|
||
out->with_header = false;
|
||
if (out->stream_type == STREAM_MAIN_INPUT) {
|
||
//clear the hal format when main close.
|
||
adev->audio_hal_info.update_type = TYPE_PCM;
|
||
adev->audio_hal_info.is_decoding = false;
|
||
adev->audio_hal_info.first_decoding_frame = false;
|
||
adev->audio_hal_info.dts_type_is_updated = false;
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AUDIO_HAL_FORMAT, TYPE_PCM);
|
||
}
|
||
if (out->stream_type == STREAM_AUX_INPUT && out->is_airplay) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AUDIO_HAL_FORMAT, TYPE_PCM);
|
||
AM_LOGI("airplay stream closed, trigger uevent");
|
||
}
|
||
pthread_mutex_unlock(&out->lock);
|
||
if (out->stream_type == STREAM_HWMIXER_INPUT) {
|
||
aml_audio_hwmixer_out_close(adev);
|
||
}
|
||
|
||
if (adev->ms12.dolby_ms12_enable) {
|
||
if (!adev->low_latency_mode) //inject Sometimes open->close->open, this action will cancel the response lowlatency
|
||
set_ms12_alsa_limit_frame(&adev->ms12, MS12_ALSA_DEFAULT_LIMIT_FRAME);
|
||
if (out->stream_type == STREAM_APP_INPUT) {
|
||
set_ms12_app_buffer_flush(&adev->ms12, true);
|
||
AM_LOGI("flush ms12 app buffer");
|
||
} else if (out->stream_type == STREAM_AUX_INPUT) {
|
||
set_ms12_system_buffer_flush(&adev->ms12, true);
|
||
AM_LOGI("flush ms12 system buffer");
|
||
}
|
||
}
|
||
adev->audio_low_latency = false;
|
||
|
||
//we muted in audio_header_find_frame when find eos, here recover mute
|
||
if (adev->dolby_lib_type != eDolbyMS12Lib && out->stream_type != STREAM_AD_INPUT) {
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, false);
|
||
}
|
||
|
||
if (out->stream_type == STREAM_APP_INPUT) {
|
||
out_set_volume(stream, 0.0f, 0.0f);
|
||
}
|
||
/*the dolby lib is changed, so we need restore it*/
|
||
if (out->restore_dolby_lib_type) {
|
||
adev->dolby_lib_type = adev->dolby_lib_type_last;
|
||
if (adev->effect_ctrl.effect_mode == EFFECT_MODE_DAP && is_dts_format(out->hal_internal_format)) {
|
||
if (adev->ms12.dap_only_enable) {
|
||
aml_dap_close(&adev->ms12);
|
||
}
|
||
}
|
||
AM_LOGI("restore dolby lib =%d, audio_mixer %p", adev->dolby_lib_type, adev->audio_mixer);
|
||
/* delete submix after adev->dolby_lib_type restore to eDolbyMS12Lib*/
|
||
pthread_mutex_lock(&adev->audio_mixer_lock);
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && adev->audio_mixer) {
|
||
deleteHalSubMixing(adev);
|
||
adev->useSubMix = false;
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
int ret = adev_ms12_prepare((struct audio_hw_device *)adev);
|
||
if (0 != ret) {
|
||
ALOGE("%s, adev_ms12_prepare fail!\n", __func__);
|
||
}
|
||
} else {
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
}
|
||
}
|
||
|
||
if (adev->hw_mixer.start_buf && out->stream_type == STREAM_MAIN_INPUT) {
|
||
aml_hw_mixer_deinit(&adev->hw_mixer);
|
||
}
|
||
|
||
if (adev->enable_deep_unit && out->stream_type == STREAM_DEEP_INPUT) {
|
||
aml_port_command(out->deep_inport, AUDIO_PORT_FLUSH, NULL);
|
||
audio_unit_release_port(adev->deep_unit, aml_port_get_ID(out->deep_inport), AUDIO_PORT_INPUT);
|
||
}
|
||
if (out->stream_type == STREAM_MAIN_INPUT && adev->native_postprocess.effect_in_chmask != AML_DTS_CHANNEL_MASK_2_0) {
|
||
adev->native_postprocess.effect_in_chmask = AML_DTS_CHANNEL_MASK_2_0;
|
||
}
|
||
|
||
if (STREAM_MAIN_INPUT == out->stream_type) {
|
||
aml_restore_output_device_to_mixer_by_id(out->decoder_id);
|
||
}
|
||
|
||
if (stream) {
|
||
aml_audio_free(stream);
|
||
stream = NULL;
|
||
}
|
||
|
||
AM_LOGI("exit!!");
|
||
}
|
||
|
||
static void adev_update_active_outport(struct aml_audio_device *adev, audio_devices_t output_destination) {
|
||
enum OUT_PORT outport = OUTPORT_SPEAKER;
|
||
ALOGI("[%s:%d] output_destination=%#x", __func__, __LINE__, output_destination);
|
||
switch (output_destination) {
|
||
case (AUDIO_DEVICE_OUT_REMOTE_SUBMIX):
|
||
outport = OUTPORT_REMOTE_SUBMIX;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_WIRED_HEADPHONE):
|
||
outport = OUTPORT_HEADPHONE;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_HDMI_ARC):
|
||
outport = OUTPORT_HDMI_ARC;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_SPEAKER):
|
||
case (AML_AUDIO_DEVICE_OUT_EXTERNAL_SPEAKER):
|
||
outport = OUTPORT_SPEAKER;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_HDMI):
|
||
outport = OUTPORT_HDMI;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_SPDIF):
|
||
outport = OUTPORT_SPDIF;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_LINE):
|
||
outport = OUTPORT_AUX_LINE;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET):
|
||
outport = OUTPORT_BT_SCO_HEADSET;
|
||
break;
|
||
case (AUDIO_DEVICE_OUT_USB_HEADSET):
|
||
outport = OUTPORT_USB_HEADSET;
|
||
break;
|
||
default:
|
||
outport = OUTPORT_MAX;
|
||
break;
|
||
}
|
||
|
||
if (adev->active_outport != outport) {
|
||
adev->active_outport_changed = true;
|
||
/* When active_outport switche to ARC, it will disable dap,
|
||
When active_outport switche to speaker, need to restore */
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if (outport == OUTPORT_SPEAKER) {
|
||
set_ms12_full_dap_disable(&adev->ms12, false);
|
||
} else if (outport == OUTPORT_HDMI_ARC) {
|
||
set_ms12_full_dap_disable(&adev->ms12, true);
|
||
}
|
||
}
|
||
if (adev->hwmixer_manager) {
|
||
aml_audio_hwmixer_set_outport(adev, outport);
|
||
}
|
||
}
|
||
adev->active_outport = outport;
|
||
AM_LOGI("active_outport:%d", adev->active_outport);
|
||
}
|
||
|
||
static int aml_audio_output_routing(struct audio_hw_device *dev,
|
||
enum OUT_PORT outport,
|
||
bool user_setting)
|
||
{
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *)dev;
|
||
|
||
if (aml_dev->active_outport != outport) {
|
||
ALOGI("%s: switch from %s to %s", __func__,
|
||
outputPort2Str(aml_dev->active_outport), outputPort2Str(outport));
|
||
|
||
/* switch off the active output */
|
||
switch (aml_dev->active_outport) {
|
||
case OUTPORT_SPEAKER:
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_SPEAKER, false);
|
||
break;
|
||
case OUTPORT_HDMI_ARC:
|
||
set_output_device_avail(aml_dev, AUDIO_DEVICE_OUT_HDMI_ARC, false);
|
||
set_output_device_mute(aml_dev, AUDIO_DEVICE_OUT_HDMI_ARC, true, false);
|
||
break;
|
||
case OUTPORT_HEADPHONE:
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, false);
|
||
break;
|
||
case OUTPORT_A2DP:
|
||
break;
|
||
case OUTPORT_BT_SCO:
|
||
case OUTPORT_BT_SCO_HEADSET:
|
||
AM_LOGI("to do !!!!!");
|
||
break;
|
||
default:
|
||
ALOGW("%s: pre active_outport:%d unsupport", __func__, aml_dev->active_outport);
|
||
break;
|
||
}
|
||
|
||
/* switch on the new output */
|
||
switch (outport) {
|
||
case OUTPORT_SPEAKER:
|
||
if (!aml_dev->speaker_mute) {
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_SPEAKER, true);
|
||
}
|
||
break;
|
||
case OUTPORT_HDMI_ARC:
|
||
set_output_device_avail(aml_dev, AUDIO_DEVICE_OUT_HDMI_ARC, true);
|
||
set_output_device_mute(aml_dev, AUDIO_DEVICE_OUT_HDMI_ARC, false, false);
|
||
break;
|
||
case OUTPORT_HEADPHONE:
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, true);
|
||
break;
|
||
case OUTPORT_A2DP:
|
||
case OUTPORT_BT_SCO:
|
||
case OUTPORT_BT_SCO_HEADSET:
|
||
break;
|
||
default:
|
||
ALOGW("%s: cur outport:%d unsupport", __func__, outport);
|
||
break;
|
||
}
|
||
|
||
aml_dev->active_outport = outport;
|
||
} else if (outport == OUTPORT_SPEAKER && user_setting) {
|
||
/* In this case, user toggle the speaker_mute menu */
|
||
if (aml_dev->speaker_mute) {
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_SPEAKER, false);
|
||
}
|
||
else {
|
||
do_output_device_routing(aml_dev, AUDIO_DEVICE_OUT_SPEAKER, true);
|
||
}
|
||
} else {
|
||
ALOGI("%s: outport %s already exists, do nothing", __func__, outputPort2Str(outport));
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int set_device_output_policy(struct aml_audio_device *adev, bool enable)
|
||
{
|
||
bool is_arc_connected = enable;
|
||
int out_port = adev->active_outport;
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_HDMI_ARC, !enable, false/*no fade*/);
|
||
/*
|
||
* when ARC is connecting, and user switch [Sound Output Device] to "ARC"
|
||
* we need to set out_port as OUTPORT_HDMI_ARC ,
|
||
* the aml_audio_output_routing() will "UNmute" ARC and "mute" speaker.
|
||
*/
|
||
if (is_arc_connected) {
|
||
out_port = OUTPORT_HDMI_ARC;
|
||
}
|
||
|
||
/*
|
||
* when ARC is connecting, and user switch [Sound Output Device] to "speaker"
|
||
* we need to set out_port as OUTPORT_SPEAKER ,
|
||
* the aml_audio_output_routing() will "mute" ARC and "unmute" speaker.
|
||
*/
|
||
if (!is_arc_connected) {
|
||
out_port = OUTPORT_SPEAKER;
|
||
}
|
||
ALOGI("[%s:%d] out_port:%s", __func__, __LINE__, outputPort2Str(out_port));
|
||
aml_audio_output_routing((struct audio_hw_device *)adev, out_port, true);
|
||
return 0;
|
||
}
|
||
|
||
static void adev_set_karaoke_vol (struct aml_audio_device *adev, float vol) {
|
||
pthread_mutex_lock (&adev->active_outputs_lock);
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
struct audio_stream_out *out = (struct audio_stream_out *)aml_out;
|
||
if (aml_out && aml_out->stream_type == STREAM_APP_INPUT) {
|
||
out_set_volume_l(out, vol, vol);
|
||
AM_LOGI("set karaoke vol to %f", vol);
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->active_outputs_lock);
|
||
}
|
||
|
||
static int aml_audio_update_arc_status(struct aml_audio_device *adev, bool enable)
|
||
{
|
||
ALOGI("[%s:%d] set audio hdmi arc status:%d", __func__, __LINE__, enable);
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
|
||
if (enable) {
|
||
restore_hdmi_desc(adev);
|
||
} else {
|
||
memset(hdmi_desc, 0, sizeof(struct aml_arc_hdmi_desc));
|
||
hdmi_desc->pcm_fmt.fmt = AML_HDMI_FORMAT_LPCM;
|
||
hdmi_desc->dts_fmt.fmt = AML_HDMI_FORMAT_DTS;
|
||
hdmi_desc->dtshd_fmt.fmt = AML_HDMI_FORMAT_DTSHD;
|
||
hdmi_desc->dd_fmt.fmt = AML_HDMI_FORMAT_AC3;
|
||
hdmi_desc->ddp_fmt.fmt = AML_HDMI_FORMAT_DDP;
|
||
hdmi_desc->mat_fmt.fmt = AML_HDMI_FORMAT_MAT;
|
||
}
|
||
/*
|
||
* when user switch UI setting, means output device changed,
|
||
* use "arc_hdmi_updated" paramter to notify HDMI ARC have updated status
|
||
* while in config_output(), it detects this change, then re-route output config.
|
||
*/
|
||
set_arc_hdmi_updated(adev, true);
|
||
|
||
/*
|
||
* when arc connect, need umute arc and mute speaker for roku, but yocto trunk don't need;
|
||
* when arc disconnect, need mute arc and unmute speaker for roku, but yocto trunk don't need;
|
||
* which device output is controlled by platform_server for yocto trunk, audiohal don't need control.
|
||
*/
|
||
set_device_output_policy(adev, enable);
|
||
return 0;
|
||
}
|
||
|
||
static void check_usb_card_device(struct str_parms *parms, int device)
|
||
{
|
||
/*usb audio hot plug need delay some time wait alsa file create */
|
||
if ((device & AUDIO_DEVICE_OUT_ALL_USB) || (device & AUDIO_DEVICE_IN_ALL_USB)) {
|
||
int card = 0, alsa_dev = 0, val, retry;
|
||
char fn[256];
|
||
int ret = str_parms_get_int(parms, "card", &val);
|
||
if (ret >= 0) {
|
||
card = val;
|
||
}
|
||
ret = str_parms_get_int(parms, "device", &val);
|
||
if (ret >= 0) {
|
||
alsa_dev = val;
|
||
}
|
||
snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, alsa_dev,
|
||
device & AUDIO_DEVICE_OUT_ALL_USB ? 'p' : 'c');
|
||
for (retry = 0; access(fn, F_OK) < 0 && retry < 10; retry++) {
|
||
usleep (20000);
|
||
}
|
||
if (access(fn, F_OK) < 0 && retry >= 10) {
|
||
ALOGE("usb audio create alsa file time out,need check \n");
|
||
}
|
||
}
|
||
}
|
||
static void set_device_connect_state(struct aml_audio_device *adev, struct str_parms *parms, int device, bool state)
|
||
{
|
||
AM_LOGI("state:%d, dev:%#x, pre_out:%#x, pre_in:%#x", state, device, adev->out_device, adev->in_device);
|
||
if (state) {
|
||
check_usb_card_device(parms, device);
|
||
if (audio_is_output_device(device)) {
|
||
if ((device & AUDIO_DEVICE_OUT_HDMI_ARC) || (device & AUDIO_DEVICE_OUT_HDMI)) {
|
||
set_output_device_avail(adev, device, true);
|
||
clear_arc_cached_edid(adev);
|
||
if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/*when arc is connected, disable dap*/
|
||
set_ms12_full_dap_disable(&adev->ms12, true);
|
||
}
|
||
aml_audio_update_arc_status(adev, true);
|
||
}
|
||
#ifdef BUILD_LINUX
|
||
if ((device & AUDIO_DEVICE_OUT_HDMI) && is_STB(adev)) {
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_SPEAKER, true, false);
|
||
adev->active_outport = OUTPORT_HDMI;
|
||
set_HDMI_reconnected_flag(adev, true);
|
||
}
|
||
#endif
|
||
update_sink_format_after_hotplug(adev);
|
||
} else if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
|
||
adev->a2dp_updated = 1;
|
||
adev->out_device |= device;
|
||
//a2dp_out_open(adev);
|
||
} else if (device & AUDIO_DEVICE_OUT_ALL_USB ||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
|
||
adev->out_device |= device;
|
||
} else if (device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
|
||
adev->out_device |= device;
|
||
}
|
||
}
|
||
} else {
|
||
if (audio_is_output_device(device)) {
|
||
if ((device & AUDIO_DEVICE_OUT_HDMI_ARC) || (device & AUDIO_DEVICE_OUT_HDMI)) {
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
set_output_device_avail(adev, device, false);
|
||
adev->is_hdmi_arc_interact_done = false;
|
||
clear_arc_cached_edid(adev);
|
||
hdmi_desc->pcm_fmt.max_channels = 2;
|
||
hdmi_desc->mat_fmt.MAT_PCM_48kHz_only = false;
|
||
if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/*when arc is connected, disable dap*/
|
||
set_ms12_full_dap_disable(&adev->ms12, false);
|
||
}
|
||
aml_audio_update_arc_status(adev, false);
|
||
}
|
||
#ifdef BUILD_LINUX
|
||
if ((device & AUDIO_DEVICE_OUT_HDMI) && is_STB(adev)) {
|
||
adev->active_outport = OUTPORT_SPEAKER;
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_SPEAKER, false, false);
|
||
set_HDMI_reconnected_flag(adev, true);
|
||
}
|
||
#endif
|
||
update_sink_format_after_hotplug(adev);
|
||
} else if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
|
||
adev->a2dp_updated = 1;
|
||
adev->out_device &= (~device);
|
||
//a2dp_out_close(adev);
|
||
} else if (device & AUDIO_DEVICE_OUT_ALL_USB ||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
|
||
adev->out_device &= (~device);
|
||
} else if (device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
|
||
device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
|
||
adev->out_device &= (~device);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
static int adev_set_master_volume (struct audio_hw_device *dev, float volume);
|
||
static int adev_set_parameters (struct audio_hw_device *dev, const char *kvpairs)
|
||
{
|
||
AM_LOGD("%p, %s", dev, kvpairs);
|
||
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
struct str_parms *parms;
|
||
struct dolby_ms12_desc *ms12 = &(adev->ms12);
|
||
char value[AUDIO_HAL_CHAR_MAX_LEN] = {0};
|
||
int val = 0;
|
||
int ret = 0;
|
||
float val_f = 0.0;
|
||
|
||
AM_LOGI ("kv: %s",kvpairs);
|
||
|
||
parms = str_parms_create_str (kvpairs);
|
||
ret = str_parms_get_str (parms, "screen_state", value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
if (strcmp (value, AUDIO_PARAMETER_VALUE_ON) == 0) {
|
||
adev->low_power = false;
|
||
} else {
|
||
adev->low_power = true;
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_float (parms, "noise_gate_level", &val_f);
|
||
if (ret >= 0) {
|
||
struct component_noise_gate *noise_gate = get_noise_gate_instance(adev);
|
||
if (noise_gate->aml_ng_enable && (noise_gate->aml_ng_level != val_f)) {
|
||
aml_noise_gate_deinit(noise_gate);
|
||
noise_gate->aml_ng_level = val_f;
|
||
aml_noise_gate_init(noise_gate);
|
||
}
|
||
AM_LOGI ("aml_ng_enable=%s, aml_ng_level set to %f", noise_gate->aml_ng_enable ? "enable":"disable", noise_gate->aml_ng_level);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "disable_pcm_mixing", &val);
|
||
if (ret >= 0) {
|
||
adev->disable_pcm_mixing = val;
|
||
AM_LOGI ("ms12 disable_pcm_mixing set to %d", adev->disable_pcm_mixing);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "Audio hdmi-out mute", &val);
|
||
if (ret >= 0) {
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_HDMI, val, false);
|
||
AM_LOGI("set Audio hdmi-out mute status: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "Audio spdif mute", &val);
|
||
if (ret >= 0) {
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_SPDIF, val, false);
|
||
AM_LOGI("set SPDIF mute status: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "AED master volume", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_EQ_MASTER_VOLUME, val);
|
||
AM_LOGI("audio master volume : %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "AED channel volume", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_EQ_LCH_VOLUME, val);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_EQ_RCH_VOLUME, val);
|
||
AM_LOGI("audio channel volume : %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "Master volume", &val);
|
||
if (ret >= 0) {
|
||
if (is_STB(adev)) {
|
||
int dac_vol[2] = {val, val};
|
||
aml_mixer_ctrl_set_array(&adev->alsa_mixer, AML_MIXER_ID_DAC_DIGITAL_VOLUME, &dac_vol, 2);
|
||
} else if (is_SBR(adev)) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AD82128_C30_MASTER_VOLUME, val);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AD82128_C31_MASTER_VOLUME, val);
|
||
} else{
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AMP_MASTER_VOLUME, val);
|
||
}
|
||
AM_LOGI("audio master volume: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
// HDMI cable plug off
|
||
ret = str_parms_get_int(parms, "disconnect", &val);
|
||
if (ret >= 0) {
|
||
|
||
set_device_connect_state(adev, parms, val, false);
|
||
goto exit;
|
||
}
|
||
|
||
// HDMI cable plug in
|
||
ret = str_parms_get_int(parms, "connect", &val);
|
||
if (ret >= 0) {
|
||
set_device_connect_state(adev, parms, val, true);
|
||
if (val & AUDIO_DEVICE_OUT_HDMI_ARC) {
|
||
adev->restart_device_flag = true;
|
||
}
|
||
|
||
goto exit;
|
||
}
|
||
|
||
// HDMI plug in and UI [Sound Output Device] set to "ARC" will recieve HDMI ARC Switch = 1
|
||
// HDMI plug off and UI [Sound Output Device] set to "speaker" will recieve HDMI ARC Switch = 0
|
||
ret = str_parms_get_int(parms, "HDMI ARC Switch", &val);
|
||
if (ret >= 0) {
|
||
aml_audio_update_arc_status(adev, (val != 0));
|
||
if (0 == val && adev->stream_write_data)
|
||
set_ms12_full_dap_disable(&adev->ms12, false);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hal_param_digital_sink_config_dts_capability", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
adev->auto_test_debug_flag = true;
|
||
if (strcmp(value, "dtshd") == 0) {
|
||
adev->sink_configured_dts_capability = AUDIO_FORMAT_DTS_HD;
|
||
//dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1 | DTSX_SINK_SUPPORTS_P2);
|
||
AM_LOGI("sink_configured_dts_capability is dtshd.");
|
||
} else if (strcmp(value, "dts") == 0) {
|
||
adev->sink_configured_dts_capability = AUDIO_FORMAT_DTS;
|
||
//dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_CA);
|
||
AM_LOGI("sink_configured_dts_capability is dts.");
|
||
} else if (strcmp(value, "pcm") == 0) {
|
||
adev->sink_configured_dts_capability = AUDIO_FORMAT_PCM;
|
||
AM_LOGI("sink_configured_dts_capability is pcm.");
|
||
} else {
|
||
AM_LOGI("unknown kvpairs");
|
||
goto exit;
|
||
}
|
||
adev->hdmi_format_updated = 1;
|
||
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_earctx_earc_mode", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_EARC_TX_EARC_MODE, val);
|
||
AM_LOGI("eARC_TX eARC Mode: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_arc_earc_tx_enable", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_ARC_EARC_TX_ENABLE, val);
|
||
AM_LOGI("ARC eARC TX enable: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "spdifin/arcin switch", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIFIN_ARCIN_SWITCH, val);
|
||
AM_LOGI("audio source: %s", val?"ARCIN":"SPDIFIN");
|
||
goto exit;
|
||
}
|
||
|
||
//add for fireos tv for Dolby audio setting
|
||
ret = str_parms_get_int (parms, "hdmi_format", &val);
|
||
if (ret >= 0 ) {
|
||
ret = set_hdmi_format(adev, val);
|
||
if (ret < 0) {
|
||
AM_LOGE("An error occurred during setting hdmi_format!");
|
||
return ret;
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "spdif_format", &val);
|
||
if (ret >= 0 ) {
|
||
adev->spdif_format = val;
|
||
AM_LOGI("S/PDIF format: %d", adev->spdif_format);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hal_param_digital_sink_config_dolby_capability", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
adev->auto_test_debug_flag = true;
|
||
if (strcmp(value, "mat") == 0) {
|
||
adev->sink_configured_dolby_capability = AUDIO_FORMAT_MAT;
|
||
AM_LOGI("sink_configured_dolby_capability is MAT.");
|
||
} else if (strcmp(value, "ddp") == 0) {
|
||
adev->sink_configured_dolby_capability = AUDIO_FORMAT_E_AC3;
|
||
AM_LOGI("sink_configured_dolby_capability is DDP.");
|
||
} else if (strcmp(value, "dd") == 0) {
|
||
adev->sink_configured_dolby_capability = AUDIO_FORMAT_AC3;
|
||
AM_LOGI("sink_configured_dolby_capability is DD.");
|
||
} else if (strcmp(value, "pcm") == 0) {
|
||
adev->sink_configured_dolby_capability = AUDIO_FORMAT_PCM_SUB_16_BIT;
|
||
AM_LOGI("sink_configured_dolby_capability is PCM.");
|
||
} else {
|
||
AM_LOGI("unknown kvpairs");
|
||
goto exit;
|
||
}
|
||
adev->hdmi_format_updated = 1;
|
||
goto exit;
|
||
}
|
||
|
||
//"digital_output_format=pcm"
|
||
//"digital_output_format=dd"
|
||
//"digital_output_format=ddp"
|
||
//"digital_output_format=auto"
|
||
//"digital_output_format=bypass", the same as "disable_pcm_mixing"
|
||
ret = str_parms_get_str(parms, "digital_output_format", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
int hdmi_format = PCM;
|
||
if (strcmp(value, "pcm") == 0) {
|
||
hdmi_format = PCM;
|
||
adev->disable_pcm_mixing = 0;
|
||
AM_LOGI("digital_output_format is PCM");
|
||
} else if (strcmp(value, "ddp") == 0) {
|
||
hdmi_format = DDP;
|
||
hdmi_desc->ddp_fmt.is_support = true;
|
||
hdmi_desc->dd_fmt.is_support = true;
|
||
adev->disable_pcm_mixing = 0;
|
||
AM_LOGI("digital_output_format is DDP");
|
||
} else if (strcmp(value, "dd") == 0) {
|
||
hdmi_format = DD;
|
||
adev->disable_pcm_mixing = 0;
|
||
hdmi_desc->dd_fmt.is_support = true;
|
||
hdmi_desc->ddp_fmt.is_support = false;
|
||
AM_LOGI("digital_output_format is DD");
|
||
} else if (strcmp(value, "auto") == 0) {
|
||
hdmi_format = AUTO;
|
||
adev->disable_pcm_mixing = 0;
|
||
AM_LOGI("digital_output_format is AUTO");
|
||
} else if (strcmp(value, "bypass") == 0) {
|
||
//make sink caps as MAX for roku
|
||
hdmi_format = BYPASS;
|
||
hdmi_desc->ddp_fmt.is_support = true;
|
||
hdmi_desc->dd_fmt.is_support = true;
|
||
hdmi_desc->dts_fmt.is_support = true;
|
||
adev->disable_pcm_mixing = 1;
|
||
/* earc AVR connected, we support MAT output*/
|
||
if ((ATTEND_TYPE_EARC == aml_audio_earctx_get_type(adev)) && (hdmi_desc->mat_fmt.atmos_supported == true)) {
|
||
hdmi_desc->mat_fmt.is_support = true;
|
||
} else {
|
||
hdmi_desc->mat_fmt.is_support = false;
|
||
}
|
||
AM_LOGI("digital_output_format is bypass");
|
||
} else if (strcmp(value, "mat") == 0) {
|
||
hdmi_format = DIGITAL_OUTPUT_MAT;
|
||
hdmi_desc->ddp_fmt.is_support = true;
|
||
hdmi_desc->dd_fmt.is_support = true;
|
||
hdmi_desc->mat_fmt.is_support = true;
|
||
ALOGI("digital_output_format is mat");
|
||
} else if (strcmp(value, "dts") == 0) {
|
||
hdmi_format = DIGITAL_OUTPUT_DTS;
|
||
hdmi_desc->dtshd_fmt.is_support = false;
|
||
hdmi_desc->dts_fmt.is_support = true;
|
||
hdmi_desc->dts_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_CA;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_CA);
|
||
ALOGI("digital_output_format is dts");
|
||
} else if (strcmp(value, "dtshd") == 0) {
|
||
hdmi_format = DIGITAL_OUTPUT_DTSHD;
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA);
|
||
ALOGI("digital_output_format is dtshd");
|
||
} else if (strcmp(value, "dtsx_p1") == 0) {
|
||
hdmi_format = DIGITAL_OUTPUT_DTSX;
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1);
|
||
ALOGI("digital_output_format is dtsx");
|
||
} else if (strcmp(value, "dtsx_p2") == 0) {
|
||
hdmi_format = DIGITAL_OUTPUT_DTSX;
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1 | DTSX_SINK_SUPPORTS_P2;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1 | DTSX_SINK_SUPPORTS_P2);
|
||
ALOGI("digital_output_format is dtsx");
|
||
} else {
|
||
AM_LOGI("unknown kvpairs");
|
||
}
|
||
|
||
if (adev->hdmi_format != hdmi_format)
|
||
adev->hdmi_format_updated = 1;
|
||
adev->hdmi_format = hdmi_format;
|
||
AM_LOGI("HDMI format: %d", adev->hdmi_format);
|
||
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "dtsx_sink_dev_type", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
if (strcmp(value, "dts") == 0) {
|
||
hdmi_desc->dtshd_fmt.is_support = false;
|
||
hdmi_desc->dts_fmt.is_support = true;
|
||
hdmi_desc->dts_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_CA;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_CA);
|
||
AM_LOGI("dtsx_sink_dev_type is dts");
|
||
} else if (strcmp(value, "dtshd") == 0) {
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA);
|
||
AM_LOGI("dtsx_sink_dev_type is dtshd");
|
||
} else if (strcmp(value, "dtsx_p1") == 0) {
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1);
|
||
AM_LOGI("dtsx_sink_dev_type is dtsx");
|
||
} else if (strcmp(value, "dtsx_p2") == 0) {
|
||
hdmi_desc->dtshd_fmt.is_support = true;
|
||
hdmi_desc->dtshd_fmt.dts_vsdb_byte3 = DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1 | DTSX_SINK_SUPPORTS_P2;
|
||
dtsx_set_sink_dev_type(DTSX_SINK_SUPPORTS_MA | DTSX_SINK_SUPPORTS_P1 | DTSX_SINK_SUPPORTS_P2);
|
||
AM_LOGI("dtsx_sink_dev_type is dtsx");
|
||
} else {
|
||
AM_LOGE("unknown kvpairs");
|
||
}
|
||
|
||
goto exit;
|
||
}
|
||
|
||
//add for roku
|
||
ret = str_parms_get_str(parms,"av_noisegate", value, sizeof(value));
|
||
if (ret >= 0 ) {
|
||
struct component_noise_gate *noise_gate = get_noise_gate_instance(adev);
|
||
ret = sscanf(value, "%d %f", &noise_gate->aml_ng_enable, &noise_gate->aml_ng_level);
|
||
AM_LOGI(" AV noise gate:%s, noise gate level:%f db", noise_gate->aml_ng_enable? "enable" : "disable" , noise_gate->aml_ng_level);
|
||
goto exit;
|
||
}
|
||
|
||
//For ott support soundbar project, using Enable Soundbar Mode UI to switch soundbar or OTT mode.
|
||
ret = str_parms_get_int(parms, "hal_param_soundbar_mode", &val);
|
||
if (ret >= 0) {
|
||
bool enable = (val != 0) ? true : false;
|
||
AM_LOGI("enable %d adev->enable_soundbar_mode %d\n", enable, adev->enable_soundbar_mode);
|
||
if (adev->enable_soundbar_mode != enable) {
|
||
adev->enable_soundbar_mode = enable;
|
||
if (adev->enable_soundbar_mode) {
|
||
adev->default_alsa_ch = aml_audio_get_default_alsa_output_ch();
|
||
} else {
|
||
adev->default_alsa_ch = 2;
|
||
}
|
||
if (!enable) {
|
||
/* enable STB and disable SBR mode*/
|
||
adev_update_active_outport(adev, (audio_devices_t)AUDIO_DEVICE_OUT_HDMI);
|
||
set_output_device_mute(adev, (audio_devices_t)AUDIO_DEVICE_OUT_HDMI, false, 0);
|
||
set_output_device_mute(adev, (audio_devices_t)AUDIO_DEVICE_OUT_SPEAKER, true, 0);
|
||
set_output_device_mute(adev, (audio_devices_t)AML_AUDIO_DEVICE_OUT_EXTERNAL_SPEAKER, true, 0);
|
||
convert_stb_to_sbr(adev, false);
|
||
} else {
|
||
/* enable SBR and disable STB mode*/
|
||
adev_update_active_outport(adev, (audio_devices_t)AML_AUDIO_DEVICE_OUT_EXTERNAL_SPEAKER);
|
||
set_output_device_mute(adev, (audio_devices_t)AUDIO_DEVICE_OUT_HDMI, true, 0);
|
||
set_output_device_mute(adev, (audio_devices_t)AUDIO_DEVICE_OUT_SPEAKER, false, 0);
|
||
convert_stb_to_sbr(adev, true);
|
||
}
|
||
aml_audio_pcm_out_close(adev);
|
||
if (ms12->dolby_ms12_init_flags) {
|
||
set_ms12_full_dap_disable(&adev->ms12, !adev->enable_soundbar_mode);
|
||
}
|
||
// only s7d(S905X5M) soundbar use the conflict alsa device.
|
||
// adev->is_alsa_device_conflict = adev->board_config.sbr_spk_ott_hbr_same_tdm;
|
||
AM_LOGI(" enable_soundbar_mode = %d device status at %s\n", enable, adev->enable_soundbar_mode ? "SBR-Speaker" : "PureOTT-HDMI");
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms,"tuner_type", value , sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGI("tuner_type=%s", value);
|
||
char var[PROPERTY_VALUE_MAX] = "ro_vendor_platform_digitaltv_standards";
|
||
aml_audio_property_set(var, value);
|
||
adev->dvb_standards = adev_get_dvb_standards();
|
||
/* If ms12 has been initialized, dvb_standards needs to be re-initialized to take effect */
|
||
if (ms12->dolby_ms12_init_flags) {
|
||
adev_ms12_cleanup(&adev->hw_device);
|
||
adev_ms12_prepare(&adev->hw_device);
|
||
AM_LOGI(" dvb_standards update, need reset ms12");
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "sink_atoms_capability", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
|
||
if (strcmp(value, "true") == 0) {
|
||
hdmi_desc->ddp_fmt.atmos_supported = true;
|
||
AM_LOGI("atoms enable");
|
||
} else {
|
||
hdmi_desc->ddp_fmt.atmos_supported = false;
|
||
AM_LOGI("atmos disable");
|
||
}
|
||
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "hal_param_spdif_output_enable", &val);
|
||
if (ret >= 0 ) {
|
||
AM_LOGI("[%s:%d] set spdif output enable:%d", __func__, __LINE__, val);
|
||
if (val == 0) {
|
||
do_output_device_routing(adev, AUDIO_DEVICE_OUT_SPDIF, false);
|
||
} else {
|
||
do_output_device_routing(adev, AUDIO_DEVICE_OUT_SPDIF, true);
|
||
}
|
||
adev->spdif_enable = (val == 0) ? false : true;
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "audio_type", &val);
|
||
if (ret >= 0) {
|
||
adev->audio_type = val;
|
||
AM_LOGI("audio_type: %d", adev->audio_type);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hdmi_is_passthrough_active", &val);
|
||
if (ret >= 0 ) {
|
||
adev->hdmi_is_pth_active = val;
|
||
AM_LOGI("hdmi_is_passthrough_active: %d", adev->hdmi_is_pth_active);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "capability:routing", &val);
|
||
if (ret >= 0) {
|
||
adev->routing = val;
|
||
AM_LOGI("capability:routing = %#x", adev->routing);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "capability:format", &val);
|
||
if (ret >= 0) {
|
||
adev->output_config.format = val;
|
||
AM_LOGI("capability:format = %#x", adev->output_config.format = val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "capability:channels", &val);
|
||
if (ret >= 0) {
|
||
adev->output_config.channel_mask = val;
|
||
AM_LOGI("capability:channel_mask = %#x", adev->output_config.channel_mask);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "capability:sampling_rate", &val);
|
||
if (ret >= 0) {
|
||
adev->output_config.sample_rate = val;
|
||
AM_LOGI("capability:sample_rate = %d", adev->output_config.sample_rate);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int (parms, "ChannelReverse", &val);
|
||
if (ret >= 0) {
|
||
adev->FactoryChannelReverse = val;
|
||
AM_LOGI("ChannelReverse = %d", adev->FactoryChannelReverse);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "set_ARC_hdmi", value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
set_arc_hdmi(dev, value, AUDIO_HAL_CHAR_MAX_LEN);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "set_ARC_format", value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
set_arc_format(dev, value, AUDIO_HAL_CHAR_MAX_LEN);
|
||
goto exit;
|
||
}
|
||
|
||
ret = set_tv_source_switch_parameters(dev, parms);
|
||
if (ret >= 0) {
|
||
AM_LOGI("get TV source param(kv: %s)", kvpairs);
|
||
goto exit;
|
||
}
|
||
|
||
// HDMI plug in and UI [Sound Output Device] set to "ARC" will recieve speaker_mute = 1
|
||
ret = str_parms_get_int(parms, "speaker_mute", &val);
|
||
if (ret >= 0) {
|
||
if (val) {
|
||
aml_audio_command_delay_mute(adev->aml_command_worker, AUDIO_DEVICE_OUT_SPEAKER, 0);
|
||
} else {
|
||
aml_audio_command_delay_unmute(adev->aml_command_worker, AUDIO_DEVICE_OUT_SPEAKER, 32);
|
||
}
|
||
adev->speaker_mute = val;
|
||
AM_LOGI("set speaker_mute status: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "usb_spk_mute", &val);
|
||
if (ret >= 0) {
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
if (adev->usb_handle) {
|
||
aml_set_external_device_mute(adev->usb_handle, val);
|
||
AM_LOGI("set usb_spk_mute status: %d", val);
|
||
}
|
||
#endif
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "bt_mute", &val);
|
||
if (ret >= 0) {
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
if (adev->bt_handle) {
|
||
aml_set_external_device_mute(adev->bt_handle, val);
|
||
AM_LOGI("set bt_mute status: %d", val);
|
||
}
|
||
#endif
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "headphone_mute", &val);
|
||
if (ret >= 0) {
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, val, false);
|
||
AM_LOGI("set headphone_mute status: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "ARC eARC mute", &val);
|
||
if (ret >= 0) {
|
||
set_output_device_mute(adev, AUDIO_DEVICE_OUT_HDMI_ARC, val, false);
|
||
AM_LOGI("set ARC eARC mute status: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "decoder_mute", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strncmp(value, "true", 4) == 0) {
|
||
if (adev->decoder_mute) {
|
||
AM_LOGI("decoder is muted, no need to set");
|
||
goto exit;
|
||
}
|
||
adev->decoder_mute = true;
|
||
adev_update_decoder_mute_state(dev);
|
||
} else if (strncmp(value, "false", 5) == 0) {
|
||
if (!adev->decoder_mute) {
|
||
AM_LOGI("decoder is unmuted, no need to set");
|
||
goto exit;
|
||
}
|
||
adev->decoder_mute = false;
|
||
adev_update_decoder_mute_state(dev);
|
||
} else {
|
||
AM_LOGE("unsupport decoder_mute value: %s", value);
|
||
}
|
||
AM_LOGI("decoder_mute set to %d", adev->decoder_mute);
|
||
goto exit;
|
||
}
|
||
|
||
// This API can only be used for HDMI,AV and ATV source
|
||
ret = str_parms_get_str(parms, "hdmi_av_mute", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strncmp(value, "true", 4) == 0) {
|
||
adev->patch_mute = true;
|
||
} else if (strncmp(value, "false", 5) == 0) {
|
||
adev->patch_mute = false;
|
||
} else {
|
||
AM_LOGE("unsupport hdmi_av_mute value: %s", value);
|
||
}
|
||
AM_LOGI("hdmi_av_mute set to %d", adev->patch_mute);
|
||
goto exit;
|
||
}
|
||
|
||
// This API can only be used for HDMI,AV,ATV and DTV source
|
||
ret = str_parms_get_str(parms, "parental_control_av_mute", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strncmp(value, "true", 4) == 0) {
|
||
adev->patch_mute = true;
|
||
adev->dtv_mute = true;
|
||
} else if (strncmp(value, "false", 5) == 0) {
|
||
adev->patch_mute = false;
|
||
adev->dtv_mute = false;
|
||
} else {
|
||
AM_LOGE("unsupport parental_control_av_mute value: %s", value);
|
||
}
|
||
AM_LOGI("parental_control_av_mute set to %d", adev->patch_mute);
|
||
goto exit;
|
||
}
|
||
|
||
// used for get first apts for A/V sync
|
||
ret = str_parms_get_str (parms, "first_apts", value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
unsigned int first_apts = atoi (value);
|
||
AM_LOGI("audio set first apts 0x%x", first_apts);
|
||
adev->first_apts = first_apts;
|
||
adev->first_apts_flag = true;
|
||
adev->frame_trigger_thred = 0;
|
||
goto exit;
|
||
}
|
||
|
||
//This API is used to set audio only flag in av source without video
|
||
//This API should be called after av patch has been created
|
||
ret = str_parms_get_int(parms, "av_audio_only", &val);
|
||
if (ret >= 0) {
|
||
struct aml_audio_patch * audio_patch = get_dev_patch_by_source(adev, SRC_LINEIN);
|
||
if (NULL == audio_patch) {
|
||
AM_LOGE("AV audio_patch is NULL, can't set av_audio_only");
|
||
goto exit;
|
||
} else {
|
||
audio_patch->av_audio_only = val;
|
||
AM_LOGI("AV source set av_audio_only to %d", val);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str (parms, "is_netflix", value, sizeof (value) );
|
||
if (ret >= 0) {
|
||
if (strcmp(value, "true") == 0) {
|
||
adev->is_netflix_hide = false;
|
||
adev->is_netflix = 1;
|
||
} else {
|
||
if (adev->is_netflix)
|
||
adev->is_netflix_hide = true;
|
||
adev->is_netflix = 0;
|
||
adev->gap_passthrough_state = GAP_PASSTHROUGH_STATE_IDLE;
|
||
adev->gap_offset = 0;
|
||
}
|
||
AM_LOGI("is_netflix %d(%s) hide:%d", adev->is_netflix, value, adev->is_netflix_hide);
|
||
|
||
set_ms12_encoder_chmod_locking(&(adev->ms12), adev->is_netflix);
|
||
set_ms12_acmod2ch_lock(&(adev->ms12), !adev->is_netflix);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "Effect_enable", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, true);
|
||
if (strncmp(value, "DAP_ON", 6) == 0) {
|
||
adev->effect_ctrl.dap_enable = 1;
|
||
set_ms12_dap_disable_by_UI(&adev->ms12, 0);
|
||
//adev->is_ui_force_dap_disable = false;
|
||
} else if (strncmp(value, "DAP_OFF", 7) == 0) {
|
||
adev->effect_ctrl.dap_enable = 0;
|
||
set_ms12_dap_disable_by_UI(&adev->ms12, 1);
|
||
//adev->is_ui_force_dap_disable = true;
|
||
} else if (strncmp(value, "VX_ON", 5) == 0) {
|
||
#ifdef DTS_VX_V4_ENABLE
|
||
if (0 == VirtualX_setparameter(&adev->native_postprocess, VIRTUALX4_PARAM_ENABLE, 1, EFFECT_CMD_SET_PARAM))
|
||
#else
|
||
if (1 == VirtualX_getparameter(&adev->native_postprocess, DTS_PARAM_VX_ENABLE_I32)
|
||
&& 0 == VirtualX_getparameter(&adev->native_postprocess, DTS_PARAM_TSX_PROCESS_DISCARD_I32) )
|
||
#endif
|
||
{
|
||
adev->effect_ctrl.vx_enable = true;
|
||
#ifdef DTS_VX_V4_ENABLE
|
||
/*
|
||
* 1. VIRTUALX4_PARAM_ENABLE: UI toggle for feature enablement
|
||
* 2. PARAM_VX_ENABLE_I32: dts vx4 module parameter, value set in ini file
|
||
* 3. dts x multichannel output: configurable only when both are enabled
|
||
*/
|
||
if (1 == VirtualX_getparameter(&adev->native_postprocess, PARAM_VX_ENABLE_I32)) {
|
||
adev->effect_ctrl.virtualXlib1_state = 1;
|
||
dca_set_out_ch_internal(0);//If vx4 enable successful,config dts x output auto
|
||
}
|
||
#else
|
||
dca_set_out_ch_internal(0);//If vx2 is enabled,config output auto
|
||
#endif
|
||
} else {
|
||
adev->effect_ctrl.vx_enable = false;
|
||
dca_set_out_ch_internal(2);//If vx4 enable failed or vx2 is disable, set config output stero
|
||
}
|
||
} else if (strncmp(value, "VX_OFF", 6) == 0) {
|
||
adev->effect_ctrl.vx_enable = false;
|
||
#ifdef DTS_VX_V4_ENABLE
|
||
VirtualX_setparameter(&adev->native_postprocess,VIRTUALX4_PARAM_ENABLE,0,EFFECT_CMD_SET_PARAM);
|
||
#endif
|
||
dca_set_out_ch_internal(2);//set vx4 or vx2 disabled,set config output stero
|
||
}
|
||
if (adev->effect_ctrl.dap_enable && adev->effect_ctrl.vx_enable) {
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_AUTO;
|
||
}
|
||
else if (adev->effect_ctrl.dap_enable && !adev->effect_ctrl.vx_enable) {
|
||
if (is_TV(adev) && MS12_CONFIG_Y != adev->dolby_ms12_audio_config) {
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_DAP;
|
||
} else {
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_OFF;
|
||
}
|
||
}
|
||
else if (!adev->effect_ctrl.dap_enable && adev->effect_ctrl.vx_enable) {
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_VX;
|
||
}
|
||
else if (!adev->effect_ctrl.dap_enable && !adev->effect_ctrl.vx_enable) {
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_OFF;
|
||
}
|
||
|
||
adev->native_postprocess.effect_ctrl.effect_mode = adev->effect_ctrl.effect_mode;
|
||
aml_audio_sleep(64000);
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, false);
|
||
ALOGD("set dolby DAP enable %d DTS VX enable %d effect_mode %d ms12_config %d is_TV %d", adev->effect_ctrl.dap_enable,
|
||
adev->effect_ctrl.vx_enable, adev->effect_ctrl.effect_mode, adev->dolby_ms12_audio_config, is_TV(adev));
|
||
goto exit;
|
||
}
|
||
|
||
/*use dolby_lib_type_last to check ms12 type, because durig playing DTS file,
|
||
this type will be changed to dcv*/
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type_last) {
|
||
ret = str_parms_get_int(parms, "continuous_audio_mode", &val);
|
||
if (ret >= 0) {
|
||
int disable_continuous = !val;
|
||
// if exit netflix, we need disable atmos lock
|
||
if (disable_continuous) {
|
||
adev->atoms_lock_flag = false;
|
||
set_ms12_atmos_lock(&(adev->ms12), adev->atoms_lock_flag);
|
||
AM_LOGI("exit netflix, set atmos lock as 0");
|
||
}
|
||
{
|
||
bool acmod2ch_lock = !val;
|
||
//when in netflix, we should always keep ddp5.1, exit netflix we can output ddp2ch
|
||
set_ms12_encoder_chmod_locking(&(adev->ms12), !acmod2ch_lock);
|
||
set_ms12_acmod2ch_lock(&(adev->ms12), acmod2ch_lock);
|
||
}
|
||
|
||
AM_LOGI("ignore the continuous_audio_mode!");
|
||
adev->is_netflix = val;
|
||
goto exit;
|
||
/*Dead Code, didn't use now*/
|
||
/*AM_LOGI("continuous_audio_mode set to %d", val);
|
||
char buf[PROPERTY_VALUE_MAX] = {0};
|
||
char *str = aml_audio_property_get_str(DISABLE_CONTINUOUS_OUTPUT, buf, NULL);
|
||
if (str != NULL) {
|
||
sscanf(buf, "%d", &disable_continuous);
|
||
AM_LOGI("%s[%s] disable_continuous %d", DISABLE_CONTINUOUS_OUTPUT, buf, disable_continuous);
|
||
}
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (continuous_mode(adev) && disable_continuous) {
|
||
// If the Netflix application is terminated, your platform must disable Atmos locking.
|
||
// For more information, see When to enable/disable Atmos lock.
|
||
// The following Netflix application state transition scenarios apply (state definitions described in Always Ready):
|
||
// Running->Not Running
|
||
// Not Running->Running
|
||
// Hidden->Visible
|
||
// Visible->Hidden
|
||
// Application crash / abnormal shutdown
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
adev->atoms_lock_flag = 0;
|
||
dolby_ms12_set_atmos_lock_flag(adev->atoms_lock_flag);
|
||
}
|
||
|
||
if (dolby_stream_active(adev) || hwsync_lpcm_active(adev)) {
|
||
AM_LOGI("later release MS12 when direct stream active");
|
||
adev->need_remove_conti_mode = true;
|
||
} else {
|
||
AM_LOGI("Dolby MS12 is at continuous output mode, here go to end it!");
|
||
bool set_ms12_non_continuous = true;
|
||
get_dolby_ms12_cleanup(&adev->ms12, set_ms12_non_continuous);
|
||
//ALOGI("[%s:%d] get_dolby_ms12_cleanup\n", __FUNCTION__, __LINE__);
|
||
adev->exiting_ms12 = 1;
|
||
clock_gettime(CLOCK_MONOTONIC, &adev->ms12_exiting_start);
|
||
if (adev->active_outputs[STREAM_PCM_NORMAL] != NULL)
|
||
usecase_change_validate_l(adev->active_outputs[STREAM_PCM_NORMAL], true);
|
||
//continuous_stream_do_standby(adev);
|
||
}
|
||
} else {
|
||
if ((!disable_continuous) && !continuous_mode(adev)) {
|
||
adev->mix_init_flag = false;
|
||
adev->continuous_audio_mode = 1;
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;*/
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hdmi_dolby_atmos_lock", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGI("hdmi_dolby_atmos_lock set to %d", val);
|
||
adev->atoms_lock_flag = val ? true : false;
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
// Note: some guide from www.netflix.com
|
||
// In the Netflix application, enable/disable Atmos locking
|
||
// when you receive the signal from the Netflix application.
|
||
pthread_mutex_lock(&adev->lock);
|
||
// enable/disable atoms lock
|
||
set_ms12_atmos_lock(&(adev->ms12), adev->atoms_lock_flag);
|
||
AM_LOGI("set adev->atoms_lock_flag = %d", adev->atoms_lock_flag);
|
||
pthread_mutex_unlock(&adev->lock);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
//for the local playback, IEC61937 format!
|
||
//temp to disable the Dolby MS12 continuous
|
||
//if local playback on Always continuous is completed,
|
||
//we should remove this function!
|
||
ret = str_parms_get_int(parms, "is_ms12_continuous", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGI("is_ms12_continuous set to %d", val);
|
||
goto exit;
|
||
}
|
||
/*after enable MS12 continuous mode, the audio delay is big, we
|
||
need use this API to compensate some delay to video*/
|
||
ret = str_parms_get_int(parms, "compensate_video_enable", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGI("compensate_video_enable set to %d", val);
|
||
adev->compensate_video_enable = val;
|
||
//aml_audio_compensate_video_delay(val);
|
||
goto exit;
|
||
}
|
||
|
||
/*enable force ddp output for ms12 v2*/
|
||
ret = str_parms_get_int(parms, "hal_param_force_ddp", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGI("hal_param_force_ddp set to %d", val);
|
||
if (adev->ms12_force_ddp_out != val) {
|
||
adev->ms12_force_ddp_out = val;
|
||
update_sink_format_after_hotplug(adev);
|
||
}
|
||
goto exit;
|
||
}
|
||
} else if (eDolbyDcvLib == adev->dolby_lib_type_last) {
|
||
ret = str_parms_get_int(parms, "continuous_audio_mode", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGI("ignore the continuous_audio_mode!");
|
||
adev->is_netflix = val;
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "SOURCE_GAIN", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
float fAtvGainDb = 0, fDtvGainDb = 0, fHdmiGainDb = 0, fAvGainDb = 0, fMediaGainDb = 0, fArcGainDb = 0;
|
||
sscanf(value,"%f %f %f %f %f %f", &fAtvGainDb, &fDtvGainDb, &fHdmiGainDb, &fAvGainDb, &fMediaGainDb, &fArcGainDb);
|
||
AM_LOGI("audio source gain: atv:%f, dtv:%f, hdmiin:%f, av:%f, media:%f, arcin:%f",
|
||
fAtvGainDb, fDtvGainDb, fHdmiGainDb, fAvGainDb, fMediaGainDb, fArcGainDb);
|
||
set_inport_gain(adev, INPORT_ATV, DbToAmpl(fAtvGainDb));
|
||
set_inport_gain(adev, INPORT_TUNER, DbToAmpl(fDtvGainDb));
|
||
set_inport_gain(adev, INPORT_HDMIIN, DbToAmpl(fHdmiGainDb));
|
||
set_inport_gain(adev, INPORT_LINEIN, DbToAmpl(fAvGainDb));
|
||
set_inport_gain(adev, INPORT_MEDIA, DbToAmpl(fMediaGainDb));
|
||
set_inport_gain(adev, INPORT_ARCIN, DbToAmpl(fArcGainDb));
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "SOURCE_MUTE", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value,"%d", &adev->source_mute);
|
||
AM_LOGI("set audio source mute: %s", adev->source_mute?"mute":"unmute");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "POST_GAIN", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value,"%f %f %f", &adev->eq_data.p_gain.speaker, &adev->eq_data.p_gain.spdif_arc,
|
||
&adev->eq_data.p_gain.headphone);
|
||
AM_LOGI("audio device gain: speaker:%f, spdif_arc:%f, headphone:%f",
|
||
adev->eq_data.p_gain.speaker, adev->eq_data.p_gain.spdif_arc,
|
||
adev->eq_data.p_gain.headphone);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms, "port_delay", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *port_name;
|
||
int port_delay = 0;
|
||
char *delimiter = ",";
|
||
char *remaining_string = value;
|
||
port_name = strtok_r(value, delimiter, &remaining_string);
|
||
port_delay = (atoi)(strtok_r(NULL, delimiter, &remaining_string));
|
||
aml_audio_set_port_delay(port_name, port_delay);
|
||
goto exit;
|
||
}
|
||
#ifdef USE_EQ_DRC
|
||
ret = str_parms_get_str(parms,"EQ_PARAM", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strcmp(value, adev->eq_param) != 0) {
|
||
char type = 'P';
|
||
unsigned int Fc = 0;
|
||
double G = 0;
|
||
double Q = 0;
|
||
unsigned int eq_type = 0;
|
||
char *remaining_string = value;
|
||
char *token = NULL;
|
||
unsigned int eq_band_id = 0;
|
||
|
||
memset(adev->eq_param, 0, sizeof(adev->eq_param));
|
||
strncpy(adev->eq_param, value, sizeof(adev->eq_param));
|
||
adev->eq_param[sizeof(adev->eq_param) - 1] = '\0';
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, true);
|
||
set_dac_digital_volume_mute(&adev->alsa_mixer, true);
|
||
aml_audio_sleep(32*1000);
|
||
token = strtok_r(value, ",", &remaining_string);
|
||
while (token != NULL) {
|
||
ret = sscanf(token, "%c:%d:%lf:%lf", &type, &Fc, &G, &Q);
|
||
if (ret != 4) {
|
||
break;
|
||
} else {
|
||
token = strtok_r(NULL, ",", &remaining_string);
|
||
if (type == 'P') {
|
||
eq_type = FILTER_TYPE_BANDPASS;
|
||
} else {
|
||
//other eq_type
|
||
}
|
||
if (((adev->eq_hw_band_data[eq_band_id].eq_type != eq_type) ||
|
||
(adev->eq_hw_band_data[eq_band_id].Fc != Fc) ||
|
||
(adev->eq_hw_band_data[eq_band_id].G != G) ||
|
||
(adev->eq_hw_band_data[eq_band_id].Q != Q)) &&
|
||
(eq_band_id < EQ_HW_BAND_MAX_NUM)) {// AED_EQ_HPF_BAND_NUM only uses for HPF
|
||
adev->eq_hw_band_data[eq_band_id].eq_type = eq_type;
|
||
adev->eq_hw_band_data[eq_band_id].Fc = Fc;
|
||
adev->eq_hw_band_data[eq_band_id].G = G;
|
||
adev->eq_hw_band_data[eq_band_id].Q = Q;
|
||
ALOGI("audio AED EQ PARAM, band num:%d, type:%c, Fc:%d, G:%lf, Q:%lf", eq_band_id, type, Fc, G, Q);
|
||
setpar_eq(G, Q, Fc, eq_type, eq_band_id);
|
||
}
|
||
eq_band_id++;
|
||
}
|
||
}
|
||
aml_audio_sleep(32*1000);
|
||
set_dac_digital_volume_mute(&adev->alsa_mixer, false);
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, false);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
/* cmd format: hpf=1:200 */
|
||
ret = str_parms_get_str(parms,"hpf", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int hpf_enable = 0;
|
||
unsigned int Fc = 0;
|
||
sscanf(value, "%d:%d", &hpf_enable, &Fc);
|
||
if (adev->hpf_enable != hpf_enable) {
|
||
double G = 0;
|
||
double Q = 1;
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, true);
|
||
aml_audio_sleep(32*1000);
|
||
ALOGI("audio AED EQ HPF, band num:%d, frequency:%d Hz, hpf enable:%d\n", EQ_HW_BAND_MAX_NUM, Fc, hpf_enable);
|
||
if (hpf_enable == 1) {
|
||
setpar_eq(G, Q, Fc, FILTER_TYPE_HPF, EQ_HW_BAND_MAX_NUM);
|
||
} else {
|
||
setpar_eq(G, Q, Fc, FILTER_TYPE_BANDPASS, EQ_HW_BAND_MAX_NUM);
|
||
}
|
||
aml_audio_sleep(32*1000);
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, false);
|
||
adev->hpf_enable = hpf_enable;
|
||
}
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms,"mb_drc",value,sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value, "%u %u %u %u %f %f",&adev->Drc_data.band_id,&adev->Drc_data.attrack_time,&adev->Drc_data.release_time,
|
||
&adev->Drc_data.estimate_time,&adev->Drc_data.K,&adev->Drc_data.threshold);
|
||
setmb_drc(adev->Drc_data.band_id,adev->Drc_data.attrack_time,adev->Drc_data.release_time,adev->Drc_data.estimate_time,
|
||
adev->Drc_data.K,adev->Drc_data.threshold);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms,"fb_drc",value,sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value, "%u %u %u %u %f %f %f",&adev->Drc_data.band_id,&adev->Drc_data.attrack_time,&adev->Drc_data.release_time,
|
||
&adev->Drc_data.estimate_time,&adev->Drc_data.K,&adev->Drc_data.threshold,&adev->Drc_data.offset);
|
||
setfb_drc(adev->Drc_data.band_id,adev->Drc_data.attrack_time,adev->Drc_data.release_time,
|
||
adev->Drc_data.estimate_time, adev->Drc_data.K, adev->Drc_data.threshold, adev->Drc_data.offset);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms,"csfilter_drc",value,sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value, "%u %u",&adev->Drc_data.band_id,&adev->Drc_data.fc);
|
||
setcsfilter_drc(adev->Drc_data.band_id,adev->Drc_data.fc);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "eq_enable", &val);
|
||
if (ret >= 0) {
|
||
if (val != adev->eq_enable) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AED_EQ_ENABLE, val);
|
||
adev->eq_enable = val;
|
||
AM_LOGI("audio AED EQ enable: %s", val?"enable":"disable");
|
||
}
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "multi_drc_enable", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AED_MULTI_DRC_ENABLE, val);
|
||
AM_LOGI("audio AED Multi-band DRC enable: %s", val?"enable":"disable");
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "fullband_drc_enable", &val);
|
||
if (ret >= 0) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AED_FULL_DRC_ENABLE, val);
|
||
AM_LOGI("audio AED Full-band DRC enable: %s", val?"enable":"disable");
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
/*AUDIO AI*/
|
||
if (adev->aml_ai_audio_type != eAmlAiAudioUnsupported) {
|
||
ret = str_parms_get_str(parms, "aiaq_enable", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int enable = 0;
|
||
sscanf(value, "%d", &enable);;
|
||
enable = enable ? 1 : 0;
|
||
if (false == aml_ai_audio_query_module(AML_AI_TYPE_AIAQ) && enable == 1) {
|
||
AmlAiConfig ai_config;
|
||
ai_config.samplerate = 48000;
|
||
ai_config.channels = 8;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/* For ms12 callback, the audio format must 8 or 10 channel, float */
|
||
ai_config.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
} else {
|
||
ai_config.format = (16 == adev->audio_process_bitwidth)? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
aml_ai_audio_open_module(ai_config, ai_config.channels, AML_AI_TYPE_AIAQ, &adev->alsa_mixer);
|
||
}
|
||
ALOGI("AI_AQ enable=%d",enable);
|
||
aml_ai_audio_set_enable(AML_AI_TYPE_AIAQ, enable);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "audio_enhancement_enable", &val);
|
||
if (ret >= 0) {
|
||
ALOGI("audio_enhancement: %s\n", (val == 1) ? "enable":"disable");
|
||
if (false == aml_ai_audio_query_module(AML_AI_TYPE_ENHANCEMENT) && val == 1) {
|
||
AmlAiConfig ai_config;
|
||
ai_config.samplerate = 48000;
|
||
ai_config.channels = 8;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/* For ms12 callback, the audio format must 8 or 10 channel, float */
|
||
ai_config.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
} else {
|
||
ai_config.format = (16 == adev->audio_process_bitwidth)? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
aml_ai_audio_open_module(ai_config, ai_config.channels, AML_AI_TYPE_ENHANCEMENT, NULL);
|
||
}
|
||
aml_ai_audio_set_enable(AML_AI_TYPE_ENHANCEMENT, val);
|
||
goto exit;
|
||
}
|
||
|
||
/* audio enhancement control */
|
||
ret = str_parms_get_int(parms, "audio_enhancement_gain", &val);
|
||
if (ret >= 0) {
|
||
if (val < MIN_AUDIO_ENHANCEMENT_GAIN) {
|
||
val = MIN_AUDIO_ENHANCEMENT_GAIN;
|
||
} else if (val > MAX_AUDIO_ENHANCEMENT_GAIN) {
|
||
val = MAX_AUDIO_ENHANCEMENT_GAIN;
|
||
}
|
||
AmlAiValues values;
|
||
values.value = val;
|
||
if (aml_ai_audio_get_enable(AML_AI_TYPE_ENHANCEMENT)) {
|
||
aml_ai_audio_set_param(AML_AI_TYPE_ENHANCEMENT, ENHANCEMENT_GAIN, values);
|
||
ALOGI("audio_enhancement level (low/middle/high): %d", val);
|
||
} else {
|
||
ALOGI("audio_enhancement_gain in disable state");
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "audio_pcm_record_enable", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int record_enable = 0;
|
||
int delay_in_ms = 0;
|
||
sscanf(value,"%d,%d", &record_enable, &delay_in_ms);
|
||
if (false == aml_ai_audio_query_module(AML_AI_TYPE_ALOOP) && record_enable == 1) {
|
||
AmlAiConfig ai_config;
|
||
ai_config.samplerate = 48000;
|
||
ai_config.channels = 8;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/* For ms12 callback, the audio format must 8 or 10 channel, float */
|
||
ai_config.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
} else {
|
||
ai_config.format = (16 == adev->audio_process_bitwidth)? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
aml_ai_audio_open_module(ai_config, ai_config.channels, AML_AI_TYPE_ALOOP, NULL);
|
||
}
|
||
if (true == aml_ai_audio_query_module(AML_AI_TYPE_ALOOP)) {
|
||
aml_ai_audio_set_enable(AML_AI_TYPE_ALOOP, record_enable);
|
||
delay_in_ms = (delay_in_ms > MAX_DELAY_TIME) ? MAX_DELAY_TIME : delay_in_ms;
|
||
delay_in_ms = (record_enable == 0) ? 0 : delay_in_ms;
|
||
AmlAiValues values;
|
||
values.value = delay_in_ms;
|
||
aml_ai_audio_set_param(AML_AI_TYPE_ALOOP, ALOOP_RECORD_DELAY, values);
|
||
ALOGD("audio_pcm_record_enable: %s, audio delay %dms\n", (record_enable == 1) ? "enable":"disable", delay_in_ms);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "audio_vocal_isolate_enable", &val);
|
||
if (ret >= 0) {
|
||
ALOGI("audio_vocal_isolate_enable: %s\n", (val == 1) ? "enable":"disable");
|
||
if (false == aml_ai_audio_query_module(AML_AI_TYPE_VOCAL_ISOLATE) && val == 1) {
|
||
AmlAiConfig ai_config;
|
||
ai_config.samplerate = 48000;
|
||
ai_config.channels = 8;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/* For ms12 callback, the audio format must 8 or 10 channel, float */
|
||
ai_config.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
} else {
|
||
ai_config.format = (16 == adev->audio_process_bitwidth)? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
aml_ai_audio_open_module(ai_config, ai_config.channels, AML_AI_TYPE_VOCAL_ISOLATE, NULL);
|
||
}
|
||
if (true == aml_ai_audio_query_module(AML_AI_TYPE_VOCAL_ISOLATE)) {
|
||
aml_ai_audio_set_enable(AML_AI_TYPE_VOCAL_ISOLATE, val);
|
||
adev->ai_external_isolate_latency = (val == 1) ? 150 : 0;
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "audio_vocal_gain", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
float vocal_gain = 0;
|
||
sscanf(value,"%f", &vocal_gain);
|
||
ALOGI("[%s] set vocal gain = %f", __func__, vocal_gain);
|
||
AmlAiValues values;
|
||
values.value_f = vocal_gain;
|
||
if (aml_ai_audio_get_enable(AML_AI_TYPE_VOCAL_ISOLATE)) {
|
||
aml_ai_audio_set_param(AML_AI_TYPE_VOCAL_ISOLATE, VOCAL_ISOLATE_GAIN, values);
|
||
} else {
|
||
ALOGI("audio_vocal_isolate in disable state");
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_music_gain", &val);
|
||
if (ret >= 0) {
|
||
ALOGV("music gain: %ddB\n", val/100);
|
||
AmlAiValues values;
|
||
values.value = val;
|
||
aml_ai_audio_set_param(AML_AI_TYPE_VOCAL_ISOLATE, VOCAL_ISOLATE_VOLUME_GAIN, values);
|
||
aml_ai_audio_set_param(AML_AI_TYPE_LOUDNESS, LOUDNESS_MUSIC_VOLUME, values);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "audio_loudness_enable", &val);
|
||
if (ret >= 0) {
|
||
ALOGI("audio_loudness_enable: %s\n", (val == 1) ? "enable":"disable");
|
||
if (false == aml_ai_audio_query_module(AML_AI_TYPE_LOUDNESS) && val == 1) {
|
||
AmlAiConfig ai_config;
|
||
ai_config.samplerate = 48000;
|
||
ai_config.channels = 8;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/* For ms12 callback, the audio format must 8 or 10 channel, float */
|
||
ai_config.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
} else {
|
||
ai_config.format = (16 == adev->audio_process_bitwidth)? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_32_BIT;
|
||
}
|
||
aml_ai_audio_open_module(ai_config, ai_config.channels, AML_AI_TYPE_LOUDNESS, NULL);
|
||
}
|
||
if (true == aml_ai_audio_query_module(AML_AI_TYPE_LOUDNESS)) {
|
||
aml_ai_audio_set_enable(AML_AI_TYPE_LOUDNESS, val);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "audio_loudness_gain", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
float loudness_gain = 0;
|
||
sscanf(value,"%f", &loudness_gain);
|
||
ALOGD("[%s] set loudness gain = %f", __func__, loudness_gain);
|
||
AmlAiValues values;
|
||
values.value = loudness_gain;
|
||
if (aml_ai_audio_get_enable(AML_AI_TYPE_LOUDNESS)) {
|
||
aml_ai_audio_set_param(AML_AI_TYPE_LOUDNESS, LOUDNESS_GAIN, values);
|
||
} else {
|
||
ALOGI("audio_loudness in disable state");
|
||
}
|
||
goto exit;
|
||
}
|
||
}
|
||
ret = str_parms_get_str(parms, "DTS_POST_GAIN", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value,"%f", &adev->dts_post_gain);
|
||
AM_LOGI("audio dts post gain: %f",adev->dts_post_gain);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "EQ_MODE", &val);
|
||
#ifdef USE_EQ_DRC
|
||
if (ret >= 0) {
|
||
if (eq_mode_set(&adev->eq_data, val) < 0)
|
||
AM_LOGE("eq_mode_set failed");
|
||
goto exit;
|
||
}
|
||
#endif
|
||
#ifdef USE_DTV
|
||
/* dvb cmd deal with start */
|
||
{
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_patch_cmd", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_CONTROL, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_ad_mix_enable", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_ENABLE ,val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_media_sync_id", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_MEDIA_SYNC_ID ,val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dual_decoder_advol_level", &val);
|
||
if (ret >= 0) {
|
||
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_VOL_LEVEL, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_float(parms, "hal_param_dtv_ad_gain_level", &val_f);
|
||
if (ret >= 0) {
|
||
if (val_f < -96.0) {
|
||
val_f = -96.0;
|
||
} else if (val_f > 10.0) {
|
||
val_f = 10.0;
|
||
}
|
||
int advol_level = DbToAmpl(val_f) * 100;
|
||
AM_LOGI("ad gain level set to %f db, %d vol\n", val_f, advol_level);
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_VOL_LEVEL, advol_level);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dual_dec_mix_level", &val);
|
||
if (ret >= 0) {
|
||
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_MIX_LEVEL, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_security_mem_level", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_SECURITY_MEM_LEVEL, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_synctype", &val);
|
||
if (ret >= 0) {
|
||
adev->synctype = val;
|
||
AM_LOGI("adev->synctype set to %d", val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_audio_output_mode", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_OUTPUT_MODE, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_demux_id", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_DEMUX_INFO, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_pid", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_PID, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_fmt", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_FMT, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_audio_fmt", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_FMT, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_audio_id", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_PID, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_sub_audio_fmt", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_FMT, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_sub_audio_pid", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_AD_PID, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_has_dtv_video", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_HAS_VIDEO, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_tv_mute", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_MUTE, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_media_presentation_id", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_MEDIA_PRESENTATION_ID, val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_media_first_lang", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_MEDIA_FIRST_LANG, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_media_second_lang", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_MEDIA_SECOND_LANG, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_audio_volume", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_VOLUME, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "hal_param_dtv_decoder_id", &val);
|
||
if (ret >= 0) {
|
||
dtv_patch_handle_event(dev, AUDIO_DTV_PATCH_CMD_SET_DECODER_ID, val);
|
||
goto exit;
|
||
}
|
||
}
|
||
#endif
|
||
/* dvb cmd deal with end */
|
||
ret = str_parms_get_str(parms, "sound_track", value, sizeof(value));
|
||
if (ret > 0) {
|
||
int mode = atoi(value);
|
||
AM_LOGI("sound_track mode %d",mode);
|
||
adev->sound_track_mode = mode;
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "has_video", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strncmp(value, "true", 4) == 0) {
|
||
adev->is_has_video = true;
|
||
} else if (strncmp(value, "false", 5) == 0) {
|
||
adev->is_has_video = false;
|
||
} else {
|
||
adev->is_has_video = true;
|
||
AM_LOGE("unsupport value %s choose is_has_video(default) %d", value, adev->is_has_video);
|
||
}
|
||
AM_LOGI("is_has_video set to %d", adev->is_has_video);
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "reconfigA2dp", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("A2DP reconfigA2dp out_device=%x", adev->out_device);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hfp_set_sampling_rate", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: hfp_set_sampling_rate. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hfp_volume", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: hfp_volume. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "bt_headset_name", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HA: bt_headset_name. Abort function and return 0.");
|
||
//goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "rotation", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: rotation. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "bt_headset_nrec", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: bt_headset_nrec. Abort function and return 0.");
|
||
//goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "bt_wbs", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGI("Amlogic_HAL: bt_wbs=%s.", value);
|
||
if (strncmp(value, "on", 2) == 0)
|
||
adev->bt_wbs = true;
|
||
else
|
||
adev->bt_wbs = false;
|
||
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hfp_enable", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: hfp_enable. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "HACSetting", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: HACSetting. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "tty_mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGE ("Amlogic_HAL: tty_mode. Abort function and return 0.");
|
||
goto exit;
|
||
}
|
||
|
||
|
||
ret = str_parms_get_str(parms, "show-meminfo", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
unsigned int level = (unsigned int)atoi(value);
|
||
AM_LOGE ("Amlogic_HAL: ShowMem info level:%d.", level);
|
||
aml_audio_debug_malloc_showinfo(level);
|
||
goto exit;
|
||
}
|
||
|
||
#ifndef NO_AUDIO_CAP
|
||
/*add interface to audio capture*/
|
||
ret = str_parms_get_str(parms, "cap_buffer", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int size = 0;
|
||
char * remaining_string = value;
|
||
char *name = strtok_r(value, ",", &remaining_string);
|
||
AM_LOGI("cap_buffer %s", value);
|
||
#ifndef NO_AUDIO_CAP
|
||
if (name) {
|
||
size = atoi(name + strlen(name) + 1);
|
||
if (size > 0) {
|
||
pthread_mutex_lock(&adev->cap_handle_lock);
|
||
if (adev->capture_handle) {
|
||
aml_audio_capture_out_close(adev->capture_handle);
|
||
adev->capture_handle = NULL;
|
||
}
|
||
aml_audio_capture_out_open(&adev->capture_handle, name, size);
|
||
AM_LOGI("IpcBuffer_created %p (%s, %d)", adev->capture_handle, name, size);
|
||
pthread_mutex_unlock(&adev->cap_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
} else if (size == 0) {
|
||
pthread_mutex_lock(&adev->cap_handle_lock);
|
||
if (adev->capture_handle) {
|
||
aml_audio_capture_out_close(adev->capture_handle);
|
||
adev->capture_handle = NULL;
|
||
}
|
||
pthread_mutex_unlock(&adev->cap_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
ret = -EINVAL;
|
||
#endif
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "cap_delay", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
adev->cap_delay = atoi(value);
|
||
AM_LOGI("cap_delay=%d",adev->cap_delay);
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
/*
|
||
* add interface to bluetooth and usb spk
|
||
* hal_param set cmd=name,enable
|
||
* hal_param set device=plughw:Device,1
|
||
* hal_param set device=bluealsa:DEV=BF:FE:4D:6E:B0:92,1
|
||
*/
|
||
ret = str_parms_get_str(parms, "device", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int enable = 0;
|
||
char * remaining_string = value;
|
||
char *name = strtok_r(value, ",", &remaining_string);
|
||
AM_LOGI("external device %s", value);
|
||
if (strncmp(name, "plughw", 6) == 0) {
|
||
enable = atoi(name + strlen(name) + 1);
|
||
if (enable > 0) {
|
||
pthread_mutex_lock(&adev->external_handle_lock);
|
||
aml_external_device_open(USB_TYPE, name);
|
||
pthread_mutex_unlock(&adev->external_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
} else if (enable == 0) {
|
||
pthread_mutex_lock(&adev->external_handle_lock);
|
||
aml_external_device_close(adev->usb_handle);
|
||
adev->usb_handle = NULL;
|
||
pthread_mutex_unlock(&adev->external_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
} else if (strncmp(name, "bluealsa", 8) == 0) {
|
||
enable = atoi(name + strlen(name) + 1);
|
||
if (enable > 0) {
|
||
pthread_mutex_lock(&adev->external_handle_lock);
|
||
aml_external_device_open(BT_TYPE, name);
|
||
pthread_mutex_unlock(&adev->external_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
} else if (enable == 0) {
|
||
pthread_mutex_lock(&adev->external_handle_lock);
|
||
aml_external_device_close(adev->bt_handle);
|
||
adev->bt_handle = NULL;
|
||
pthread_mutex_unlock(&adev->external_handle_lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
ret = str_parms_get_str(parms, "hal_param_dialogue_enhancement", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
switch (atoi(value)) {
|
||
case DIALOGUE_ENHANCEMENT_OFF:
|
||
adev->ms12.ac4_de = 0;
|
||
adev->ms12.dap_de_enable = 0;
|
||
adev->ms12.dap_de_amount = 0;
|
||
break;
|
||
case DIALOGUE_ENHANCEMENT_LOW:
|
||
adev->ms12.ac4_de = 4;
|
||
adev->ms12.dap_de_enable = 1;
|
||
adev->ms12.dap_de_amount = 4;
|
||
break;
|
||
case DIALOGUE_ENHANCEMENT_MEDIUM:
|
||
adev->ms12.ac4_de = 8;
|
||
adev->ms12.dap_de_enable = 1;
|
||
adev->ms12.dap_de_amount = 8;
|
||
break;
|
||
case DIALOGUE_ENHANCEMENT_HIGH:
|
||
adev->ms12.ac4_de = 12;
|
||
adev->ms12.dap_de_enable = 1;
|
||
adev->ms12.dap_de_amount = 12;
|
||
break;
|
||
default:
|
||
ALOGE("%s(), not the expected Dialogue Enhancement lever, set Dialogue Enhancement off", __FUNCTION__);
|
||
adev->ms12.ac4_de = 0;
|
||
adev->ms12.dap_de_enable = 0;
|
||
adev->ms12.dap_de_amount = 0;
|
||
break;
|
||
}
|
||
char parm[64] = "";
|
||
AM_LOGI("dap_init_mode=%d ms12_config:%d(0:Y,1:X,2:Z) ac4_de=%d dap_de=%d,%d",
|
||
adev->dolby_ms12_dap_init_mode, adev->dolby_ms12_audio_config, adev->ms12.ac4_de, adev->ms12.dap_de_enable, adev->ms12.dap_de_amount);
|
||
|
||
//STB and TV has different way to set dap de, TV use runtime, STB call decoder setting API
|
||
if (is_TV(adev) && adev->dolby_ms12_audio_config != MS12_CONFIG_Y) {
|
||
sprintf(parm,"ms12_runtime=-dap_dialogue_enhancer %d,%d", adev->ms12.dap_de_enable, adev->ms12.dap_de_amount);
|
||
if (strlen(parm) > 0) {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm);
|
||
}
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "hal_param_dmx_mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
switch (atoi(value)) {
|
||
case SOUND_DMX_MODE_SURROUND:
|
||
adev->downmix_type = 0;
|
||
break;
|
||
case SOUND_DMX_MODE_STEREO:
|
||
adev->downmix_type = 1;
|
||
break;
|
||
default:
|
||
ALOGE("%s(), not the expected dmx mode, set dmx mode surround", __FUNCTION__);
|
||
adev->downmix_type = 0;
|
||
break;
|
||
}
|
||
ALOGI("Amlogic_HAL - %s: set MS12 Downmix modes :%d.", __FUNCTION__, adev->downmix_type);
|
||
char parm[32] = "";
|
||
sprintf(parm, "%s %d", "-dmx", adev->downmix_type);
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (strlen(parm) > 0) {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm);
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;
|
||
}
|
||
|
||
|
||
ret = str_parms_get_str(parms, "picture_mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
if (strncmp(value, "PQ_MODE_STANDARD", 16) == 0) {
|
||
set_dev_pic_mode(PQ_STANDARD);
|
||
} else if (strncmp(value, "PQ_MODE_GAME", 12) == 0) {
|
||
set_dev_pic_mode(PQ_GAME);
|
||
} else {
|
||
set_dev_pic_mode(PQ_STANDARD);
|
||
AM_LOGE("unsupport value %s choose pic mode (default) standard", value);
|
||
}
|
||
AM_LOGI("set pic mode to: %d", get_dev_pic_mode());
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms, "prim_mixgain", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char parm[40] = "";
|
||
int gain = atoi(value);
|
||
if ((gain <= 0) && (gain >= -96)) {
|
||
sprintf(parm, "-sys_prim_mixgain %d,200,0", gain << 7);
|
||
pthread_mutex_lock(&adev->lock);
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm);
|
||
pthread_mutex_unlock(&adev->lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms, "apps_mixgain", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char parm[40] = "";
|
||
int gain = atoi(value);
|
||
if ((gain <= 0) && (gain >= -96)) {
|
||
int after_master_gain;
|
||
adev->ms12.apps_mixgain = gain << 7;
|
||
after_master_gain = 2560.0f * log10((adev->master_mute) ? 0.0f : adev->master_volume);
|
||
after_master_gain += adev->ms12.apps_mixgain;
|
||
if (after_master_gain > 0) {
|
||
after_master_gain = 0;
|
||
} else if (after_master_gain < (-96 << 7)) {
|
||
after_master_gain = -96 << 7;
|
||
}
|
||
sprintf(parm, "-sys_apps_mixgain %d,200,0", after_master_gain);
|
||
pthread_mutex_lock(&adev->lock);
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm);
|
||
pthread_mutex_unlock(&adev->lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms, "syss_mixgain", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char parm[40] = "";
|
||
int gain = atoi(value);
|
||
if ((gain <= 0) && (gain >= -96)) {
|
||
int after_master_gain;
|
||
adev->ms12.syss_mixgain = gain << 7;
|
||
after_master_gain = 2560.0f * log10((adev->master_mute) ? 0.0f : adev->master_volume);
|
||
after_master_gain += adev->ms12.syss_mixgain;
|
||
if (after_master_gain > 0) {
|
||
after_master_gain = 0;
|
||
} else if (after_master_gain < (-96 << 7)) {
|
||
after_master_gain = -96 << 7;
|
||
}
|
||
sprintf(parm, "-sys_syss_mixgain %d,200,0", after_master_gain);
|
||
pthread_mutex_lock(&adev->lock);
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm);
|
||
pthread_mutex_unlock(&adev->lock);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
ret = str_parms_get_str(parms, "vol_ease", value, sizeof(value));
|
||
if (ret >= 0) {// vol_ease only apply to main stream
|
||
int gain, duration, shape;// shape(0: linear, 1: in cube, 2: out cube)
|
||
|
||
AM_LOGI("vol_ease: value= %s", value);
|
||
if (adev->master_volume < FLOAT_ZERO) {
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
if (sscanf(value, "%d,%d,%d", &gain, &duration, &shape) == 3) {
|
||
set_vol_ease_by_decoder_id(0, gain, duration, shape);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
ret = str_parms_get_str(parms, "stream_vol_ease", value, sizeof(value));
|
||
if (ret >= 0) {// vol_ease only apply to main stream
|
||
int gain, duration, shape;// shape(0: linear, 1: in cube, 2: out cube)
|
||
int decoder_id = 0;
|
||
|
||
AM_LOGI("vol_ease: value= %s", value);
|
||
if (adev->master_volume < FLOAT_ZERO) {
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
if (sscanf(value, "%d,%d,%d,%d", &decoder_id, &gain, &duration, &shape) == 4) {
|
||
set_vol_ease_by_decoder_id(decoder_id, gain, duration, shape);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
}
|
||
|
||
//ms12_runtime is supported when MS12 exists or Dolby dap exists
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type || adev->ms12.dap_only_enable) {
|
||
ret = str_parms_get_str(parms, "ms12_runtime", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *parm = strstr(kvpairs, "=");
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (parm) {
|
||
if (strcmp(parm+1, "-atmos_lock 1") == 0) {
|
||
adev->atoms_lock_flag = 1;
|
||
} else if (strcmp(parm+1, "-atmos_lock 0") == 0) {
|
||
adev->atoms_lock_flag = 0;
|
||
} else if (strstr(parm+1, "-drc")) {
|
||
aml_audio_set_drc_control(parm+1, &adev->decoder_drc_control);
|
||
//dap drc default same with decoder drc
|
||
adev->dap_drc_control = adev->decoder_drc_control;
|
||
}
|
||
if (strstr(parm+1, "-dap_drc")) {
|
||
aml_audio_set_drc_control(strstr(parm+1, "-dap_drc"), &adev->dap_drc_control);
|
||
}
|
||
if (strstr(parm+1, "-dmx")) {
|
||
adev->downmix_type = atoi(parm+5);//refer to enum: AM_DownMixMode_t
|
||
AM_LOGE("%s, downmix_type %d", parm+5, adev->downmix_type);
|
||
}
|
||
if (strstr(parm+1, "-ac4_de")) {
|
||
int ac4_de = atoi(parm+8);
|
||
adev->ms12.ac4_de = ac4_de;
|
||
AM_LOGI("ac4_de=%d", ac4_de);
|
||
} else if (strstr(parm+1, "-dap_surround_virtualizer")) {
|
||
char *param_value = (adev->dolby_ms12_audio_config != MS12_CONFIG_Z) ? \
|
||
"-dap_surround_virtualizer 0,0" : parm + 1;
|
||
aml_ms12_update_runtime_params(&(adev->ms12), param_value);
|
||
} else if (strstr(parm+1, "-dap_surround_decoder_enable")) {
|
||
char *param_value = (adev->dolby_ms12_audio_config != MS12_CONFIG_Z) ? \
|
||
"-dap_surround_decoder_enable 0" : parm + 1;
|
||
aml_ms12_update_runtime_params(&(adev->ms12), param_value);
|
||
} else if (strstr(parm+1, "-dap_dialogue_enhancer") || strstr(parm+1, "-dap_leveler")) {
|
||
AM_LOGI("dap_init_mode=%d dolby_ms12_audio_config:%d(0:Y,1:X,2:Z)", adev->dolby_ms12_dap_init_mode, adev->dolby_ms12_audio_config);
|
||
if ((adev->dolby_ms12_dap_init_mode == 1) && (adev->dolby_ms12_audio_config == MS12_CONFIG_X)) {
|
||
//for OTT config X, dap is in codec graph
|
||
if (strstr(parm+1, "-dap_dialogue_enhancer")) {
|
||
adev->ms12.dap_de_enable = atoi(parm+24);
|
||
adev->ms12.dap_de_amount = atoi(parm+26);
|
||
AM_LOGI("de_enable:%d de_amount:%d", adev->ms12.dap_de_enable, adev->ms12.dap_de_amount);
|
||
} else {
|
||
adev->ms12.dap_leveler[0] = atoi(parm+14);
|
||
adev->ms12.dap_leveler[1] = atoi(parm+16);
|
||
AM_LOGI("dap_leveler:%d,%d", adev->ms12.dap_leveler[0], adev->ms12.dap_leveler[1]);
|
||
}
|
||
} else {
|
||
//for TV/Soundbar config X/Z
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm+1);
|
||
}
|
||
} else {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm+1);
|
||
audio_continuous_standby_reset(ms12->continuous_standby_handle);
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;
|
||
}
|
||
}
|
||
ret = str_parms_get_str(parms, "dmx_mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *parm = strstr(kvpairs, "=");
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (parm) {
|
||
if (strstr(parm+1, "-dmx")) {
|
||
adev->downmix_type = atoi(parm+5);//refer to enum: AM_DownMixMode_t
|
||
AM_LOGD("%s, downmix_type %d", parm+5, adev->downmix_type);
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), parm+1);
|
||
}
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "drc_mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *parm = strstr(kvpairs, "=");
|
||
pthread_mutex_lock(&adev->lock);
|
||
if (parm) {
|
||
if (strstr(parm+1, "-drc")) {
|
||
aml_audio_set_drc_control(parm+1, &adev->decoder_drc_control);
|
||
//dap drc default same with decoder drc
|
||
adev->dap_drc_control = adev->decoder_drc_control;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if (strstr(parm+1, "-dap_drc")) {
|
||
aml_audio_set_drc_control(strstr(parm+1, "-dap_drc"), &adev->dap_drc_control);
|
||
}
|
||
//aml_ms12_update_runtime_params(&(adev->ms12), parm+1);
|
||
adev->drc_mode_ui_config = true;
|
||
ALOGI("UI set drc_mode_ui_config = %d",adev->drc_mode_ui_config);
|
||
dynamic_set_dap_drc_parameters(&adev->ms12, adev->decoder_drc_control);
|
||
dynamic_set_dolby_ms12_drc_parameters(&adev->ms12, adev->dap_drc_control );
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "bypass_dap", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
sscanf(value,"%d %f", &adev->ms12.UI_disable_dap, &adev->ms12.dap_bypassgain);
|
||
set_ms12_dap_disable_by_UI(&adev->ms12, adev->ms12.UI_disable_dap);
|
||
AM_LOGD("UI_disable_dap is %d and dap_bypassgain is %f",adev->ms12.UI_disable_dap, adev->ms12.dap_bypassgain);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "tuning_binary", value, sizeof(value));
|
||
if (ret >= 0 && strlen(value)) {
|
||
adev->is_ms12_tuning_dat = is_ms12_tuning_dat_in_dut(value);
|
||
if (adev->is_ms12_tuning_dat) {
|
||
if (sizeof(adev->ms12_tuning_dat_path) >= strlen(value) + 1) {
|
||
memset(adev->ms12_tuning_dat_path, 0, sizeof(adev->ms12_tuning_dat_path));
|
||
memcpy(adev->ms12_tuning_dat_path, value, strlen(value));
|
||
char tuning_data_runtime_param[AUDIO_HAL_CHAR_MAX_LEN + 12] = {};
|
||
if (-1 != snprintf(tuning_data_runtime_param, sizeof(tuning_data_runtime_param), "-dap_tuning %s", adev->ms12_tuning_dat_path)) {
|
||
AM_LOGI("tuning_data_runtime_param=%s", tuning_data_runtime_param);
|
||
if ((eDolbyMS12Lib == adev->dolby_lib_type) && (adev->dolby_ms12_audio_config != MS12_CONFIG_Y)) {
|
||
aml_ms12_update_runtime_params(&(adev->ms12), tuning_data_runtime_param);
|
||
audio_continuous_standby_reset(ms12->continuous_standby_handle);
|
||
} else {
|
||
AM_LOGW("dolby_lib_type:%d ms12_config:%d, can not set ms12 tuning data", adev->dolby_lib_type, adev->dolby_ms12_audio_config);
|
||
}
|
||
} else {
|
||
AM_LOGE("Set dap tuning data fail");
|
||
}
|
||
} else {
|
||
AM_LOGE("The len of value is %zu, it is too long to set", strlen(value) + 1);
|
||
}
|
||
} else {
|
||
AM_LOGW("The file in the %s path does not exist", value);
|
||
}
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_str(parms, "Dolby_Config_Type", value, sizeof(value));
|
||
if (ret >= 0 && strlen(value)) {
|
||
adev->dolby_ms12_audio_config = (strcasestr(value, "Z") != NULL) ? MS12_CONFIG_Z : \
|
||
(strcasestr(value, "X") != NULL) ? MS12_CONFIG_X : MS12_CONFIG_Y;
|
||
ALOGI("[%s:%d],use dolby config %d ", __func__, __LINE__, adev->dolby_ms12_audio_config);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "VX_SET_DTS_Mode", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int dts_decoder_output_mode = atoi(value);
|
||
if (dts_decoder_output_mode > 6 || dts_decoder_output_mode < 0)
|
||
goto exit;
|
||
if (dts_decoder_output_mode == 2)
|
||
adev->native_postprocess.vx_force_stereo = 1;
|
||
else
|
||
adev->native_postprocess.vx_force_stereo = 0;
|
||
dca_set_out_ch_internal(dts_decoder_output_mode);
|
||
AM_LOGD("set dts decoder output mode to %d", dts_decoder_output_mode);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "pts_gap", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
unsigned long long offset, duration;
|
||
if (sscanf(value, "%llu,%lld", &offset, &duration) == 2) {
|
||
AM_LOGI("pts_gap %llu %lld", offset, duration);
|
||
adev->gap_offset = offset;
|
||
adev->gap_ignore_pts = false;
|
||
adev->gap_passthrough_state = GAP_PASSTHROUGH_STATE_SET;
|
||
//to test
|
||
//dolby_ms12_set_pts_gap(offset, duration);
|
||
ret = 0;
|
||
goto exit;
|
||
}
|
||
ret = -EINVAL;
|
||
goto exit;
|
||
}
|
||
|
||
#ifndef NO_AUDIO_CAP
|
||
ret = str_parms_get_int(parms, "audioinject", &val);
|
||
if (ret >= 0) {
|
||
if (val == 1) {
|
||
adev->injection_enable = 1;
|
||
// injection must be used with capture together
|
||
pthread_mutex_lock(&adev->cap_handle_lock);
|
||
if (!adev->capture_handle) {
|
||
AM_LOGE("injection must be used with capture together!!! please check !!!");
|
||
}
|
||
pthread_mutex_unlock(&adev->cap_handle_lock);
|
||
//set PCM output to close spdif handle
|
||
set_hdmi_format(adev, PCM);
|
||
AM_LOGI("close pcm out");
|
||
aml_audio_pcm_out_close(adev);
|
||
} else {
|
||
adev->injection_enable = 0;
|
||
}
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
ret = str_parms_get_int(parms, "low_latency", &val);
|
||
if (ret >= 0 ) {
|
||
adev->low_latency_mode = val;
|
||
if (adev->ms12.dolby_ms12_enable) {
|
||
set_ms12_full_dap_disable(&adev->ms12, adev->low_latency_mode);
|
||
pthread_mutex_lock(&adev->ms12.lock);
|
||
if (adev->low_latency_mode) {
|
||
set_ms12_alsa_limit_frame(&adev->ms12, MS12_ALSA_LOW_LIMIT_FRAME);
|
||
} else {
|
||
set_ms12_alsa_limit_frame(&adev->ms12, MS12_ALSA_DEFAULT_LIMIT_FRAME);
|
||
}
|
||
pthread_mutex_unlock(&adev->ms12.lock);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "gst_pause", &val);
|
||
if (ret >= 0) {
|
||
AM_LOGE ("TODO: gst_pause: This feature is currently unavailable and needs to be added");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "enable_scaletempo", &val);
|
||
if (ret >= 0) {
|
||
if (val == 1)
|
||
adev->user_setting_scaletempo = true;
|
||
else
|
||
adev->user_setting_scaletempo = false;
|
||
AM_LOGI("audio enable_scaletempo: %s", adev->user_setting_scaletempo? "already enable as default": "disable");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms,"OutputDestination", value , sizeof(value));
|
||
if (ret >= 0) {
|
||
AM_LOGI("OutputDestination=%s", value);
|
||
adev_update_active_outport(adev, (audio_devices_t)atoi(value));
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "spdif_protection_mode", &val);
|
||
if (ret >= 0 ) {
|
||
if (val == SPDIF_PROTECTION_MODE_NEVER) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_ENABLE);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_B_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_ENABLE);
|
||
} else if (val == SPDIF_PROTECTION_MODE_ONCE || val == SPDIF_PROTECTION_MODE_NONE) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_DISABLE);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_B_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_DISABLE);
|
||
} else if (val == SPDIF_PROTECTION_MODE_CP_NO) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_CP_ENABLE);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_B_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_CP_ENABLE);
|
||
} else if (val == SPDIF_PROTECTION_MODE_CP_YES) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_CP_DISABLE);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_B_OUT_CHANNEL_STATUS, SPDIF_PROTECTION_CP_DISABLE);
|
||
}
|
||
AM_LOGI("spdif_protection_mode:%d", val);
|
||
goto exit;
|
||
}
|
||
|
||
//this function is used for TTS
|
||
//1. when TTS starts to play, the volumes of other streams become small
|
||
// the calling order shold be a."audio_focus_enable=ture" b."audio_focus_volume=***"
|
||
//2. when TTS stops to play, the volumes of other streams resume
|
||
// the calling order shold be "audio_focus_enable=false"
|
||
ret = str_parms_get_int(parms, "audio_focus_enable", &val);
|
||
if (ret >= 0) {
|
||
if (val == 1) {
|
||
adev->audio_focus_enable = true;
|
||
}
|
||
else {
|
||
adev->audio_focus_enable = false;
|
||
}
|
||
AM_LOGI("audio focus %s", adev->audio_focus_enable? "enable": "disable");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "audio_focus_volume", &val);
|
||
if (ret >= 0) {
|
||
if (adev->audio_focus_enable) {
|
||
if (val == 100) { // 0 ~ 100: 100 means recover volume
|
||
adev->audio_focus_ratio = 1.0;
|
||
aml_audio_focus(adev, false);
|
||
AM_LOGI("audio_foucus recover volume");
|
||
} else {
|
||
adev->audio_focus_volume = val;
|
||
adev->audio_focus_ratio = adev->audio_focus_volume / 100.0L;
|
||
aml_audio_focus(adev, true);
|
||
AM_LOGI("audio_focus_volume is %d", adev->audio_focus_volume);
|
||
}
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms,"master_volume", &val);
|
||
if (ret >= 0) {
|
||
adev_set_master_volume(dev, (float)val/100.0);
|
||
|
||
AM_LOGI("master_volume is %f", (float)val/100.0);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "patch_set_decoder_id", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int patch_id = 0;
|
||
int decoder_id = 0;
|
||
char *delimiter = ",";
|
||
char *remaining_string = value;
|
||
patch_id = (atoi)(strtok_r(value, delimiter, &remaining_string));
|
||
decoder_id = (atoi)(strtok_r(NULL, delimiter, &remaining_string));
|
||
patch_mgr_set_decoder_id(adev->patch_manager, patch_id, decoder_id);
|
||
goto exit;
|
||
}
|
||
|
||
//example: set_volume_by_id=1,0.5
|
||
ret = str_parms_get_str(parms, "set_volume_by_id", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int decoder_id = 0;
|
||
float decoder_volume = 0;
|
||
char *delimiter = ",";
|
||
char *remaining_string = value;
|
||
decoder_id = (atoi)(strtok_r(value, delimiter, &remaining_string));
|
||
decoder_volume = (atof)(strtok_r(NULL, delimiter, &remaining_string));
|
||
set_volume_by_decoder_id(decoder_id, decoder_volume, decoder_volume);
|
||
goto exit;
|
||
}
|
||
|
||
//example:hal_param set set_output_device_by_id=1,0 [id,device]
|
||
ret = str_parms_get_str(parms, "set_output_device_by_id", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
int decoder_id = 0;
|
||
char *delimiter = ",";
|
||
int device = AML_OUTPUT_DEVICE_DEFAULT;
|
||
char *remaining_string = value;
|
||
decoder_id = (atoi)(strtok_r(value, delimiter, &remaining_string));
|
||
device = (atoi)(strtok_r(NULL, delimiter, &remaining_string));
|
||
aml_set_output_device_by_id(decoder_id, device);
|
||
goto exit;
|
||
}
|
||
|
||
/* karaoke parameters
|
||
format: karaoke_control=cmd,type,value
|
||
such as: "karaoke_control=switch,0,0" means that set USB mic on */
|
||
ret = str_parms_get_str(parms, "karaoke_control", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
karaoke_manager_command(adev->kara_manager, value, sizeof(value));
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "karaoke_vol", &val);
|
||
if (ret >= 0 ) {
|
||
float volume = val / 100.0;
|
||
adev_set_karaoke_vol(adev, volume);
|
||
AM_LOGI("set karaoke_vol:%d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dtsx_drc_enable", &val);
|
||
if (ret >= 0 ) {
|
||
adev->dtsx_drc_enable = val? true : false;
|
||
dtsx_set_drc_state(adev->dtsx_drc_enable);
|
||
ALOGI("[%s:%d] set dtsx drc state to:%s", __func__, __LINE__, adev->dtsx_drc_enable?"ON" : "OFF");
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dtsx_spk_loudness", &val);
|
||
if (ret >= 0 ) {
|
||
if (val == 1) {
|
||
dtsx_spk_loudness_enable(true);
|
||
} else {
|
||
dtsx_spk_loudness_enable(false);
|
||
}
|
||
ALOGI("[%s:%d] dtsx_spk_loudness:%d", __func__, __LINE__, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dtsx_spk_loudness_target", &val);
|
||
if (ret >= 0 ) {
|
||
dtsx_spk_loudness_target(val);
|
||
ALOGI("[%s:%d] dtsx_spk_loudness_target:%d", __func__, __LINE__, val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dtsx_type1_relable_enable", &val);
|
||
if (ret >= 0) {
|
||
dtsx_enable_type1_relable(val);
|
||
AM_LOGI("dtsx_type1_relable_enable: %d", val);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms,"remove_audio_effect", value , sizeof(value));
|
||
if (ret >= 0) {
|
||
char sound_effect_support_list[AUDIO_HAL_CHAR_MAX_LEN] = {0};
|
||
aml_report_audio_support_list_to_ui(adev, sound_effect_support_list, AUDIO_HAL_CHAR_MAX_LEN);
|
||
if (strncmp(value, "all", strlen(value)) == 0) {
|
||
ALOGI("adev->native_postprocess.num_postprocessors=%d\n",adev->native_postprocess.num_postprocessors);
|
||
while (adev->native_postprocess.num_postprocessors > 0) {
|
||
effect_handle_t effect = adev->native_postprocess.postprocessors[adev->native_postprocess.num_postprocessors-1];
|
||
adev_remove_device_effect(dev, 0, effect);
|
||
}
|
||
AM_LOGI("remove %s sound effect", value);
|
||
} else {
|
||
effect_descriptor_t tmpdesc_in_queue;
|
||
for (int i = 0; i < adev->native_postprocess.num_postprocessors; i++) {
|
||
(*adev->native_postprocess.postprocessors[i])->get_descriptor(adev->native_postprocess.postprocessors[i], &tmpdesc_in_queue);
|
||
if (strncmp (tmpdesc_in_queue.name, value, strlen(tmpdesc_in_queue.name)) == 0) {
|
||
adev_remove_device_effect(dev, 0, adev->native_postprocess.postprocessors[i]);
|
||
AM_LOGI("support %s effect, remove %s sound effect", sound_effect_support_list, value);
|
||
break;
|
||
}
|
||
}
|
||
AM_LOGW("Not support %s effect, remove sound effect failed", value);
|
||
}
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "vpts_mt_offset", &val);
|
||
if (ret >= 0) {
|
||
adev->hbbtvsync_info.vpts_mt_offset = val;//ms
|
||
AM_LOGI("vpts_mt_offset: %d", val);
|
||
goto exit;
|
||
}
|
||
ret = str_parms_get_int(parms, "va_offset", &val);
|
||
if (ret >= 0) {
|
||
adev->hbbtvsync_info.va_offset = val;//ms
|
||
AM_LOGI("va_offset: %d", val);
|
||
goto exit;
|
||
}
|
||
ret = set_mpegh_parameters(adev, parms);
|
||
if (ret >= 0) {
|
||
AM_LOGI("set mpeg param, kv: %s", kvpairs);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_int(parms, "dtsx_support", &val);
|
||
if (ret >= 0 ) {
|
||
ALOGI("[%s:%d] dtsx_support:%d", __func__, __LINE__, val);
|
||
//The platform does not support dts, but dts x lib in the DTS_X_LIB_PATH_A
|
||
//need close the open dts lib.
|
||
if (!val && adev->dts_lib_type == eDTSXLib) {
|
||
adev->dts_lib_type = detect_dts_lib_type((bool)val);
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
#ifdef BUILD_LINUX
|
||
ret = str_parms_get_str(parms, "setenv", value, sizeof(value));
|
||
if (ret >= 0) {
|
||
char *remaining_string;
|
||
char *var = strtok_r(value, ",", &remaining_string);
|
||
if (var) {
|
||
char *val = var + strlen(var) + 1;
|
||
if (strlen(val) > 0) {
|
||
aml_audio_property_set(var, val);
|
||
} else {
|
||
aml_audio_property_unset(var);
|
||
AM_LOGI("env %s unset", var);
|
||
|
||
#ifdef DIAG_LOG
|
||
if (strcmp(var, "AV_PROGRESSION") == 0) {
|
||
pthread_mutex_lock(&adev->diag_log_lock);
|
||
diag_log_close(adev);
|
||
pthread_mutex_unlock(&adev->diag_log_lock);
|
||
}
|
||
#endif
|
||
|
||
}
|
||
}
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
ret = str_parms_get_int(parms, "system_early_suspend", &val);
|
||
if (ret >= 0)
|
||
{
|
||
if (adev->is_early_suspend != val) {
|
||
AM_LOGI("system_early_suspend: %d", val);
|
||
adev->is_early_suspend = val;
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
int len = 2048; //todo
|
||
//len = str_parms_get_str_len(parms, "applyxmlaction");
|
||
if (0 < len)
|
||
{
|
||
char *xmlbuf = aml_audio_calloc(1, (len + 1));
|
||
if (NULL == xmlbuf) {
|
||
AM_LOGE("aml_audio_calloc: %d, fail!", ret);
|
||
goto exit;
|
||
}
|
||
|
||
ret = str_parms_get_str(parms, "applyxmlaction", xmlbuf, (len + 1));
|
||
if (ret >= 0) {
|
||
ret = aml_mpegh_applyxmlaction(adev, xmlbuf, (len + 1));
|
||
AM_LOGI("applyxmlaction: %d", ret);
|
||
}
|
||
aml_audio_free(xmlbuf);
|
||
xmlbuf = NULL;
|
||
goto exit;
|
||
}
|
||
|
||
exit:
|
||
str_parms_destroy (parms);
|
||
/* always success to pass VTS */
|
||
return 0;
|
||
}
|
||
|
||
static void adev_get_cec_control_object(struct aml_audio_device *adev, char *temp_buf)
|
||
{
|
||
int cec_control_tv = 0;
|
||
if (!is_TV(adev) && adev->dolby_lib_type != eDolbyMS12Lib) {
|
||
enum AML_SPDIF_FORMAT format = AML_STEREO_PCM;
|
||
enum AML_SRC_TO_HDMITX spdif_index = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_AUDIO_SRC_TO_HDMI);
|
||
if (spdif_index == AML_SPDIF_A_TO_HDMITX) {
|
||
format = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_FORMAT);
|
||
} else if (spdif_index == AML_SPDIF_B_TO_HDMITX) {
|
||
format = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_SPDIF_B_FORMAT);
|
||
} else {
|
||
format = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_I2S2HDMI_FORMAT);
|
||
}
|
||
cec_control_tv = (format == AML_STEREO_PCM) ? 0 : 1;
|
||
}
|
||
sprintf (temp_buf, "hal_param_cec_control_tv=%d", cec_control_tv);
|
||
if (adev->debug_flag) {
|
||
ALOGD("[%s:%d] hal_param_cec_control_tv:%d", __func__, __LINE__, cec_control_tv);
|
||
}
|
||
}
|
||
|
||
/*Based on the existing library resources to determine whether to support the decoding of this format*/
|
||
static bool aml_get_codec_support_runtime(struct aml_audio_device *adev, char* aformat)
|
||
{
|
||
audio_format_t audio_format = convert_audio_str_2_audio_formt(aformat);
|
||
if (audio_format == AUDIO_FORMAT_PCM) {
|
||
return true;
|
||
} else {
|
||
if ((adev->dolby_lib_type == eDolbyMS12Lib && is_dolby_ms12_support_compression_format(audio_format)) ||
|
||
(adev->dts_decode_enable && is_dts_format(audio_format)) ||
|
||
(adev->dolby_lib_type == eDolbyDcvLib && adev->dolby_decode_enable && is_dcv_dec_support(audio_format))) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static char * adev_get_parameters (const struct audio_hw_device *dev,
|
||
const char *keys)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
char temp_buf[AUDIO_HAL_CHAR_MAX_LEN + 32] = {0};
|
||
|
||
if (!strcmp (keys, AUDIO_PARAMETER_HW_AV_SYNC) ) {
|
||
ALOGI ("get hw_av_sync id\n");
|
||
return strdup ("hw_av_sync=12345678");
|
||
}
|
||
// ALOGI ("adev_get_parameters keys: %s \n", keys);
|
||
if (strstr (keys, "getenv=") ) {
|
||
char *pret=getenv(&keys[7]);
|
||
if (NULL != pret) {
|
||
ALOGI ("ret: val %s,key %s \n", pret, &keys[7]);
|
||
return strdup (pret);
|
||
} else {
|
||
return strdup ("find not");
|
||
}
|
||
} else if (strstr (keys, AUDIO_PARAMETER_HW_AV_EAC3_SYNC) ) {
|
||
return strdup ("HwAvSyncEAC3Supported=true");
|
||
} else if (strstr (keys, "hdmi_format") ) {
|
||
sprintf (temp_buf, "hdmi_format=%d", adev->hdmi_format);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "digital_output_format") ) {
|
||
if (adev->hdmi_format == PCM) {
|
||
return strdup ("digital_output_format=pcm");
|
||
} else if (adev->hdmi_format == DD) {
|
||
return strdup ("digital_output_format=dd");
|
||
} else if (adev->hdmi_format == DDP) {
|
||
return strdup ("digital_output_format=ddp");
|
||
} else if (adev->hdmi_format == AUTO) {
|
||
return strdup ("digital_output_format=auto");
|
||
} else if (adev->hdmi_format == BYPASS) {
|
||
return strdup ("digital_output_format=bypass");
|
||
}
|
||
} else if (strstr (keys, "spdif_format") ) {
|
||
sprintf (temp_buf, "spdif_format=%d", adev->spdif_format);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "hdmi_is_passthrough_active") ) {
|
||
sprintf (temp_buf, "hdmi_is_passthrough_active=%d", adev->hdmi_is_pth_active);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "disable_pcm_mixing") ) {
|
||
sprintf (temp_buf, "disable_pcm_mixing=%d", adev->disable_pcm_mixing);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "hdmi_encodings") ) {
|
||
struct format_desc *fmtdesc = NULL;
|
||
bool dd = false, ddp = false;
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
|
||
// query dd support
|
||
fmtdesc = &hdmi_desc->dd_fmt;
|
||
if (fmtdesc && fmtdesc->fmt == AML_HDMI_FORMAT_AC3)
|
||
dd = fmtdesc->is_support;
|
||
|
||
// query ddp support
|
||
fmtdesc = &hdmi_desc->ddp_fmt;
|
||
if (fmtdesc && fmtdesc->fmt == AML_HDMI_FORMAT_DDP)
|
||
ddp = fmtdesc->is_support;
|
||
|
||
sprintf (temp_buf, "hdmi_encodings=%s", "pcm;");
|
||
if (ddp)
|
||
sprintf (temp_buf, "ac3;eac3;");
|
||
else if (dd)
|
||
sprintf (temp_buf, "ac3;");
|
||
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "is_passthrough_active") ) {
|
||
bool active = false;
|
||
pthread_mutex_lock (&adev->lock);
|
||
// "is_passthrough_active" is used by amnuplayer to check is current audio hal have passthrough instance(DD/DD+/DTS)
|
||
// if already have one passthrough instance, it will not invoke another one.
|
||
// While in HDMI plug off/in test case. Player will query "is_passthrough_active" before adev->usecase_masks finally settle
|
||
// So Player will have a chance get a middle-term value, which is wrong.
|
||
// now only one passthrough instance, do not check
|
||
/* if (adev->usecase_masks & RAW_USECASE_MASK)
|
||
active = true;
|
||
else if (adev->audio_patch && (adev->audio_patch->aformat == AUDIO_FORMAT_E_AC3 \
|
||
|| adev->audio_patch->aformat == AUDIO_FORMAT_AC3) ) {
|
||
active = true;
|
||
} */
|
||
pthread_mutex_unlock (&adev->lock);
|
||
sprintf (temp_buf, "is_passthrough_active=%d",active);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "hal_param_cec_control_tv")) {
|
||
adev_get_cec_control_object(adev, temp_buf);
|
||
return strdup (temp_buf);
|
||
} else if (!strcmp(keys, "SOURCE_GAIN")) {
|
||
sprintf(temp_buf, "source_gain = %f %f %f %f %f", adev->eq_data.s_gain.atv, adev->eq_data.s_gain.dtv,
|
||
adev->eq_data.s_gain.hdmi, adev->eq_data.s_gain.av, adev->eq_data.s_gain.media);
|
||
ALOGD("source_gain = %f %f %f %f %f", adev->eq_data.s_gain.atv, adev->eq_data.s_gain.dtv,
|
||
adev->eq_data.s_gain.hdmi, adev->eq_data.s_gain.av, adev->eq_data.s_gain.media);
|
||
return strdup(temp_buf);
|
||
} else if (!strcmp(keys, "POST_GAIN")) {
|
||
sprintf(temp_buf, "post_gain = %f %f %f", adev->eq_data.p_gain.speaker, adev->eq_data.p_gain.spdif_arc,
|
||
adev->eq_data.p_gain.headphone);
|
||
return strdup(temp_buf);
|
||
} else if (strstr(keys, "dolby_ms12_enable")) {
|
||
int ms12_enable = (eDolbyMS12Lib == adev->dolby_lib_type_last);
|
||
ALOGI("ms12_enable :%d", ms12_enable);
|
||
sprintf(temp_buf, "dolby_ms12_enable=%d", ms12_enable);
|
||
return strdup(temp_buf);
|
||
} else if (strstr(keys, "isReconfigA2dpSupported")) {
|
||
return strdup("isReconfigA2dpSupported=1");
|
||
} else if (!strcmp(keys, "SOURCE_MUTE")) {
|
||
sprintf(temp_buf, "source_mute = %d", adev->source_mute);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "stream_dra_channel") ) {
|
||
struct aml_audio_patch *dtv_patch = get_dev_patch_by_source(adev, SRC_DTV);
|
||
if (dtv_patch) {
|
||
if (dtv_patch->dtv_NchOriginal > 8 || dtv_patch->dtv_NchOriginal < 1) {
|
||
sprintf (temp_buf, "0.0");
|
||
} else {
|
||
sprintf(temp_buf, "channel_num=%d.%d", dtv_patch->dtv_NchOriginal,dtv_patch->dtv_lfepresent);
|
||
ALOGD ("temp_buf=%s\n", temp_buf);
|
||
}
|
||
} else {
|
||
sprintf (temp_buf, "0.0");
|
||
}
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr(keys, "HDMI Switch")) {
|
||
sprintf(temp_buf, "HDMI Switch=%d", (OUTPORT_HDMI == adev->active_outport || is_HDMI_connected(adev) == 1));
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (!strcmp(keys, "decoder_mute")) {
|
||
sprintf(temp_buf, "decoder_mute = %d", adev->decoder_mute);
|
||
return strdup(temp_buf);
|
||
} else if (!strcmp(keys, "parental_control_av_mute")) {
|
||
sprintf(temp_buf, "parental_control_av_mute = %d", adev->patch_mute);
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr (keys, "diaglogue_enhancement") ) {
|
||
sprintf(temp_buf, "diaglogue_enhancement=%d", adev->ms12.ac4_de);
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr(keys, "audioindicator")) {
|
||
get_audio_indicator(adev, temp_buf);
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr (keys, "hal_param_get_earctx_attend_type") ) {
|
||
int type = aml_audio_earctx_get_type(adev);
|
||
sprintf(temp_buf, "hal_param_get_earctx_attend_type=%d", type);
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr (keys, "hal_param_get_earctx_cds") ) {
|
||
char cds[AUDIO_HAL_CHAR_MAX_LEN] = {0};
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(adev);
|
||
|
||
earctx_fetch_cds(&adev->alsa_mixer, cds, 0, hdmi_desc);
|
||
sprintf(temp_buf, "hal_param_get_earctx_cds=%s", cds);
|
||
return strdup(temp_buf);
|
||
}
|
||
else if (strstr(keys, "audio_information")) {
|
||
if ((0 >= adev->audio_hal_info.channel_number) || (0 >= adev->audio_hal_info.sample_rate)) {
|
||
adev->audio_hal_info.sample_rate = 48000;
|
||
adev->audio_hal_info.channel_number = 2;
|
||
}
|
||
snprintf(temp_buf, sizeof(temp_buf), "audio_information=%d,%d", adev->audio_hal_info.sample_rate, adev->audio_hal_info.channel_number);
|
||
return strdup(temp_buf);
|
||
}
|
||
#ifdef USE_DTV
|
||
else if (strstr (keys, "hal_param_dtv_demuxidbase") ) {
|
||
sprintf(temp_buf, "hal_param_dtv_demuxidbase=%d", dtv_get_demuxidbase());
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "ac4_active_pres_id")) {
|
||
int active_id_offset = -1;
|
||
struct aml_stream_out *aml_out = NULL;
|
||
bool is_ac4_stream_present = false;
|
||
|
||
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
|
||
aml_out = adev->active_outputs[i];
|
||
if (aml_out && AUDIO_FORMAT_AC4 == aml_out->hal_internal_format) {
|
||
AM_LOGI("aml_out:%p format:%x", aml_out, aml_out->hal_internal_format);
|
||
is_ac4_stream_present = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ((eDolbyMS12Lib == adev->dolby_lib_type) && is_ac4_stream_present) {
|
||
//should use the dolby_ms12_get_ac4_active_presentation() before or after get_dolby_ms12_cleanup()
|
||
pthread_mutex_lock(&adev->ms12.lock);
|
||
if (adev->ms12.dolby_ms12_enable && (0 == get_aml_ac4_active_presentation((struct audio_stream_out *)aml_out, &active_id_offset))) {
|
||
ALOGI ("get_aml_ac4_active_presentation index is %d", active_id_offset);
|
||
}
|
||
pthread_mutex_unlock(&adev->ms12.lock);
|
||
}
|
||
sprintf(temp_buf, "ac4_active_pres_id=%d", active_id_offset);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "hal_param_dtv_es_pts_dts_flag")) {
|
||
int flag = dtv_path_get_es_pts_dts_flag(0);
|
||
sprintf(temp_buf, "hal_param_dtv_es_pts_dts_flag=%d", flag);
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
}
|
||
#endif
|
||
else if (strstr (keys, "codecsupport")) {
|
||
//return strdup(aml_get_codec_support((char*)(&keys[strlen("codecsupport") + 1]))? "true": "false");
|
||
return strdup(aml_get_codec_support_runtime(adev, (char*)(&keys[strlen("codecsupport") + 1]))? "true": "false");
|
||
} else if (strstr(keys, "dolby_lib_type")) {
|
||
ALOGI("dolby_lib_type: %d", adev->dolby_lib_type);
|
||
sprintf(temp_buf, "dolby_lib_type=%d", adev->dolby_lib_type);
|
||
return strdup(temp_buf);
|
||
} else if (!strncmp(keys, "audio_info=", 11)) {
|
||
int audio_info_type = 0;
|
||
keys += 11;
|
||
sscanf(keys ,"%d", &audio_info_type);
|
||
|
||
switch (audio_info_type) {
|
||
case AUDIO_PARAMTYPE_DEC_STATUS:
|
||
sprintf (temp_buf,"audio_information_d=%d", adev->audio_hal_info.is_decoding);
|
||
break;
|
||
case AUDIO_PARAMTYPE_PTS:
|
||
//AUDIO_PARAMTYPE_PTS
|
||
break;
|
||
case AUDIO_PARAMTYPE_SAMPLE_RATE:
|
||
sprintf (temp_buf,"audio_information_s=%d", adev->audio_hal_info.sample_rate);
|
||
break;
|
||
case AUDIO_PARAMTYPE_CHANNEL_MODE:
|
||
sprintf (temp_buf,"audio_information_c=%d", adev->audio_hal_info.channel_number);
|
||
break;
|
||
case AUDIO_PARAMTYPE_DIGITAL_AUDIO_INFO:
|
||
//AUDIO_PARAMTYPE_DIGITAL_AUDIO_INFO;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
ALOGI("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "get_sink_capability")) {
|
||
return strdup(get_sink_all_capability(adev, temp_buf));
|
||
} else if (strstr(keys, "get_device_capability")) { //only get the ms12 atmos enable or not
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && adev->dolby_ms12_audio_config == MS12_CONFIG_Z && is_dap_surround_virtualizer_support()) {
|
||
sprintf(temp_buf,"device_cap=ddp_atmos");
|
||
} else {
|
||
sprintf(temp_buf,"device_cap=none");
|
||
}
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "get_audio_playing_status")) {
|
||
sprintf(temp_buf, "audio_playing_status=%d", aml_is_audio_playing(adev));
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "get_output_port_information")) {
|
||
return strdup(get_output_port_information(adev, temp_buf));
|
||
} else if (strstr(keys, "audio_server_status")) {
|
||
sprintf(temp_buf, "ready");
|
||
ALOGI("audio_server_status: %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "get_audio_support_info")) {
|
||
char effect_list[AUDIO_HAL_CHAR_MAX_LEN] = {0};
|
||
aml_report_audio_support_list_to_ui(adev, effect_list, AUDIO_HAL_CHAR_MAX_LEN);
|
||
sprintf(temp_buf, "audio_support_info: %s", effect_list);
|
||
ALOGI("audio_support_list_to_ui: %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr (keys, "speaker_mute")) {
|
||
bool is_muted = is_output_device_muted(adev, AUDIO_DEVICE_OUT_SPEAKER, false);
|
||
sprintf (temp_buf, "speaker_mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "headphone_mute")) {
|
||
bool is_muted = is_output_device_muted(adev, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, false);
|
||
sprintf (temp_buf, "headphone_mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "Audio spdif mute")) {
|
||
bool is_muted = is_output_device_muted(adev, AUDIO_DEVICE_OUT_SPDIF, false);
|
||
sprintf (temp_buf, "Audio spdif mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "ARC eARC mute")) {
|
||
bool is_muted = is_output_device_muted(adev, AUDIO_DEVICE_OUT_HDMI_ARC, false);
|
||
sprintf (temp_buf, "ARC eARC mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "usb_spk_mute")) {
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
if (adev->usb_handle) {
|
||
bool is_muted = aml_get_external_device_mute(adev->usb_handle);
|
||
sprintf (temp_buf, "usb_spk_mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
}
|
||
#endif
|
||
} else if (strstr (keys, "bt_mute")) {
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
if (adev->usb_handle) {
|
||
bool is_muted = aml_get_external_device_mute(adev->bt_handle);
|
||
sprintf (temp_buf, "bt_mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
}
|
||
#endif
|
||
} else if (strstr (keys, "Master volume")) {
|
||
int master_volume = 0;
|
||
if (is_STB(adev)) {
|
||
int dac_vol[2] = {0};
|
||
aml_mixer_ctrl_get_array(&adev->alsa_mixer, AML_MIXER_ID_DAC_DIGITAL_VOLUME, &dac_vol, 2);
|
||
master_volume = dac_vol[0];
|
||
} else {
|
||
master_volume = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_AMP_MASTER_VOLUME);
|
||
}
|
||
sprintf (temp_buf, "Master volume=%d", master_volume);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "Audio hdmi-out mute")) {
|
||
bool is_muted = is_output_device_muted(adev, AUDIO_DEVICE_OUT_HDMI, false);
|
||
sprintf (temp_buf, "Audio hdmi-out mute=%d", is_muted);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "get_cap_info=")) {
|
||
/*Only for box to get the aud_cap node's info
|
||
e.g. PCM max_channels=2 sampling_rates=32000|44100|48000*/
|
||
int tmp = get_hdmi_cap_info(adev, &keys[13], temp_buf, AUDIO_HAL_CHAR_MAX_LEN);
|
||
if (tmp < 0) {
|
||
strcat(temp_buf, "This format is invalid");
|
||
}
|
||
ALOGI("ret: val %s,key %s \n", temp_buf, &keys[13]);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "hdmi_current_video_latency")) {
|
||
int v_ltcy = audio_patch_get_current_video_latency(adev);
|
||
AM_LOGI("v_ltcy(%d)", v_ltcy);
|
||
sprintf (temp_buf, "hdmi_current_video_latency=%d", v_ltcy);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "hdmi_current_audio_latency")) {
|
||
int a_ltcy = audio_patch_get_current_audio_latency(adev);
|
||
AM_LOGI("a_ltcy(%d)", a_ltcy);
|
||
sprintf (temp_buf, "hdmi_current_audio_latency=%d", a_ltcy);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "hdmi_audio_output_compensated")) {
|
||
sprintf (temp_buf, "hdmi_audio_output_compensated=%d", 1);
|
||
return strdup (temp_buf);
|
||
} else if (strstr (keys, "mpegh_audiosceneconfig") ) {
|
||
char *xmlbuf = aml_mpegh_getxmlsceneinfo(adev);
|
||
if (NULL != xmlbuf) {
|
||
int xmlsize = strlen(xmlbuf);
|
||
AM_LOGI("[size:%d]", xmlsize);
|
||
return strdup (xmlbuf);
|
||
}
|
||
return strdup ("");
|
||
} else if (strstr(keys, "is_dolby_atmos")) {
|
||
snprintf(temp_buf, AUDIO_HAL_CHAR_MAX_LEN, "is_dolby_atmos=%d", adev->audio_hal_info.is_dolby_atmos);
|
||
ALOGD("temp_buf %s", temp_buf);
|
||
return strdup(temp_buf);
|
||
} else if (strstr(keys, "mpegh_persistency_ctx")) {
|
||
if (adev->mpegh_ui_persistencemem) {
|
||
aml_mpegh_base64_encode(adev->mpegh_ui_persistencemem, adev->mpegh_ui_persistencememsize, adev);
|
||
//aml_dump_audio_bitstreams("/data/vendor/audiohal/get_mpegh_persistency_ctx.xml", adev->mpegh_base64_encode_mem, BASE64_BUFSIZE);
|
||
return strdup (adev->mpegh_base64_encode_mem);
|
||
}
|
||
} else if (strstr(keys, "hal_param_get_earc_status")) {
|
||
if (is_STB(adev)) {
|
||
AM_LOGE("STB is not support earc!");
|
||
} else {
|
||
int earc_status = -1;
|
||
earc_status = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_EARC_TX_ATTENDED_TYPE);
|
||
sprintf(temp_buf, "hal_param_get_earc_status=%d", earc_status);
|
||
return strdup(temp_buf);
|
||
}
|
||
} else if (adev->aml_ai_audio_type != eAmlAiAudioUnsupported) {
|
||
char *parm = NULL;
|
||
AmlAiValues ret_values;
|
||
parm = strstr(keys, "ai_audio_result");
|
||
if (parm) {
|
||
ret_values = aml_ai_audio_get_param(AML_AI_TYPE_AIAQ, AIAQ_RESULT);
|
||
sprintf(temp_buf, "aq_tuning:ai_audio_result=%d", ret_values.value);
|
||
return strdup(temp_buf);
|
||
}
|
||
parm = strstr(keys, "audio_enhancement_enable");
|
||
if (parm) {
|
||
ret_values = aml_ai_audio_get_param(AML_AI_TYPE_ENHANCEMENT, ENHANCEMENT_ENABLE);
|
||
sprintf(temp_buf, "audio_enhancement_enable=%d", ret_values.value);
|
||
return strdup(temp_buf);
|
||
}
|
||
parm = strstr(keys, "audio_enhancement_gain");
|
||
if (parm) {
|
||
ret_values = aml_ai_audio_get_param(AML_AI_TYPE_ENHANCEMENT, ENHANCEMENT_GAIN);
|
||
sprintf(temp_buf, "audio_enhancement_gain=%d", ret_values.value);
|
||
return strdup(temp_buf);
|
||
}
|
||
parm = strstr(keys, "audio_vocal_isolate_enable");
|
||
if (parm) {
|
||
ret_values = aml_ai_audio_get_param(AML_AI_TYPE_VOCAL_ISOLATE, VOCAL_ISOLATE_ENABLE);
|
||
sprintf(temp_buf, "audio_vocal_isolate_enable=%d", ret_values.value);
|
||
return strdup(temp_buf);
|
||
}
|
||
parm = strstr(keys, "audio_vocal_gain");
|
||
if (parm) {
|
||
ret_values = aml_ai_audio_get_param(AML_AI_TYPE_VOCAL_ISOLATE, VOCAL_ISOLATE_GAIN);
|
||
sprintf(temp_buf, "audio_vocal_gain=%f", ret_values.value_f);
|
||
return strdup(temp_buf);
|
||
}
|
||
} else if (strstr(keys, "HDMIIN audio samplerate")) {
|
||
int stable = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_HDMI_IN_AUDIO_STABLE);
|
||
if (!stable) {
|
||
AM_LOGW("HDMI in audio is not stable, get samplerate after stable");
|
||
return strdup("");
|
||
}
|
||
int cur_sr = aml_mixer_ctrl_get_int (&adev->alsa_mixer, AML_MIXER_ID_HDMI_IN_SAMPLERATE);
|
||
switch (cur_sr) {
|
||
case 0:
|
||
cur_sr = 0;
|
||
break;
|
||
case 1:
|
||
cur_sr = 32000;
|
||
break;
|
||
case 2:
|
||
cur_sr = 44100;
|
||
break;
|
||
case 3:
|
||
cur_sr = 48000;
|
||
break;
|
||
case 4:
|
||
cur_sr = 88200;
|
||
break;
|
||
case 5:
|
||
cur_sr = 96000;
|
||
break;
|
||
case 6:
|
||
cur_sr = 176400;
|
||
break;
|
||
case 7:
|
||
cur_sr = 192000;
|
||
break;
|
||
default:
|
||
cur_sr = 48000;
|
||
break;
|
||
}
|
||
sprintf (temp_buf, "HDMIIN audio samplerate=%d", cur_sr);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "HDMIIN Audio Type")) {
|
||
int cur_type = LPCM;
|
||
if (get_hdmiin_audio_mode(&adev->alsa_mixer) != HDMIIN_MODE_I2S) {
|
||
cur_type = aml_mixer_ctrl_get_int (&adev->alsa_mixer, AML_MIXER_ID_HDMIIN_AUDIO_TYPE);
|
||
} else if (aml_mixer_ctrl_get_int (&adev->alsa_mixer, AML_MIXER_ID_AUDIO_PCPD_MONITOR_ENABLE)) {
|
||
cur_type = aml_mixer_ctrl_get_int(&adev->alsa_mixer, AML_MIXER_ID_AUDIO_PCPD_MONITOR_DATA_TYPE);
|
||
}
|
||
sprintf (temp_buf, "HDMIIN Audio Type=%d", cur_type);
|
||
return strdup (temp_buf);
|
||
} else if (strstr(keys, "Audiopatch State")) {
|
||
int hdmi_state = 0;
|
||
struct aml_stream_out *aml_out = NULL;
|
||
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
|
||
aml_out = adev->active_outputs[i];
|
||
if (aml_out && HDMI_SRC == aml_out->source_type) {
|
||
hdmi_state = 1;
|
||
}
|
||
}
|
||
sprintf (temp_buf, "Audiopatch State=%d", hdmi_state);
|
||
return strdup (temp_buf);
|
||
} else {
|
||
ALOGE("%s() keys %s is not supported! TODO!\n", __func__, keys);
|
||
}
|
||
return strdup("");
|
||
}
|
||
|
||
static int adev_init_check (const struct audio_hw_device *dev __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int adev_set_voice_volume (struct audio_hw_device *dev __unused, float volume __unused)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static int adev_set_master_volume (struct audio_hw_device *dev, float volume)
|
||
{
|
||
if ((volume > 1.0) || (volume < 0.0) || (dev == NULL)) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
int i;
|
||
pthread_mutex_lock (&adev->lock);
|
||
adev->master_volume = volume;
|
||
if (adev->master_mute)
|
||
adev->master_mute = false;
|
||
for (i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
struct audio_stream_out *out = (struct audio_stream_out *)aml_out;
|
||
if (aml_out) {
|
||
out_set_volume_l(out, aml_out->volume_l_org, aml_out->volume_r_org);
|
||
}
|
||
}
|
||
ALOGI("%s() volume = %f, active_outport = %d", __FUNCTION__, volume, adev->active_outport);
|
||
pthread_mutex_unlock (&adev->lock);
|
||
return 0;
|
||
}
|
||
|
||
int adev_update_decoder_mute_state (struct audio_hw_device *dev)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
int i;
|
||
|
||
if (dev == NULL) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
AM_LOGI("decoder_mute:%d", adev->decoder_mute);
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
for (i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
if (aml_out && aml_out->stream_type != STREAM_AUX_INPUT) {
|
||
out_set_stream_mute((struct audio_stream_out *)aml_out, adev->decoder_mute, true);
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
return 0;
|
||
}
|
||
|
||
static int adev_get_master_volume (struct audio_hw_device *dev,
|
||
float *volume)
|
||
{
|
||
if ((volume == NULL) || (dev == NULL)) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
*volume = adev->master_volume;
|
||
ALOGI("%s() volume = %f", __FUNCTION__, *volume);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int adev_set_master_mute (struct audio_hw_device *dev, bool muted)
|
||
{
|
||
if (dev == NULL) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
ALOGI("%s, %d -> %d", __FUNCTION__, adev->master_mute, muted);
|
||
if (adev->master_mute != muted) {
|
||
if (muted) { //mute
|
||
adev_get_master_volume (dev, &adev->record_volume_before_mute); //Record the volume before mute
|
||
adev_set_master_volume (dev, 0); //set mute
|
||
} else {
|
||
adev_set_master_volume (dev, adev->record_volume_before_mute); //unmute
|
||
}
|
||
adev->master_mute = muted;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int adev_get_master_mute (struct audio_hw_device *dev, bool *muted)
|
||
{
|
||
if ((muted == NULL) || (dev == NULL)) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
*muted = adev->master_mute;
|
||
ALOGI("%s() muted = %d", __FUNCTION__, *muted);
|
||
|
||
return 0;
|
||
|
||
}
|
||
static int adev_set_mode (struct audio_hw_device *dev, audio_mode_t mode)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
ALOGD ("%s(%p, %d)", __FUNCTION__, dev, mode);
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
if (adev->mode != mode) {
|
||
adev->mode = mode;
|
||
select_mode (adev);
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int adev_set_mic_mute (struct audio_hw_device *dev, bool state)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
|
||
adev->mic_mute = state;
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int adev_get_mic_mute (const struct audio_hw_device *dev, bool *state)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
|
||
*state = adev->mic_mute;
|
||
|
||
return 0;
|
||
|
||
}
|
||
|
||
static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
|
||
const struct audio_config *config)
|
||
{
|
||
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
|
||
size_t size;
|
||
|
||
ALOGD("%s: enter: channel_mask(%#x) rate(%d) format(%#x)", __func__,
|
||
config->channel_mask, config->sample_rate, config->format);
|
||
|
||
if (check_input_parameters(config->sample_rate, config->format, channel_count, AUDIO_DEVICE_NONE) != 0) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
size = get_input_buffer_size(0, config->sample_rate, config->format, channel_count);
|
||
|
||
ALOGD("%s: exit: buffer_size = %zu", __func__, size);
|
||
|
||
return size;
|
||
}
|
||
|
||
static int adev_open_input_stream(struct audio_hw_device *dev,
|
||
audio_io_handle_t handle __unused,
|
||
audio_devices_t devices,
|
||
struct audio_config *config,
|
||
struct audio_stream_in **stream_in,
|
||
audio_input_flags_t flags __unused,
|
||
const char *address __unused,
|
||
audio_source_t source)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
struct aml_stream_in *in;
|
||
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
|
||
int ret = 0;
|
||
|
||
AM_LOGD("%s: enter: devices(%#x) channel_mask(%#x) rate(%d) format(%#x) source(%d)", __func__,
|
||
devices, config->channel_mask, config->sample_rate, config->format, source);
|
||
|
||
if ((ret = check_input_parameters(config->sample_rate, config->format, channel_count, devices)) != 0) {
|
||
if (-ENOSYS == ret) {
|
||
AM_LOGE(" check_input_parameters input config Not Supported, and set to Default config(48000,2,PCM_16_BIT)");
|
||
config->sample_rate = DEFAULT_OUT_SAMPLING_RATE;
|
||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
} else {
|
||
return -EINVAL;
|
||
}
|
||
|
||
}
|
||
|
||
in = (struct aml_stream_in *)aml_audio_calloc(1, sizeof(struct aml_stream_in));
|
||
if (!in) {
|
||
AM_LOGE(" calloc fail, return!!!");
|
||
return -ENOMEM;
|
||
}
|
||
in->device = devices & ~AUDIO_DEVICE_BIT_IN;
|
||
in->input_type = audio_input_get_type(in->device);
|
||
|
||
if (channel_count == 1)
|
||
// in fact, this value should be AUDIO_CHANNEL_OUT_BACK_LEFT(16u) according to VTS codes,
|
||
// but the macroname can be confusing, so I'd like to set this value to
|
||
// AUDIO_CHANNEL_IN_FRONT(16u) instead of AUDIO_CHANNEL_OUT_BACK_LEFT.
|
||
config->channel_mask = AUDIO_CHANNEL_IN_FRONT;
|
||
else if (channel_count == 2) {
|
||
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
if (in->device & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
|
||
config->channel_mask = AUDIO_CHANNEL_IN_2POINT0POINT2;
|
||
}
|
||
}
|
||
if (in->device & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
|
||
if (access(AML_AEC_LIB_PATH, R_OK) != 0) {
|
||
AM_LOGE("libAudioSignalProcess.so not found.");
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
in->stream.common.get_sample_rate = in_get_sample_rate;
|
||
in->stream.common.set_sample_rate = in_set_sample_rate;
|
||
in->stream.common.get_buffer_size = in_get_buffer_size;
|
||
in->stream.common.get_channels = in_get_channels;
|
||
in->stream.common.get_format = in_get_format;
|
||
in->stream.common.set_format = in_set_format;
|
||
in->stream.common.standby = in_standby;
|
||
in->stream.common.dump = in_dump;
|
||
in->stream.common.set_parameters = in_set_parameters;
|
||
in->stream.common.get_parameters = in_get_parameters;
|
||
in->stream.set_gain = in_set_gain;
|
||
in->stream.read = in_read;
|
||
in->stream.get_capture_position = in_get_capture_position;
|
||
in->stream.get_input_frames_lost = in_get_input_frames_lost;
|
||
in->stream.get_active_microphones = in_get_active_microphones;
|
||
in->stream.common.add_audio_effect = in_add_audio_effect;
|
||
in->stream.common.remove_audio_effect = in_remove_audio_effect;
|
||
|
||
in->unique_ID = adev->next_unique_ID;
|
||
adev->next_unique_ID++;
|
||
in->dev = adev;
|
||
in->standby = 1;
|
||
|
||
in->requested_rate = config->sample_rate;
|
||
in->hal_channel_mask = config->channel_mask;
|
||
in->hal_format = config->format;
|
||
|
||
in->config.channels = channel_count;
|
||
in->source = source;
|
||
if (source == AUDIO_SOURCE_ECHO_REFERENCE) {
|
||
in->config.rate = PLAYBACK_CODEC_SAMPLING_RATE;
|
||
} else if (source == AUDIO_SOURCE_MIXER_OUT || source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
audio_unit_acquire_port((audio_unit *)adev->mixer_unit, &in->capture_port, AUDIO_PORT_OUTPUT);
|
||
}
|
||
if (source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
aml_encoder_config_prepare(&adev->encoder_ctx.enc_cfg);
|
||
if ((ret = aml_encoder_init(&adev->encoder_ctx.enc_handle, &adev->encoder_ctx.enc_cfg)) == 0) {
|
||
aml_enc_info_t enc_info = {0};
|
||
aml_encoder_getinfo(adev->encoder_ctx.enc_handle, AML_ENC_FRAME_SIZE, &enc_info);
|
||
adev->encoder_ctx.frame_len = enc_info.frame_size;
|
||
AM_LOGD("aml_encoder_init ok, frame_len %d", enc_info.frame_size);
|
||
} else
|
||
AM_LOGE("aml_encoder_init fail, ret: %d", ret);
|
||
}
|
||
|
||
switch (config->format) {
|
||
case AUDIO_FORMAT_PCM_16_BIT:
|
||
in->config.format = PCM_FORMAT_S16_LE;
|
||
break;
|
||
case AUDIO_FORMAT_PCM_32_BIT:
|
||
in->config.format = PCM_FORMAT_S32_LE;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
in->buffer = aml_audio_malloc(in->config.period_size * audio_stream_in_frame_size(&in->stream));
|
||
if (!in->buffer) {
|
||
ret = -ENOMEM;
|
||
ALOGE(" malloc fail, goto err!!!");
|
||
goto err;
|
||
}
|
||
memset(in->buffer, 0, in->config.period_size * audio_stream_in_frame_size(&in->stream));
|
||
|
||
if (in->device & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
|
||
adev->aml_aec = aec_create(AML_AEC_MIC_CHANNEL_NUM, pcm_config_aec);
|
||
}
|
||
*stream_in = &in->stream;
|
||
|
||
ALOGD("%s: exit", __func__);
|
||
return 0;
|
||
err:
|
||
#ifndef ANDROID_BUILD
|
||
if (in->resampler) {
|
||
release_resampler(in->resampler);
|
||
in->resampler = NULL;
|
||
}
|
||
#endif
|
||
if (in->buffer) {
|
||
aml_audio_free(in->buffer);
|
||
in->buffer = NULL;
|
||
}
|
||
aml_audio_free(in);
|
||
*stream_in = NULL;
|
||
return ret;
|
||
}
|
||
|
||
static void adev_close_input_stream(struct audio_hw_device *dev,
|
||
struct audio_stream_in *stream)
|
||
{
|
||
#ifndef BUILD_LINUX
|
||
if (remoteDeviceOnline()) {
|
||
kehwin_adev_close_input_stream(dev,stream);
|
||
return;
|
||
}
|
||
#endif
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
struct aml_stream_in *in = (struct aml_stream_in *)stream;
|
||
|
||
ALOGD("%s: enter: dev(%p) stream(%p)", __func__, dev, stream);
|
||
|
||
in_standby(&stream->common);
|
||
|
||
|
||
#ifndef ANDROID_BUILD
|
||
if (in->resampler) {
|
||
release_resampler(in->resampler);
|
||
in->resampler = NULL;
|
||
}
|
||
#endif
|
||
pthread_mutex_lock (&in->lock);
|
||
if (in->buffer) {
|
||
aml_audio_free(in->buffer);
|
||
in->buffer = NULL;
|
||
}
|
||
pthread_mutex_unlock (&in->lock);
|
||
|
||
if (in->proc_buf) {
|
||
aml_audio_free(in->proc_buf);
|
||
}
|
||
if (in->ref_buf) {
|
||
aml_audio_free(in->ref_buf);
|
||
}
|
||
|
||
if (in->device & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
|
||
aec_destroy(adev->aml_aec);
|
||
}
|
||
|
||
if (in->source == AUDIO_SOURCE_MIXER_OUT || in->source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
aml_port_command(in->capture_port, AUDIO_PORT_FLUSH, NULL);
|
||
audio_unit_release_port(adev->mixer_unit, aml_port_get_ID(in->capture_port), AUDIO_PORT_OUTPUT);
|
||
}
|
||
if (in->source == AUDIO_SOURCE_ENCODER_OUT) {
|
||
aml_encoder_release(adev->encoder_ctx.enc_handle);
|
||
}
|
||
aml_audio_free(stream);
|
||
ALOGD("%s: exit", __func__);
|
||
return;
|
||
}
|
||
|
||
/* must be called with hw device and output stream mutexes locked */
|
||
int do_output_standby_l(struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
|
||
ALOGI("[%s:%d] stream stream_type:%s", __func__, __LINE__,
|
||
streamtype2Str(aml_out->stream_type));
|
||
|
||
if (adev->dolby_lib_type != eDolbyMS12Lib) {
|
||
aml_audio_spdif_output_close_all();
|
||
}
|
||
|
||
aml_out->standby= 1;
|
||
|
||
if (true == aml_out->pause_status) {
|
||
aml_out->pause_status = false;//clear pause status
|
||
/* Avoid the inconsistent pause status between ms12 and audiohal, causes ms12 unable to resume */
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if ((adev->ms12.dolby_ms12_enable == true) &&
|
||
(aml_out->stream_type == STREAM_MAIN_INPUT)) {
|
||
dolby_ms12_main_resume((struct audio_stream_out *)stream);
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int out_standby_new(struct audio_stream *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *)stream;
|
||
int status;
|
||
|
||
ALOGD("%s: enter", __func__);
|
||
aml_audio_trace_int("out_standby_new", 1);
|
||
if (aml_out->standby) {
|
||
ALOGI("already standby, do nothing");
|
||
aml_audio_trace_int("out_standby_new", 0);
|
||
return 0;
|
||
}
|
||
|
||
#if 0 // close this part, put the sleep to ms12 dolby_ms12_main_flush().
|
||
if (continuous_mode(aml_out->dev)
|
||
&& (aml_out->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
|
||
//1.audio easing duration is 32ms,
|
||
//2.one loop for schedule_run cost about 32ms(contains the hardware costing),
|
||
//3.if [pause, flush] too short, means it need more time to do audio easing
|
||
//so, the delay time for 32ms(pause is completed after audio easing is done) is enough.
|
||
//aml_audio_sleep(64000);
|
||
}
|
||
#endif
|
||
pthread_mutex_lock (&aml_out->dev->lock);
|
||
pthread_mutex_lock (&aml_out->lock);
|
||
status = do_output_standby_l(stream);
|
||
pthread_mutex_unlock (&aml_out->lock);
|
||
pthread_mutex_unlock (&aml_out->dev->lock);
|
||
ALOGI("%s exit", __func__);
|
||
aml_audio_trace_int("out_standby_new", 0);
|
||
|
||
return status;
|
||
}
|
||
|
||
audio_format_t get_output_format (struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
audio_format_t output_format = aml_out->hal_internal_format;
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
output_format = adev->sink_format;
|
||
} else if (eDolbyDcvLib == adev->dolby_lib_type) {
|
||
if (adev->hdmi_format > 0) {
|
||
if (adev->dual_spdif_support) {
|
||
if (aml_out->hal_internal_format == AUDIO_FORMAT_E_AC3 && adev->sink_format == AUDIO_FORMAT_E_AC3) {
|
||
if (adev->dolby_decode_enable == 1) {
|
||
output_format = AUDIO_FORMAT_AC3;
|
||
} else {
|
||
output_format = AUDIO_FORMAT_E_AC3;
|
||
}
|
||
} else {
|
||
output_format = adev->sink_format;
|
||
}
|
||
} else {
|
||
output_format = adev->sink_format;
|
||
}
|
||
} else
|
||
output_format = adev->sink_format;
|
||
}
|
||
|
||
return output_format;
|
||
}
|
||
|
||
bool is_low_latency_mode(struct aml_audio_device *aml_dev)
|
||
{
|
||
return aml_dev->low_latency_mode;
|
||
}
|
||
|
||
void update_low_latency_mode(struct aml_audio_device *aml_dev)
|
||
{
|
||
bool current_low_latency_mode = false;
|
||
struct aml_audio_patch * hdmi_patch = get_dev_patch_by_source(aml_dev, SRC_HDMIIN);
|
||
// Simultaneously meeting the following three conditions is the low latency mode
|
||
// 1.hdmi source
|
||
// 2.format is pcm
|
||
// 3.pic_mode is PQ_GAME
|
||
if (hdmi_patch && PQ_GAME == get_dev_pic_mode() && !hdmi_patch->IEC61937_format) {
|
||
current_low_latency_mode = true;
|
||
}
|
||
if (aml_dev->low_latency_mode != current_low_latency_mode) {
|
||
AM_LOGI("low_latency_mode changed from %d to %d, useSubMix %d",
|
||
aml_dev->low_latency_mode, current_low_latency_mode, aml_dev->useSubMix);
|
||
aml_dev->low_latency_mode_changed = true;
|
||
aml_dev->low_latency_mode = current_low_latency_mode;
|
||
//reconfig_dev_pic_mode_in(aml_dev, true);
|
||
if (aml_dev->useSubMix) {
|
||
reconfig_dev_pic_mode_out(true);
|
||
}
|
||
}
|
||
}
|
||
|
||
int reconfig_encoder(struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *)stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
AM_LOGI("dolby_lib_type(%d) is_dts(%d) dts_lib_type(%d) active_outport(%d)",
|
||
adev->dolby_lib_type, is_dts_format(aml_out->hal_internal_format),
|
||
get_dts_lib_type(), adev->active_outport);
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
audiohal_send_msg_2_ms12(&adev->ms12, MS12_MESG_TYPE_RESET_MS12_ENCODER);
|
||
} else if (is_dts_format(aml_out->hal_internal_format) &&
|
||
get_dts_lib_type() == eDTSXLib) {
|
||
//The dtsx lib will determine the output format based on the sink device's capability
|
||
//and whether it is passthrough. So when sink device's capability or passthrough option
|
||
//change, we need reset decoder to reconfig encoder.
|
||
if (dtsx_is_need_reset_decoder(stream)) {
|
||
aml_decoder_reset_wrapper(stream);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
//The dtsx lib will determine the output format based on the sink device's capability
|
||
//and whether it is passthrough. So when sink device's capability or passthrough option
|
||
//change, we need reset decoder.
|
||
int aml_decoder_reset_wrapper(struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *)stream;
|
||
int ret = -1;
|
||
|
||
/*if decoder is init, we close it first*/
|
||
if (aml_out->aml_dec) {
|
||
aml_decoder_release(aml_out->aml_dec);
|
||
aml_out->aml_dec = NULL;
|
||
}
|
||
|
||
aml_audio_spdif_output_close_all();
|
||
|
||
ret = aml_decoder_init_wrapper(stream);
|
||
|
||
AM_LOGI("ret=%d", ret);
|
||
return ret;
|
||
}
|
||
|
||
int aml_decoder_init_wrapper(struct audio_stream_out *stream)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *)stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
int ret = -1;
|
||
memset(&aml_out->dec_config, 0, sizeof(aml_dec_config_t));
|
||
AM_LOGI("+<in>");
|
||
|
||
/*prepare the decoder config*/
|
||
ret = aml_decoder_config_prepare(stream, aml_out->hal_internal_format, &aml_out->dec_config);
|
||
|
||
if (ret < 0) {
|
||
AM_LOGE("config decoder error");
|
||
return ret;
|
||
}
|
||
|
||
ret = aml_decoder_init(&aml_out->aml_dec, aml_out->hal_internal_format, (aml_dec_config_t *)&aml_out->dec_config);
|
||
if (ret < 0) {
|
||
AM_LOGE("aml_decoder_init failed");
|
||
return ret;
|
||
}
|
||
|
||
if (eDolbyMS12Lib != adev->dolby_lib_type) {
|
||
pthread_mutex_lock(&adev->lock);
|
||
/*coverity[missing_lock]:adev->hw_mixer.start_buf does not need to be lock*/
|
||
if (!adev->hw_mixer.start_buf) {
|
||
aml_hw_mixer_init(&adev->hw_mixer);
|
||
} else {
|
||
aml_hw_mixer_reset(&adev->hw_mixer);
|
||
}
|
||
pthread_mutex_unlock(&adev->lock);
|
||
}
|
||
|
||
AM_LOGI("-<out> init success! ret=%d", ret);
|
||
return ret;
|
||
}
|
||
|
||
|
||
ssize_t mixer_main_buffer_write(struct audio_stream_out *stream, struct audio_buffer *abuffer)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = NULL;
|
||
|
||
int return_bytes = 0;
|
||
output_function parser_next_func = NULL;
|
||
|
||
if (!stream) {
|
||
AM_LOGE("invalid stream %p", stream);
|
||
return -1;
|
||
}
|
||
if (false == check_audio_buffer_valid(abuffer)) {
|
||
AM_LOGE("audio buffer checked fail");
|
||
return -1;
|
||
}
|
||
|
||
adev = aml_out->dev;
|
||
|
||
if (adev->debug_flag > 1) {
|
||
AM_LOGI("out:%p bytes:%"PRId32",format:%#x,with_header:%d",
|
||
aml_out, abuffer->size, abuffer->format,aml_out->with_header);
|
||
AM_LOGI("original_format:%#x, stream_type:%s",
|
||
abuffer->original_format, streamtype2Str(aml_out->stream_type));
|
||
}
|
||
|
||
if (get_debug_value(AML_DUMP_AUDIOHAL_ABUFFER)) {
|
||
aml_dump_audio_buffer_with_id("input_main.raw", abuffer, aml_out->unique_ID);
|
||
}
|
||
|
||
if (aml_out->standby && (eDolbyMS12Lib == adev->dolby_lib_type_last || !adev->useSubMix)) {
|
||
AM_LOGI("standby to unstandby");
|
||
aml_out->standby = false;
|
||
}
|
||
|
||
/* here to check if the audio output routing changed. */
|
||
if (adev->out_device != aml_out->out_device) {
|
||
AM_LOGI("output routing changed, adev_dev:%#x, out_dev:%#x",
|
||
adev->out_device, aml_out->out_device);
|
||
aml_out->out_device = adev->out_device;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
parser_next_func = aml_audio_ms12_render;
|
||
} else {
|
||
if (is_dts_format(aml_out->hal_internal_format) && get_dts_lib_type() == eDTSXLib) {
|
||
parser_next_func = aml_audio_nonms12_dec_render;
|
||
} else {
|
||
parser_next_func = aml_audio_nonms12_render;
|
||
}
|
||
}
|
||
|
||
//usac aac(xHE-AAC) doesn't need the parser
|
||
if ((AUDIO_FORMAT_HE_AAC_V2 == aml_out->hal_format || AUDIO_FORMAT_HE_AAC_V1 == aml_out->hal_format) && MEDIA_SRC == aml_out->source_type) {
|
||
return_bytes = parser_next_func(stream, abuffer);
|
||
if (return_bytes != abuffer->size) {
|
||
AM_LOGE("return err return_bytes(%d) != write_size(%"PRId32"), need check!!", return_bytes, abuffer->size);
|
||
}
|
||
} else {
|
||
return_bytes = audio_parser_process(stream, abuffer, parser_next_func);
|
||
}
|
||
|
||
aml_out->input_bytes_size += return_bytes;
|
||
aml_out->last_pts = abuffer->pts;
|
||
|
||
if (return_bytes > 0) {
|
||
size_t frame_size = audio_stream_out_frame_size((const struct audio_stream_out *)stream);
|
||
if (frame_size > 0) {
|
||
aml_out->frame_write_sum += (size_t)return_bytes / frame_size;
|
||
}
|
||
clock_gettime(CLOCK_MONOTONIC, &aml_out->timestamp);
|
||
aml_out->lasttimestamp.tv_sec = aml_out->timestamp.tv_sec;
|
||
aml_out->lasttimestamp.tv_nsec = aml_out->timestamp.tv_nsec;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && adev->ms12.dolby_ms12_enable) {
|
||
unsigned int alsa_latency_frame = adev->ms12.latency_frame;
|
||
if (adev->compensate_video_enable) {
|
||
alsa_latency_frame = 0;
|
||
}
|
||
if (frame_size > 0 && aml_out->ms12_dec_handle) {
|
||
uint64_t main_bytes_consumed = dolby_ms12_get_main_bytes_consumed(
|
||
(struct audio_stream_out *)stream);
|
||
aml_out->last_frames_position = main_bytes_consumed / frame_size;
|
||
} else {
|
||
aml_out->last_frames_position = aml_out->frame_write_sum;
|
||
}
|
||
if (aml_out->last_frames_position >= alsa_latency_frame) {
|
||
aml_out->last_frames_position -= alsa_latency_frame;
|
||
}
|
||
AM_LOGI_IF(adev->debug_flag > 1,
|
||
"main presentation %"PRIu64" frame_write_sum %"PRIu64" alsa_latency %u",
|
||
aml_out->last_frames_position, aml_out->frame_write_sum, alsa_latency_frame);
|
||
}
|
||
}
|
||
AM_LOGI_IF(adev->debug_flag, "return %d!", return_bytes);
|
||
return return_bytes;
|
||
}
|
||
|
||
ssize_t mixer_aux_buffer_write(struct audio_stream_out *stream, struct audio_buffer *abuffer)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = NULL;
|
||
const void *buffer = NULL;
|
||
size_t bytes = 0, frame_size = 0, in_frames = 0, bytes_remaining = 0, bytes_written = 0;
|
||
int ret = 0, retry = 0;
|
||
unsigned int alsa_latency_frame = 0;
|
||
bool is_deep_buf = false;
|
||
struct timespec ts;
|
||
struct audio_buffer abuf;
|
||
|
||
if (!stream) {
|
||
AM_LOGE ("invalid stream %p\n", stream);
|
||
return -1;
|
||
}
|
||
if (false == check_audio_buffer_valid(abuffer)) {
|
||
AM_LOGE("audio buffer checked fail");
|
||
return -1;
|
||
}
|
||
adev = aml_out->dev;
|
||
buffer = abuffer->buffer;
|
||
bytes = abuffer->size;
|
||
frame_size = audio_stream_out_frame_size(stream);
|
||
in_frames = bytes / frame_size;
|
||
bytes_remaining = bytes;
|
||
is_deep_buf = (STREAM_DEEP_INPUT == aml_out->stream_type) ? true : false;
|
||
memcpy(&abuf, abuffer, sizeof(abuf));
|
||
|
||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||
AM_LOGI_IF(adev->debug_flag, "[%lld.%9ld -- %d] mixer_aux_buffer_write %zu, is_deep_buf:%d", (long long)ts.tv_sec, ts.tv_nsec, gettid(), bytes, is_deep_buf);
|
||
|
||
if (adev->debug_flag > 1) {
|
||
ALOGD("%s:%d size:%zu, dolby_lib_type:0x%x, frame_size:%zu, is_deep_buf:%d",
|
||
__func__, __LINE__, bytes, adev->dolby_lib_type, frame_size, is_deep_buf);
|
||
}
|
||
|
||
if (aml_out->standby) {
|
||
ALOGI("%s(), standby to unstandby", __func__);
|
||
aml_out->audio_data_handle_state = AUDIO_DATA_HANDLE_START;
|
||
aml_out->standby = false;
|
||
}
|
||
|
||
if (get_debug_value(AML_DUMP_AUDIOHAL_IN)) {
|
||
aml_dump_audio_bitstreams_with_id("input_aux.raw", buffer, bytes, aml_out->unique_ID);
|
||
}
|
||
|
||
// convert data to 48KHz
|
||
if (aml_out->hal_rate != OUTPUT_ALSA_SAMPLERATE ) {
|
||
audio_resample_config_t cfg = {
|
||
.aformat = aml_out->hal_internal_format,
|
||
.channels = aml_out->hal_ch,
|
||
.input_sr = aml_out->hal_rate,
|
||
.output_sr = OUTPUT_ALSA_SAMPLERATE,
|
||
};
|
||
ret = aml_audio_resample_process_ex(&aml_out->resample_handle, &cfg, buffer, bytes);
|
||
if (ret != 0) {
|
||
ALOGE("aml_audio_resample_process_ex failed");
|
||
} else {
|
||
buffer = aml_out->resample_handle->resample_buffer;
|
||
bytes_remaining = aml_out->resample_handle->resample_size;
|
||
}
|
||
}
|
||
|
||
if (AUDIO_FORMAT_MPEGH == adev->optical_format) {
|
||
struct aml_stream_out *aml_out = NULL;
|
||
bool mpegh_stream_exist = false;
|
||
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
|
||
aml_out = adev->active_outputs[i];
|
||
if (aml_out && is_mpegh_format(aml_out->hal_internal_format)) {
|
||
mpegh_stream_exist = true;
|
||
break;
|
||
}
|
||
}
|
||
if (mpegh_stream_exist) {
|
||
int used_size;
|
||
if (0 != aml_system_sound_process(aml_out->aml_dec, abuffer, &used_size)) {
|
||
AM_LOGE("aml_system_sound_process fail");
|
||
}
|
||
}
|
||
|
||
}/* else */
|
||
|
||
aml_out->input_bytes_size += bytes;
|
||
aml_out->frame_write_sum += in_frames;
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
if (adev->a2dp_no_reconfig_ms12 > 0) {
|
||
uint64_t curr = aml_audio_get_systime();
|
||
if (adev->a2dp_no_reconfig_ms12 <= curr)
|
||
adev->a2dp_no_reconfig_ms12 = 0;
|
||
}
|
||
|
||
/* audio zero data detect, and do fade in */
|
||
if (adev->is_netflix) {
|
||
aml_audio_data_handle(stream, buffer, bytes_remaining);
|
||
}
|
||
|
||
// SUSP-008-TC2 Test Steps 8 pop
|
||
if (adev->is_netflix_hide) {
|
||
audio_fade_func((void *)buffer, bytes_remaining, 0);
|
||
adev->netflix_hide_fadeout_startTime = aml_audio_get_systime()/1000;
|
||
adev->is_netflix_hide = false;
|
||
ALOGI("%s aux audio fade out. starTime:%"PRIu64"", __func__, adev->netflix_hide_fadeout_startTime);
|
||
} else {
|
||
if (adev->netflix_hide_fadeout_startTime) {
|
||
uint64_t currentTime = aml_audio_get_systime()/1000;
|
||
if (currentTime - adev->netflix_hide_fadeout_startTime < 500) {
|
||
memset((void *)buffer, 0, bytes_remaining);
|
||
} else {
|
||
adev->netflix_hide_fadeout_startTime = 0;
|
||
ALOGI("%s aux audio memset done. currentTime:%"PRIu64"", __func__, currentTime);
|
||
}
|
||
}
|
||
}
|
||
abuf.buffer = buffer;
|
||
abuf.size = bytes_remaining;
|
||
aml_ms12_loudness_input_control(aml_out, &abuf);
|
||
|
||
while (bytes_remaining && adev->ms12.dolby_ms12_enable && retry < 20) {
|
||
size_t used_size = 0;
|
||
if (is_deep_buf) {
|
||
if (adev->enable_deep_unit) {
|
||
if (aml_port_get_room(aml_out->deep_inport) > bytes_remaining) {
|
||
used_size = aml_port_push_buffer(aml_out->deep_inport, &abuf);
|
||
}
|
||
ret = 0;
|
||
//AM_LOGI("deep unit write %zu bytes", used_size);
|
||
} else {
|
||
ret = dolby_ms12_deep_buffer_process(stream, (char *)buffer + bytes_written, bytes_remaining, &used_size);
|
||
}
|
||
} else {
|
||
ret = dolby_ms12_system_process(stream, (char *)buffer + bytes_written, bytes_remaining, &used_size);
|
||
}
|
||
if (!ret) {
|
||
bytes_remaining -= used_size;
|
||
bytes_written += used_size;
|
||
retry = 0;
|
||
}
|
||
retry++;
|
||
if (bytes_remaining) {
|
||
//usleep(bytes_remaining * 1000000 / frame_size / out_get_sample_rate(&stream->common));
|
||
aml_audio_sleep(5000);
|
||
}
|
||
}
|
||
} else {
|
||
struct aml_stream_out *out_stream = NULL;
|
||
bool dts_stream_exist = false;
|
||
for (int i = 0 ; i < STREAM_NUM_MAX; i++) {
|
||
out_stream = adev->active_outputs[i];
|
||
if (out_stream && is_dts_format(out_stream->hal_internal_format)) {
|
||
dts_stream_exist = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (adev->useSubMix && (!dts_stream_exist || (dts_stream_exist && !adev->hw_mixer.start_buf))) {
|
||
bytes_written = out_write_direct_pcm(stream, buffer, bytes_remaining);
|
||
} else if (adev->hw_mixer.start_buf) {
|
||
//This data is for mixing with DTS. The output format(16 or 32 bits) of DTS is determined by adev->audio_process_bitwidth,
|
||
//Therefore, the data format will be converted to the DTS output format here to facilitate subsequent mixing
|
||
if (audio_bytes_per_sample(aml_out->hal_format) != adev->audio_process_bitwidth / 8) {
|
||
audio_format_t dst_format = (adev->audio_process_bitwidth==32) ? AUDIO_FORMAT_PCM_32_BIT:AUDIO_FORMAT_PCM_16_BIT;
|
||
audio_format_t src_format = aml_out->hal_format;
|
||
int src_samples = bytes_remaining / audio_bytes_per_sample(src_format);
|
||
int need_size = src_samples * audio_bytes_per_sample(dst_format);
|
||
if (adev->hw_mixer.tmp_buf_size < need_size) {
|
||
AM_LOGI("realloc hw_mixer.tmp_buf from (%d) to (%u)", adev->hw_mixer.tmp_buf_size, need_size);
|
||
adev->hw_mixer.tmp_buf = aml_audio_realloc(adev->hw_mixer.tmp_buf, need_size);
|
||
if (adev->hw_mixer.tmp_buf == NULL) {
|
||
AM_LOGE("realloc for hw_mixer.tmp_buf(%u) failed", need_size);
|
||
return bytes;
|
||
}
|
||
adev->hw_mixer.tmp_buf_size = need_size;
|
||
}
|
||
memcpy_by_audio_format(adev->hw_mixer.tmp_buf, dst_format, (const void *)buffer, src_format, src_samples);
|
||
bytes_written = aml_hw_mixer_write(&adev->hw_mixer, adev->hw_mixer.tmp_buf, need_size);
|
||
} else {
|
||
bytes_written = aml_hw_mixer_write(&adev->hw_mixer, buffer, bytes_remaining);
|
||
}
|
||
} else {
|
||
AM_LOGE("This case shouldn't have happened, there must be something wrong");
|
||
}
|
||
}
|
||
|
||
clock_gettime (CLOCK_MONOTONIC, &aml_out->timestamp);
|
||
aml_out->lasttimestamp.tv_sec = aml_out->timestamp.tv_sec;
|
||
aml_out->lasttimestamp.tv_nsec = aml_out->timestamp.tv_nsec;
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/*
|
||
mixer_aux_buffer_write is called when the hw write is called another thread,for example
|
||
main write thread or ms12 thread. aux audio is coming from the audioflinger mixed thread.
|
||
we need calculate the system buffer latency in ms12 also with the alsa out latency.It is
|
||
48K 2 ch 16 bit audio.
|
||
*/
|
||
alsa_latency_frame = adev->ms12.latency_frame;
|
||
int system_latency = 0;
|
||
if (is_deep_buf) {
|
||
system_latency = dolby_ms12_get_deep_buffer_avail_frames(NULL);
|
||
} else {
|
||
if (adev->dev_ms12_version == eDolbyMS12_V282) {
|
||
system_latency = dolby_ms12_get_system_buffer_avail(NULL);
|
||
} else {
|
||
system_latency = dolby_ms12_get_system_buffer_avail(NULL) / frame_size;
|
||
}
|
||
}
|
||
|
||
if (adev->compensate_video_enable) {
|
||
alsa_latency_frame = 0;
|
||
}
|
||
aml_out->last_frames_position = aml_out->frame_write_sum - system_latency;
|
||
if (aml_out->last_frames_position >= alsa_latency_frame) {
|
||
aml_out->last_frames_position -= alsa_latency_frame;
|
||
}
|
||
if (adev->debug_flag > 1) {
|
||
AM_LOGI("is_deep_buf:%d stream audio presentation %"PRIu64" latency_frame %d.ms12 system latency_frame %d,total frame=%" PRId64 " %" PRId64 " ms",
|
||
is_deep_buf, aml_out->last_frames_position, alsa_latency_frame, system_latency,aml_out->frame_write_sum, aml_out->frame_write_sum/48);
|
||
}
|
||
}
|
||
|
||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||
AM_LOGI_IF(adev->debug_flag && !is_deep_buf, "[%lld.%9ld] write %zu bytes, system level %zu ms", (long long)ts.tv_sec, ts.tv_nsec, bytes, dolby_ms12_get_system_buffer_avail(NULL) / frame_size / 48);
|
||
AM_LOGI_IF(adev->debug_flag && is_deep_buf, "[%lld.%9ld] write %zu bytes, deep_buffer level %d ms", (long long)ts.tv_sec, ts.tv_nsec, bytes, dolby_ms12_get_deep_buffer_avail_frames(NULL) / 48);
|
||
|
||
return bytes;
|
||
|
||
}
|
||
ssize_t mixer_ad_buffer_write (struct audio_stream_out *stream, struct audio_buffer *abuffer)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = NULL;
|
||
int32_t return_size = 0;
|
||
struct audio_buffer abuffer_out = {0};
|
||
|
||
if (!stream) {
|
||
AM_LOGE ("invalid stream %p\n", stream);
|
||
return -1;
|
||
}
|
||
if (false == check_audio_buffer_valid(abuffer)) {
|
||
AM_LOGE("audio buffer checked fail");
|
||
return -1;
|
||
}
|
||
adev = aml_out->dev;
|
||
|
||
memcpy(&abuffer_out, abuffer, sizeof(abuffer_out));
|
||
|
||
AM_LOGI_IF(adev->debug_flag, "out %p, useSubMix:%d, db_lib:%d, original_format:0x%x, format:0x%x, stream_type:0x%x, in %"PRId32, aml_out,
|
||
adev->useSubMix, adev->dolby_lib_type, abuffer->original_format, abuffer->format, aml_out->stream_type, abuffer->size);
|
||
|
||
if (aml_out->standby) {
|
||
aml_out->standby = false;
|
||
}
|
||
|
||
return_size = audio_parser_process(stream, abuffer, aml_audio_ad_render);
|
||
|
||
AM_LOGI_IF(adev->debug_flag, "out %p, return %d!\n", aml_out, return_size);
|
||
return return_size;
|
||
}
|
||
|
||
ssize_t mixer_app_buffer_write(struct audio_stream_out *stream, struct audio_buffer *abuffer)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = NULL;
|
||
int ret = 0;
|
||
int buffer_frames = 0;
|
||
const void *buffer = NULL;
|
||
size_t bytes = 0, frame_size = 0, bytes_remaining = 0, bytes_written = 0;
|
||
int retry = 100;
|
||
|
||
if (!stream) {
|
||
AM_LOGE ("invalid stream %p\n", stream);
|
||
return -1;
|
||
}
|
||
if (false == check_audio_buffer_valid(abuffer)) {
|
||
AM_LOGE("audio buffer checked fail");
|
||
return -1;
|
||
}
|
||
adev = aml_out->dev;
|
||
buffer = abuffer->buffer;
|
||
bytes = abuffer->size;
|
||
frame_size = audio_stream_out_frame_size(stream);
|
||
bytes_remaining = bytes;
|
||
|
||
if (adev->debug_flag) {
|
||
ALOGD("[%s:%d] size:%zu, frame_size:%zu", __func__, __LINE__, bytes, frame_size);
|
||
}
|
||
|
||
if (get_debug_value(AML_DUMP_AUDIOHAL_IN)) {
|
||
aml_dump_audio_bitstreams_with_id("input_app.raw", buffer, bytes, aml_out->unique_ID);
|
||
}
|
||
|
||
if (eDolbyMS12Lib != adev->dolby_lib_type) {
|
||
if (!adev->useSubMix) {
|
||
AM_LOGW("Submix is disable now, app write isn't supported");
|
||
return bytes;
|
||
}
|
||
AM_LOGI_IF(adev->debug_flag, "dolby_lib_type:%d, is not ms12, app write to nonms12", adev->dolby_lib_type);
|
||
int return_bytes = out_write_direct_pcm(stream, buffer, bytes);
|
||
return return_bytes;
|
||
}
|
||
|
||
if (is_bypass_dolbyms12(stream)) {
|
||
ALOGW("[%s:%d] is_bypass_dolbyms12, not support app write", __func__, __LINE__);
|
||
return -1;
|
||
}
|
||
|
||
// convert data to 48KHz
|
||
if (aml_out->hal_rate != OUTPUT_ALSA_SAMPLERATE ) {
|
||
audio_resample_config_t cfg = {
|
||
.aformat = aml_out->hal_internal_format,
|
||
.channels = aml_out->hal_ch,
|
||
.input_sr = aml_out->hal_rate,
|
||
.output_sr = OUTPUT_ALSA_SAMPLERATE,
|
||
};
|
||
ret = aml_audio_resample_process_ex(&aml_out->resample_handle, &cfg, buffer, bytes);
|
||
if (ret != 0) {
|
||
ALOGE("aml_audio_resample_process_ex failed");
|
||
} else {
|
||
buffer = aml_out->resample_handle->resample_buffer;
|
||
bytes_remaining = aml_out->resample_handle->resample_size;
|
||
}
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
aml_ms12_loudness_input_control(aml_out, abuffer);
|
||
}
|
||
|
||
|
||
if (aml_out->flags & AUDIO_OUTPUT_FLAG_FAST) { //video drop data in miracast case,audio does it also.
|
||
if (dolby_ms12_get_app_buffer_frame(&buffer_frames) / 48 > 45) {
|
||
AM_LOGI_IF(adev->debug_flag, "fast mode write %zu bytes, app level %d ms", bytes, buffer_frames / 48);
|
||
return bytes;
|
||
}
|
||
}
|
||
|
||
while (bytes_remaining && adev->ms12.dolby_ms12_enable && retry > 0) {
|
||
size_t used_size = 0;
|
||
ret = dolby_ms12_app_process(stream, (char *)buffer + bytes_written, bytes_remaining, &used_size);
|
||
if (!ret) {
|
||
bytes_remaining -= used_size;
|
||
bytes_written += used_size;
|
||
}
|
||
retry--;
|
||
if (bytes_remaining) {
|
||
aml_audio_sleep(3000);
|
||
}
|
||
}
|
||
if (retry <= 10) {
|
||
ALOGE("[%s:%d] write retry=%d ", __func__, __LINE__, retry);
|
||
}
|
||
if (retry == 0 && bytes_remaining != 0) {
|
||
ALOGE("[%s:%d] write timeout 60 ms ", __func__, __LINE__);
|
||
bytes -= bytes_remaining;
|
||
}
|
||
|
||
if (adev->debug_flag) {
|
||
dolby_ms12_get_app_buffer_frame(&buffer_frames);
|
||
AM_LOGI("app level %d ms", buffer_frames / 48);
|
||
}
|
||
return bytes;
|
||
}
|
||
|
||
ssize_t mixer_hwmixer_buffer_write (struct audio_stream_out *stream, struct audio_buffer *abuffer)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = NULL;
|
||
int32_t return_size = 0;
|
||
|
||
if (!stream) {
|
||
AM_LOGE ("invalid stream %p\n", stream);
|
||
return -1;
|
||
}
|
||
adev = aml_out->dev;
|
||
|
||
AM_LOGI_IF(adev->debug_flag, "out %p, format:0x%x, stream_type:0x%x, in %"PRId32, aml_out, abuffer->format, aml_out->stream_type, abuffer->size);
|
||
|
||
if (aml_out->standby) {
|
||
aml_out->standby = false;
|
||
}
|
||
|
||
return_size = aml_audio_hwmixer_out_write(adev, abuffer);
|
||
|
||
AM_LOGI_IF(adev->debug_flag, "out %p, return %d!\n", aml_out, return_size);
|
||
return return_size;
|
||
}
|
||
|
||
/* must be called with hw device mutexes locked */
|
||
static int stream_type_validate_l(struct aml_stream_out *aml_out, uint32_t flags)
|
||
{
|
||
int ret = 0;
|
||
struct aml_audio_device *adev = adev_get_handle();
|
||
aml_out->flags = flags;
|
||
aml_out->enable_scaletempo = false;
|
||
|
||
/* decide aml_out->stream_type with aml_out->flags */
|
||
// hwsync case
|
||
if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) && (aml_out->hal_format != AUDIO_FORMAT_IEC61937)) {
|
||
if (is_digital_raw_format(aml_out->hal_format) || audio_is_linear_pcm(aml_out->hal_format)) {
|
||
aml_out->stream_type = STREAM_MAIN_INPUT;
|
||
} else {
|
||
ALOGE("No matching stream_type, need check!!");
|
||
}
|
||
}
|
||
// non hwsync cases
|
||
if (is_digital_raw_format(aml_out->hal_format)) {
|
||
aml_out->stream_type = STREAM_MAIN_INPUT;
|
||
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && audio_is_linear_pcm(aml_out->hal_format)) {
|
||
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
|
||
// AAudio case
|
||
aml_out->stream_type = STREAM_APP_INPUT;
|
||
} else {
|
||
//multi-channel LPCM or hi-res LPCM
|
||
aml_out->stream_type = STREAM_MAIN_INPUT;
|
||
}
|
||
} else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
|
||
aml_out->stream_type = STREAM_APP_INPUT;
|
||
} else if (flags & AUDIO_OUTPUT_FLAG_FAST) {
|
||
if (adev->has_hwmixer) {
|
||
aml_out->stream_type = STREAM_HWMIXER_INPUT;
|
||
} else {
|
||
aml_out->stream_type = STREAM_APP_INPUT;
|
||
}
|
||
} else if (aml_out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
|
||
aml_out->stream_type = STREAM_DEEP_INPUT;
|
||
} else {
|
||
aml_out->stream_type = STREAM_AUX_INPUT;
|
||
}
|
||
//ad case
|
||
if (flags & AUDIO_OUTPUT_FLAG_AD_STREAM) {
|
||
aml_out->stream_type = STREAM_AD_INPUT;
|
||
}
|
||
/* decide aml_out->write with aml_out->stream_type */
|
||
if (adev->dolby_lib_type == eDolbyMS12Lib) {
|
||
switch (aml_out->stream_type) {
|
||
case STREAM_AUX_INPUT:
|
||
case STREAM_DEEP_INPUT:
|
||
aml_out->write = mixer_aux_buffer_write;
|
||
aml_out->inputPortType = AML_DOLBY_INPUT_SYSTEM;
|
||
AM_LOGI("mixer_aux_buffer_write!");
|
||
break;
|
||
case STREAM_APP_INPUT:
|
||
aml_out->write = mixer_app_buffer_write;
|
||
aml_out->inputPortType = AML_DOLBY_INPUT_APP;
|
||
AM_LOGI("mixer_app_buffer_write!");
|
||
break;
|
||
case STREAM_AD_INPUT:
|
||
aml_out->write = mixer_ad_buffer_write;
|
||
aml_out->inputPortType = AML_DOLBY_INPUT_AD;
|
||
AM_LOGI("mixer_ad_buffer_write!");
|
||
break;
|
||
case STREAM_MAIN_INPUT:
|
||
aml_out->write = mixer_main_buffer_write;
|
||
aml_out->inputPortType = AML_DOLBY_INPUT_MAIN;
|
||
aml_out->enable_scaletempo = true;
|
||
AM_LOGI("mixer_main_buffer_write!");
|
||
break;
|
||
case STREAM_HWMIXER_INPUT:
|
||
aml_out->write = mixer_hwmixer_buffer_write;
|
||
AM_LOGI("mixer_hwmixer_buffer_write!");
|
||
break;
|
||
default:
|
||
AM_LOGE("No matching aml_out->write_func !");
|
||
ret = -1;
|
||
break;
|
||
}
|
||
} else {
|
||
aml_out->inputPortType = get_input_port_type(&aml_out->audioCfg, aml_out->flags);
|
||
switch (aml_out->stream_type) {
|
||
case STREAM_AUX_INPUT:
|
||
case STREAM_DEEP_INPUT:
|
||
aml_out->write = mixer_aux_buffer_write;
|
||
AM_LOGI("mixer_aux_buffer_write !");
|
||
break;
|
||
case STREAM_APP_INPUT:
|
||
aml_out->write = mixer_app_buffer_write;
|
||
AM_LOGI("mixer_app_buffer_write !");
|
||
break;
|
||
case STREAM_AD_INPUT:
|
||
aml_out->write = mixer_ad_buffer_write;
|
||
aml_out->inputPortType = AML_DOLBY_INPUT_AD;
|
||
AM_LOGI("mixer_ad_buffer_write!");
|
||
break;
|
||
case STREAM_MAIN_INPUT:
|
||
aml_out->write = mixer_main_buffer_write;
|
||
aml_out->enable_scaletempo = true;
|
||
AM_LOGI("mixer_main_buffer_write !");
|
||
break;
|
||
case STREAM_HWMIXER_INPUT:
|
||
aml_out->write = mixer_hwmixer_buffer_write;
|
||
AM_LOGI("mixer_hwmixer_buffer_write!");
|
||
break;
|
||
default:
|
||
AM_LOGE("No matching aml_out->write_func !");
|
||
ret = -1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (HDMI_SRC == aml_out->source_type || HDMI1_SRC == aml_out->source_type || AV_SRC == aml_out->source_type) {
|
||
aml_out->enable_scaletempo = false;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static inline int add_active_output_stream(struct aml_audio_device *adev, struct aml_stream_out *aml_out)
|
||
{
|
||
int i = 0;
|
||
pthread_mutex_lock(&adev->active_outputs_lock);
|
||
for (i = 0; i < STREAM_NUM_MAX; i++) {
|
||
if (adev->active_outputs[i] == NULL) {
|
||
adev->active_outputs[i] = aml_out;
|
||
AM_LOGI("adev->active_outputs[%d] = aml_out", i);
|
||
break;
|
||
}
|
||
}
|
||
if (i == STREAM_NUM_MAX) {
|
||
AM_LOGE("adev->active_outputs[] is full");
|
||
pthread_mutex_unlock(&adev->active_outputs_lock);
|
||
return -1;
|
||
}
|
||
pthread_mutex_unlock(&adev->active_outputs_lock);
|
||
return 0;
|
||
}
|
||
|
||
static inline int remove_active_output_stream(struct aml_audio_device *adev, struct aml_stream_out *aml_out)
|
||
{
|
||
int i = 0;
|
||
pthread_mutex_lock(&adev->active_outputs_lock);
|
||
for (i = 0; i < STREAM_NUM_MAX; i++) {
|
||
if (adev->active_outputs[i] == aml_out) {
|
||
adev->active_outputs[i] = NULL;
|
||
AM_LOGI("set adev->active_outputs[%d] = NULL, removed stream", i);
|
||
break;
|
||
}
|
||
}
|
||
if (i == STREAM_NUM_MAX) {
|
||
AM_LOGE("stream is not in adev->active_outputs[]");
|
||
pthread_mutex_unlock(&adev->active_outputs_lock);
|
||
return -1;
|
||
}
|
||
pthread_mutex_unlock(&adev->active_outputs_lock);
|
||
return 0;
|
||
}
|
||
|
||
static int set_hdmi_format(struct aml_audio_device *adev, int val)
|
||
{
|
||
int ret = -1;
|
||
if (adev->hdmi_format == val) {
|
||
return 0;
|
||
}
|
||
adev->hdmi_format_updated = 1;
|
||
adev->hdmi_format = val;
|
||
/* update the DUT's EDID */
|
||
ret = update_edid_after_edited_audio_sad((struct audio_hw_device *)adev);
|
||
if (ret < 0) {
|
||
ALOGE("[%s:%d], An error occurred during updating the DUT's EDID!", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
get_sink_format(adev);
|
||
|
||
audiohal_send_msg_2_ms12(&adev->ms12, MS12_MESG_TYPE_RESET_MS12_ENCODER);
|
||
if (adev->out_device & AUDIO_DEVICE_OUT_ALL_A2DP) {
|
||
adev->a2dp_no_reconfig_ms12 = aml_audio_get_systime() + 2000000;
|
||
}
|
||
}
|
||
ALOGI("update HDMI format: %d\n", adev->hdmi_format);
|
||
return 0;
|
||
}
|
||
|
||
static int out_write_pcm_float_to_s32(struct aml_stream_out *aml_out,
|
||
const void **write_buf, size_t *write_bytes)
|
||
{
|
||
if (*write_bytes == 0) {
|
||
return 0;
|
||
}
|
||
const size_t samples = *write_bytes / audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
|
||
const size_t out_bytes = samples * audio_bytes_per_sample(AUDIO_FORMAT_PCM_32_BIT);
|
||
|
||
if (samples == 0 || (*write_bytes % audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT)) != 0) {
|
||
return -EINVAL;
|
||
}
|
||
if (aml_out->float_to_s32_tmp_buf_size < out_bytes) {
|
||
void *new_buf = aml_audio_realloc(aml_out->float_to_s32_tmp_buf, out_bytes);
|
||
if (new_buf == NULL) {
|
||
return -ENOMEM;
|
||
}
|
||
aml_out->float_to_s32_tmp_buf = new_buf;
|
||
aml_out->float_to_s32_tmp_buf_size = out_bytes;
|
||
}
|
||
|
||
memcpy_by_audio_format(aml_out->float_to_s32_tmp_buf, AUDIO_FORMAT_PCM_32_BIT,
|
||
*write_buf, AUDIO_FORMAT_PCM_FLOAT, samples);
|
||
*write_buf = aml_out->float_to_s32_tmp_buf;
|
||
*write_bytes = out_bytes;
|
||
return 0;
|
||
}
|
||
|
||
/* out_write entrance: every write goes in here. */
|
||
ssize_t out_write_new(struct audio_stream_out *stream,
|
||
const void *buffer,
|
||
size_t bytes)
|
||
{
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
||
struct aml_audio_device *adev = aml_out->dev;
|
||
ssize_t return_bytes = 0;
|
||
struct audio_buffer abuffer = {0};
|
||
size_t pheader_cost = 0;
|
||
int pheader_outsize = 0;
|
||
uint64_t cur_pts = HWSYNC_PTS_NA;
|
||
size_t write_bytes = bytes;
|
||
const void *write_buf = buffer;
|
||
size_t bytes_cost = 0;
|
||
size_t total_bytes = bytes;
|
||
bool need_reconfig_encoder = false;
|
||
if (aml_out->source_type == MEDIA_SRC && !audio_is_linear_pcm(aml_out->hal_format)) {
|
||
aml_set_thread_priority("out_write_new", pthread_self(), adev->out_write_thread_priority);
|
||
}
|
||
|
||
if (NULL == buffer) {
|
||
ALOGE("[%s:%d], buffer is NULL, out_stream(%p) position(%zu)", __func__, __LINE__, stream, bytes);
|
||
return bytes;
|
||
}
|
||
|
||
#ifdef NO_SERVER
|
||
enum digital_format digital_mode = PCM;
|
||
enum OUT_PORT output_sel = OUTPORT_SPEAKER;
|
||
int ret = 0;
|
||
|
||
digital_mode = get_digital_mode(&adev->alsa_mixer);
|
||
ret = set_hdmi_format(adev, digital_mode);
|
||
if (ret < 0) {
|
||
ALOGE("[%s:%d], An error occurred during setting hdmi_format !", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
output_sel = get_output_select(&adev->alsa_mixer);
|
||
if (aml_out->is_sink_format_prepared && output_sel != adev->active_outport) {
|
||
adev->active_outport = output_sel;
|
||
get_sink_format(adev);
|
||
} else {
|
||
adev->active_outport = output_sel;
|
||
}
|
||
#endif
|
||
/* Confirm whether to enable mch pcm output */
|
||
pthread_mutex_lock(&adev->audio_mixer_lock);
|
||
if (aml_out->standby && adev->useSubMix) {
|
||
if (aml_need_mch_pcm_output(adev)) {
|
||
mixer_enable_multich_output(adev->audio_mixer, true);
|
||
} else {
|
||
/* need to close multi-pcm alsa handle, then npcm can use it. */
|
||
mixer_enable_multich_output(adev->audio_mixer, false);
|
||
}
|
||
}
|
||
/* init submix input port when input isn't main */
|
||
if (adev->useSubMix && aml_out->inputPortID == -1 && (aml_out->stream_type == STREAM_AUX_INPUT ||
|
||
aml_out->stream_type == STREAM_APP_INPUT || aml_out->stream_type == STREAM_DEEP_INPUT)) {
|
||
init_mixer_input_port(adev->audio_mixer, &aml_out->audioCfg, aml_out->flags,
|
||
on_notify_cbk, aml_out, on_input_avail_cbk, aml_out, 1.0);
|
||
AM_LOGI("[Submix]port:%s, inputPortID:%d", mixerInputType2Str(get_input_port_type(&aml_out->audioCfg, aml_out->flags)), aml_out->inputPortID);
|
||
}
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
|
||
adev->debug_flag = aml_audio_get_debug_flag();
|
||
AM_LOGI_IF(adev->debug_flag, "+<IN>out_stream(%p) position(%zu)", stream, bytes);
|
||
|
||
/*move it from open function, because when hdmi hot plug, audio service will
|
||
* call many times open/close to query the hdmi capability, this will affect the
|
||
* sink format
|
||
*/
|
||
if (!aml_out->is_sink_format_prepared) {
|
||
need_reconfig_encoder = true;
|
||
|
||
aml_out->card = alsa_device_get_card_index();
|
||
if (!is_TV(adev)) {
|
||
if (is_use_spdifb(aml_out)) {
|
||
aml_audio_select_spdif_to_hdmi(AML_SPDIF_B_TO_HDMITX);
|
||
aml_out->restore_hdmitx_selection = true;
|
||
}
|
||
}
|
||
aml_out->is_sink_format_prepared = true;
|
||
}
|
||
|
||
/* here to check if the audio HDMI ARC format updated. */
|
||
if (is_arc_hdmi_updated(adev)) {
|
||
AM_LOGI ("arc format updated, need reconfig output");
|
||
need_reconfig_encoder = true;
|
||
set_arc_hdmi_updated(adev, false);
|
||
}
|
||
|
||
/* here to check if the digital output format updated. */
|
||
if (adev->hdmi_format_updated) {
|
||
AM_LOGI("hdmi format updated, need reconfig output, [PCM(0)/SPDIF(4)/AUTO(5)] %d", adev->hdmi_format);
|
||
need_reconfig_encoder = true;
|
||
adev->hdmi_format_updated = 0;
|
||
}
|
||
|
||
/* here to check if hdmi reconnected. */
|
||
if (is_HDMI_reconnected(adev)) {
|
||
AM_LOGI("hdmi connect updated, need reconfig output");
|
||
need_reconfig_encoder = true;
|
||
set_HDMI_reconnected_flag(adev, false);
|
||
}
|
||
|
||
if (need_reconfig_encoder) {
|
||
get_sink_format(adev);
|
||
reconfig_encoder(stream);
|
||
dtsx_set_drc_state(adev->dtsx_drc_enable);
|
||
need_reconfig_encoder = false;
|
||
}
|
||
|
||
if (adev->active_outport_changed) {
|
||
dtsx_set_drc_state(adev->dtsx_drc_enable);
|
||
adev->active_outport_changed = false;
|
||
}
|
||
|
||
aml_audio_trace_int("out_write_new", bytes);
|
||
/**
|
||
* deal with the device output changes
|
||
* pthread_mutex_lock(&aml_out->lock);
|
||
* out_device_change_validate_l(aml_out);
|
||
* pthread_mutex_unlock(&aml_out->lock);
|
||
*/
|
||
|
||
clock_gettime(CLOCK_MONOTONIC, &adev->last_write_ts);
|
||
adev->stream_write_data = true;
|
||
|
||
pheader_rewrite:
|
||
if (true == aml_out->with_header) {
|
||
write_bytes = 0;
|
||
if (NULL == aml_out->pheader) {
|
||
aml_out->pheader = audio_header_info_init();
|
||
}
|
||
|
||
pheader_cost = audio_header_find_frame(aml_out->pheader, (char *)buffer + bytes_cost, total_bytes - bytes_cost, &cur_pts, &pheader_outsize);
|
||
if (pheader_outsize > 0)
|
||
{
|
||
write_bytes = pheader_outsize;
|
||
write_buf = aml_out->pheader->hw_sync_body_buf;
|
||
}
|
||
|
||
if ((0 != aml_out->pheader->clip_front) || (0 != aml_out->pheader->clip_back))
|
||
{
|
||
if (NULL == aml_out->clip_meta)
|
||
{
|
||
aml_out->clip_meta = hal_clip_meta_init();
|
||
}
|
||
//AM_LOGI("b_install_clip_callback:%d ms12_dec_handle:%p", aml_out->b_install_clip_callback, aml_out->ms12_dec_handle);
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type && !aml_out->b_install_clip_callback && aml_out->ms12_dec_handle) {
|
||
if (0 != aml_ms12_decoder_register_callback(&(adev->ms12), aml_out->ms12_dec_handle, MS12_CODEC_CALLBACK_CLIPMETA, ms12_clipmeta, (void *)stream))
|
||
{
|
||
AM_LOGE("clip callback register fail!");
|
||
} else {
|
||
AM_LOGI("clip callback register success!");
|
||
aml_out->b_install_clip_callback = true;
|
||
}
|
||
}
|
||
|
||
AM_LOGI("inbytes:%zu, outbytes:%zu, offset:%"PRIu64", clip_front:%"PRIu64", clip_back:%"PRIu64"", bytes, write_bytes,
|
||
aml_out->clip_offset, aml_out->pheader->clip_front, aml_out->pheader->clip_back);
|
||
aml_out->clip_offset = aml_out->payload_offset;
|
||
hal_set_clip_info(aml_out->clip_meta, aml_out->clip_offset, aml_out->pheader->clip_front, aml_out->pheader->clip_back);
|
||
}
|
||
|
||
aml_out->payload_offset += write_bytes;
|
||
|
||
if (aml_out->eos != aml_out->pheader->eos) {
|
||
if (aml_out->pheader->eos) {
|
||
/* in nonms12 render case, there would pop noise when playback ending, as there's no fade out.
|
||
* and we use AED mute to avoid noise.
|
||
*/
|
||
if (adev->dolby_lib_type != eDolbyMS12Lib) {
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, true);
|
||
} else {
|
||
//mute
|
||
ease_setting_t vol_setting;
|
||
vol_setting.duration = 32;
|
||
vol_setting.start_volume = 0;
|
||
vol_setting.target_volume = 0;
|
||
vol_setting.ease_shape = EaseLinear;
|
||
aml_audio_ease_config(aml_out->vol_process_handle, &vol_setting);
|
||
}
|
||
} else {
|
||
if (adev->dolby_lib_type != eDolbyMS12Lib) {
|
||
set_aed_master_volume_mute(&adev->alsa_mixer, false);
|
||
} else {
|
||
//unmute
|
||
ease_setting_t vol_setting;
|
||
vol_setting.duration = 32;
|
||
vol_setting.start_volume = aml_out->volume_l;
|
||
vol_setting.target_volume = aml_out->volume_l;
|
||
vol_setting.ease_shape = EaseLinear;
|
||
aml_audio_ease_config(aml_out->vol_process_handle, &vol_setting);
|
||
}
|
||
}
|
||
aml_out->eos = aml_out->pheader->eos;
|
||
}
|
||
if (adev->debug_flag > 0) {
|
||
ALOGI("[%s:%d], inputsize:%zu, pheader_cost:%zu, cur_pts:0x%"PRIx64" (%"PRIu64" ms), outsize:%d", __func__, __LINE__, bytes, pheader_cost, cur_pts, cur_pts/90, pheader_outsize);
|
||
}
|
||
|
||
if ((cur_pts > 0xffffffff) && (cur_pts != HWSYNC_PTS_NA) && (cur_pts != HWSYNC_PTS_EOS)) {
|
||
ALOGE("APTS exeed the max 32bit value");
|
||
}
|
||
}
|
||
|
||
if ((NULL != aml_out->avsync_ctx) && (AVSYNC_TYPE_MEDIASYNC == aml_out->avsync_type)) {
|
||
if (NULL == aml_out->avsync_ctx->mediasync_ctx) {
|
||
AM_LOGE("mediasync_ctx is null error, cleanup avsync_type!");
|
||
aml_out->avsync_type = AVSYNC_TYPE_NULL;
|
||
} else if (true != aml_out->with_header) { //DTV
|
||
pthread_mutex_lock(&(aml_out->avsync_ctx->lock));
|
||
cur_pts = aml_out->avsync_ctx->mediasync_ctx->in_apts;
|
||
pthread_mutex_unlock(&(aml_out->avsync_ctx->lock));
|
||
}
|
||
}
|
||
if (aml_out->flags & AUDIO_OUTPUT_FLAG_HBBTV && aml_out->avsync_type == AVSYNC_TYPE_MEDIASYNC) {
|
||
pthread_mutex_lock(&(aml_out->avsync_ctx->lock));
|
||
if (aml_out->avsync_ctx->mediasync_ctx->handle) {
|
||
struct mediasync_audio_queue_info audio_queue_info;
|
||
audio_queue_info.apts = ((int64_t)cur_pts / 90 + adev->hbbtvsync_info.va_offset + adev->hbbtvsync_info.vpts_mt_offset) * 90;
|
||
audio_queue_info.duration = 0;
|
||
audio_queue_info.size = write_bytes;
|
||
audio_queue_info.isneedupdate = false;
|
||
audio_queue_info.isworkingchannel = true;
|
||
audio_queue_info.tunit = MEDIASYNC_UNIT_PTS;
|
||
mediasync_wrap_queueAudioFrame(aml_out->avsync_ctx->mediasync_ctx->handle, &audio_queue_info);
|
||
AM_LOGI_IF(adev->debug_flag, "aout %p, handle %p. cur_pts:0x%"PRIx64", adjust_pts 0x%"PRIx64", va_offset %dms, vpts_mt_offset %dms",
|
||
aml_out, aml_out->avsync_ctx->mediasync_ctx->handle, cur_pts, audio_queue_info.apts, adev->hbbtvsync_info.va_offset, adev->hbbtvsync_info.vpts_mt_offset);
|
||
cur_pts = audio_queue_info.apts;
|
||
}
|
||
pthread_mutex_unlock(&(aml_out->avsync_ctx->lock));
|
||
}
|
||
|
||
if (aml_out->hal_input_is_float) {
|
||
if (out_write_pcm_float_to_s32(aml_out, &write_buf, &write_bytes) < 0) {
|
||
AM_LOGE("out_write_pcm_float_to_s32 error!");
|
||
return bytes;
|
||
}
|
||
}
|
||
|
||
if (aml_out->write && write_bytes > 0) {
|
||
abuffer.buffer = write_buf;
|
||
abuffer.size = write_bytes;
|
||
abuffer.pts = cur_pts;
|
||
abuffer.original_format = aml_out->hal_format;
|
||
abuffer.original_sample_rate = aml_out->hal_rate;
|
||
abuffer.format = aml_out->hal_format;
|
||
abuffer.sample_rate = aml_out->hal_rate;
|
||
abuffer.channel = aml_out->hal_ch;
|
||
abuffer.channel_mask = aml_out->hal_channel_mask;
|
||
if (abuffer.pts != HWSYNC_PTS_NA) {
|
||
abuffer.b_pts_valid = true;
|
||
}
|
||
return_bytes = aml_out->write(stream, &abuffer);
|
||
}
|
||
|
||
/*if the data consume is not complete, it will be send again by audio flinger,
|
||
this old data will cause av sync problem after seek.
|
||
*/
|
||
if (aml_out->with_header && return_bytes > 0) {
|
||
/*
|
||
if the data is not consumed totally,
|
||
we need re-send data again
|
||
*/
|
||
bytes_cost += pheader_cost;
|
||
if (bytes_cost > 0 && total_bytes > bytes_cost) {
|
||
/* We need to wait for Google to fix the issue:
|
||
* Issue: After pause, there will be residual sound in AF, which will cause NTS fail.
|
||
* Now we need to judge whether the current format is DTS */
|
||
if (is_dts_format(aml_out->hal_internal_format))
|
||
return bytes_cost;
|
||
else
|
||
goto pheader_rewrite;
|
||
}
|
||
return_bytes = bytes_cost;
|
||
}
|
||
|
||
aml_audio_trace_int("out_write_new", 0);
|
||
if (return_bytes > 0) {
|
||
aml_out->total_write_size += return_bytes;
|
||
if (aml_out->is_normal_pcm) {
|
||
size_t frame_size = audio_stream_out_frame_size(stream);
|
||
if (frame_size != 0) {
|
||
if (aml_out->stream_type == STREAM_DEEP_INPUT) {
|
||
adev->deep_buf_audio_frame_written = aml_out->input_bytes_size / frame_size;
|
||
} else {
|
||
adev->sys_audio_frame_written = aml_out->input_bytes_size / frame_size;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
update_audio_format(adev, aml_out);
|
||
|
||
AM_LOGI_IF(adev->debug_flag, "-<OUT>out_stream(%p) position(%zu) ret %zd, %"PRIu64"", stream, bytes, return_bytes, aml_out->total_write_size);
|
||
|
||
return return_bytes;
|
||
}
|
||
|
||
int adev_open_output_stream_new(struct audio_hw_device *dev,
|
||
audio_io_handle_t handle __unused,
|
||
audio_devices_t devices,
|
||
audio_output_flags_t flags,
|
||
struct audio_config *config,
|
||
struct audio_stream_out **stream_out,
|
||
const char *address)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
struct aml_stream_out *aml_out = NULL;
|
||
int ret = 0;
|
||
AM_LOGD("enter!!");
|
||
ret = adev_open_output_stream(dev,
|
||
0,
|
||
devices,
|
||
flags,
|
||
config,
|
||
stream_out,
|
||
address);
|
||
if (ret < 0) {
|
||
ALOGE("%s(), open stream failed", __func__);
|
||
return ret;
|
||
}
|
||
|
||
aml_out = (struct aml_stream_out *)(*stream_out);
|
||
memcpy(&aml_out->audioCfg, config, sizeof(struct audio_config));
|
||
|
||
/* init ease for stream */
|
||
if (aml_audio_ease_init(&aml_out->audio_stream_ease) < 0) {
|
||
ALOGE("%s aml_audio_ease_init faild\n", __func__);
|
||
ret = -EINVAL;
|
||
goto AUDIO_EASE_INIT_FAIL;
|
||
}
|
||
|
||
if (is_dts_format(aml_out->hal_internal_format) || is_mpegh_format(aml_out->hal_internal_format)) {
|
||
adev->native_postprocess.effect_ctrl.is_dts = true;
|
||
if (!adev->useSubMix && adev->dolby_lib_type_last == eDolbyMS12Lib) {
|
||
pthread_mutex_lock(&adev->audio_mixer_lock);
|
||
/*coverity[lock_evasion]: There will be no competition here*/
|
||
adev->useSubMix = true;
|
||
ret = initHalSubMixing(MIXER_LPCM, adev, is_TV(adev));//init submix
|
||
if (ret < 0)
|
||
AM_LOGI("initHalSubMixing fail");
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
adev->restart_device_flag = false;
|
||
}
|
||
}
|
||
|
||
/* init vol process for stream */
|
||
if (aml_audio_ease_init(&aml_out->vol_process_handle) < 0) {
|
||
AM_LOGE("aml_audio_ease_init vol_process_handle failed\n");
|
||
ret = -EINVAL;
|
||
goto AUDIO_EASE_INIT_FAIL;
|
||
} else {
|
||
AM_LOGI("out:%p vol_process_handle:%p init success", aml_out, aml_out->vol_process_handle);
|
||
aml_out->vol_process_handle->data_format.format = AUDIO_FORMAT_PCM_FLOAT;
|
||
|
||
if (aml_out->stream_type != STREAM_AD_INPUT) {
|
||
/*In order to avoid the invalid adjustment of mastervol when there is no stream */
|
||
AM_LOGI("stream:%p set vol to %f", aml_out, aml_out->volume_l_org);
|
||
out_set_volume_l((struct audio_stream_out *)aml_out, aml_out->volume_l_org, aml_out->volume_r_org);
|
||
}
|
||
}
|
||
|
||
/*when a new stream is opened here, we can add it to active stream*/
|
||
ret = add_active_output_stream(adev, aml_out);
|
||
if (ret < 0) {
|
||
AM_LOGE("add_active_output_stream failed");
|
||
return ret;
|
||
}
|
||
|
||
AM_LOGD("exit, out %p, stream ID:%d, io handle:%d, stream_type:%s card:%d alsa devices:%d",
|
||
aml_out, aml_out->unique_ID, handle, streamtype2Str(aml_out->stream_type), aml_out->card, aml_out->device);
|
||
return 0;
|
||
|
||
AUDIO_EASE_INIT_FAIL:
|
||
adev_close_output_stream(dev, *stream_out);
|
||
return ret;
|
||
}
|
||
|
||
void adev_close_output_stream_new(struct audio_hw_device *dev,
|
||
struct audio_stream_out *stream)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)dev;
|
||
struct aml_stream_out *aml_out = (struct aml_stream_out *)stream;
|
||
|
||
if (dev == NULL || stream == NULL) {
|
||
ALOGE("%s: Input parameter error!!!", __func__);
|
||
return;
|
||
}
|
||
AM_LOGI("enter, stream:%p, stream ID:%d, stream_type = %s, format = %x, ch = %d",aml_out,
|
||
aml_out->unique_ID, streamtype2Str(aml_out->stream_type), aml_out->hal_internal_format, aml_out->hal_ch);
|
||
|
||
/* when a stream is closed here, we remove it from active stream */
|
||
remove_active_output_stream(adev, aml_out);
|
||
/* free vol process resource */
|
||
aml_audio_ease_close(aml_out->vol_process_handle);
|
||
aml_out->vol_process_handle = NULL;
|
||
/* free stream ease resource */
|
||
aml_audio_ease_close(aml_out->audio_stream_ease);
|
||
aml_out->audio_stream_ease = NULL;
|
||
|
||
/*Avoid accidentally setting variate when multiple streams
|
||
*An unexpected setting of variable values will result in dts foramt without dtsvx sound effects*/
|
||
pthread_mutex_lock(&adev->active_outputs_lock);
|
||
if (adev->native_postprocess.effect_ctrl.is_dts) {
|
||
if (!dts_stream_active(adev)) {
|
||
adev->native_postprocess.effect_ctrl.is_dts = false;
|
||
}
|
||
AM_LOGI("native_postprocess.effect_ctrl.is_dts=%d",adev->native_postprocess.effect_ctrl.is_dts);
|
||
}
|
||
pthread_mutex_unlock(&adev->active_outputs_lock);
|
||
|
||
adev_close_output_stream(dev, stream);
|
||
|
||
/* Confirm whether to disable mch pcm output */
|
||
pthread_mutex_lock(&adev->audio_mixer_lock);
|
||
if (adev->useSubMix && eDolbyDcvLib == adev->dolby_lib_type) {
|
||
if (aml_need_mch_pcm_output(adev)) {
|
||
mixer_enable_multich_output(adev->audio_mixer, true);
|
||
} else {
|
||
/* need to close multi-pcm alsa handle, then npcm can use it. */
|
||
mixer_enable_multich_output(adev->audio_mixer, false);
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&adev->audio_mixer_lock);
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
/*only enable mc output when it supports multi channel*/
|
||
if (aml_need_mch_pcm_output(adev)) {
|
||
set_ms12_mch_enable(&(adev->ms12), true);
|
||
} else {
|
||
set_ms12_mch_enable(&(adev->ms12), false);
|
||
}
|
||
}
|
||
get_sink_format(adev);
|
||
AM_LOGI("exit!!");
|
||
}
|
||
|
||
static enum OUT_PORT get_output_dev_for_sinks(enum OUT_PORT *sinks, int num_sinks, enum OUT_PORT sink) {
|
||
for (int i=0; i<num_sinks; i++) {
|
||
if (sinks[i] == sink) {
|
||
return sink;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static enum OUT_PORT get_output_dev_for_strategy(struct aml_audio_device *adev, enum OUT_PORT *sinks, int num_sinks)
|
||
{
|
||
uint32_t sink = -1;
|
||
if (sink == -1) {
|
||
sink = get_output_dev_for_sinks(sinks, num_sinks, OUTPORT_A2DP);
|
||
}
|
||
if (sink == -1 && is_arc_connected(adev)) {
|
||
sink = get_output_dev_for_sinks(sinks, num_sinks, OUTPORT_HDMI_ARC);
|
||
}
|
||
if (sink == -1) {
|
||
sink = get_output_dev_for_sinks(sinks, num_sinks, OUTPORT_HDMI);
|
||
}
|
||
if (sink == -1) {
|
||
sink = get_output_dev_for_sinks(sinks, num_sinks, OUTPORT_SPEAKER);
|
||
}
|
||
if (sink == -1) {
|
||
sink = OUTPORT_SPEAKER;
|
||
}
|
||
return sink;
|
||
}
|
||
|
||
static int adev_create_audio_patch(struct audio_hw_device *dev,
|
||
unsigned int num_sources,
|
||
const struct audio_port_config *sources,
|
||
unsigned int num_sinks,
|
||
const struct audio_port_config *sinks,
|
||
audio_patch_handle_t *handle)
|
||
{
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *)dev;
|
||
const struct audio_port_config *src_config = NULL;
|
||
const struct audio_port_config *sink_config = NULL;
|
||
enum OUT_PORT outport = OUTPORT_SPEAKER;
|
||
unsigned int i = 0;
|
||
int ret = -1;
|
||
|
||
if (!sources || !sinks || !handle) {
|
||
ALOGE("[%s:%d] null pointer! sources:%p, sinks:%p, handle:%p", __func__, __LINE__, sources, sinks, handle);
|
||
return -EINVAL;
|
||
}
|
||
src_config = sources;
|
||
sink_config = sinks;
|
||
|
||
if ((num_sources != 1) || (num_sinks > 3) || (src_config->type != AUDIO_PORT_TYPE_DEVICE)) {
|
||
ALOGE("[%s:%d] unsupport num sources:%d or sinks:%d", __func__, __LINE__, num_sources, num_sinks);
|
||
return -EINVAL;
|
||
}
|
||
|
||
AM_LOGI("num_sources:%d, num_sinks:%d, %s(0x%x)->%s(0x%x), AF:%p"
|
||
, num_sources, num_sinks
|
||
, (src_config->type == AUDIO_PORT_TYPE_MIX) ? "mix" : "device"
|
||
, (src_config->type == AUDIO_PORT_TYPE_MIX) ? src_config->ext.mix.handle : src_config->ext.device.type
|
||
, (sink_config->type == AUDIO_PORT_TYPE_MIX) ? "mix" : "device"
|
||
, (sink_config->type == AUDIO_PORT_TYPE_MIX) ? sink_config->ext.mix.handle : sink_config->ext.device.type
|
||
, handle);
|
||
|
||
android_dev_convert_to_hal_dev(sink_config->ext.device.type, (int *)&outport);
|
||
|
||
if (num_sinks > 1) {
|
||
enum OUT_PORT sink_devs[3] = {OUTPORT_SPEAKER, OUTPORT_SPEAKER, OUTPORT_SPEAKER};
|
||
for (int i=0; i<num_sinks; i++) {
|
||
android_dev_convert_to_hal_dev(sink_config[i].ext.device.type, (int *)&sink_devs[i]);
|
||
if (aml_dev->debug_flag) {
|
||
AM_LOGD("sink[%d]:%s", i, outputPort2Str(sink_devs[i]));
|
||
}
|
||
}
|
||
|
||
outport = get_output_dev_for_strategy(aml_dev, sink_devs, num_sinks);
|
||
} else {
|
||
AM_LOGI("one sink, sink:%s", outputPort2Str(outport));
|
||
}
|
||
|
||
/*ignore outport SPEAKER, because LINUX always sets SPEAKER when ARC or HDMI connected*/
|
||
if (outport != OUTPORT_SPEAKER || aml_dev->active_outport == OUTPORT_MAX) {
|
||
if (outport != OUTPORT_SPDIF) {
|
||
aml_audio_output_routing(dev, outport, false);
|
||
}
|
||
aml_dev->out_device = 0;
|
||
for (i = 0; i < num_sinks; i++) {
|
||
aml_dev->out_device |= sink_config[i].ext.device.type;
|
||
}
|
||
}
|
||
|
||
if (src_config->type == AUDIO_PORT_TYPE_DEVICE) {
|
||
ret = patch_mgr_create_patch(aml_dev, num_sources, sources, num_sinks, sinks, handle);
|
||
if (ret != 0) {
|
||
AM_LOGE("device->device patch: unsupport input dev:%#x.", src_config->ext.device.type);
|
||
ret = -EINVAL;
|
||
}
|
||
}
|
||
|
||
AM_LOGI("patch handle(%d)", *handle);
|
||
return ret;
|
||
}
|
||
|
||
/* Release an audio patch */
|
||
static int adev_release_audio_patch(struct audio_hw_device *dev,
|
||
audio_patch_handle_t handle)
|
||
{
|
||
int ret = 0;
|
||
|
||
AM_LOGI("++ handle(%d)", handle);
|
||
if (dev) {
|
||
ret = patch_mgr_release_patch((struct aml_audio_device *)dev, handle);
|
||
}
|
||
AM_LOGI("-- after releasing patch, patch sets will be:");
|
||
|
||
return ret;
|
||
}
|
||
|
||
static char *adev_dump(const audio_hw_device_t *device, int fd)
|
||
{
|
||
struct aml_audio_device* aml_dev = (struct aml_audio_device*)device;
|
||
const int kNumRetries = 5;
|
||
const int kSleepTimeMS = 100;
|
||
int retry = kNumRetries;
|
||
int size;
|
||
char *string = NULL;
|
||
int ret = 0;
|
||
int buffer_frames = 0;
|
||
|
||
#ifdef BUILD_LINUX
|
||
fd = open("/tmp/haldump", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
|
||
if (fd < 0) {
|
||
ALOGE("Cannot access /tmp for dump");
|
||
return NULL;
|
||
}
|
||
#endif
|
||
aml_dev->debug_flag = aml_audio_get_debug_flag();
|
||
dprintf(fd, "AUDIO_HAL_GIT_VERSION %s\n",libVersion_audio_hal);
|
||
|
||
dprintf(fd, "\n-------------[AML_HAL] primary audio hal[dev:%p]------------------\n", aml_dev);
|
||
while (retry > 0 && pthread_mutex_trylock(&aml_dev->lock) != 0) {
|
||
usleep(kSleepTimeMS * 1000);
|
||
retry--;
|
||
}
|
||
|
||
if (retry > 0) {
|
||
aml_dev_dump_latency(aml_dev, fd);
|
||
pthread_mutex_unlock(&aml_dev->lock);
|
||
} else {
|
||
// Couldn't lock
|
||
dprintf(fd, "[AML_HAL] Could not obtain aml_dev lock.\n");
|
||
}
|
||
|
||
adev_audio_patches_dump(aml_dev, fd);
|
||
|
||
dprintf(fd, "\n-------------[AML_HAL] extra info------------------\n");
|
||
dprintf(fd, "[AML_HAL] hdmi_format : %10d | active_outport : %s | active_inport: %s\n",
|
||
aml_dev->hdmi_format, outputPort2Str(aml_dev->active_outport), inputPort2Str(get_active_inport(aml_dev)));
|
||
dprintf(fd, "[AML_HAL] dvb_standards : %d\n", aml_dev->dvb_standards);
|
||
dprintf(fd, "[AML_HAL] injection : %d\n", aml_dev->injection_enable);
|
||
#ifndef NO_AUDIO_CAP
|
||
pthread_mutex_lock(&aml_dev->cap_handle_lock);
|
||
dprintf(fd, "[AML_HAL] capture enable : %d\n", aml_dev->capture_handle ? 1 :0);
|
||
if (aml_dev->capture_handle) {
|
||
aml_audio_capture_out_dump(aml_dev->capture_handle, fd);
|
||
}
|
||
pthread_mutex_unlock(&aml_dev->cap_handle_lock);
|
||
#endif
|
||
dprintf(fd, "[AML_HAL] last_stream_write_data : %10d | stream_write_data : %d\n",
|
||
aml_dev->last_stream_write_data, aml_dev->stream_write_data);
|
||
dprintf(fd, "[AML_HAL] continuous_standby : %10d\n",
|
||
audio_continuous_standby_check(aml_dev->ms12.continuous_standby_handle));
|
||
|
||
audio_continuous_standby_dump(aml_dev->ms12.continuous_standby_handle, fd);
|
||
dolby_ms12_get_app_buffer_frame(&buffer_frames);
|
||
|
||
dprintf(fd, "[AML_HAL] audio_process_bitwidth: %2d bit\n", aml_dev->audio_process_bitwidth);
|
||
|
||
dprintf(fd, "[AML_HAL] A2DP gain : %10f \n",
|
||
aml_dev->sink_gain[OUTPORT_A2DP]);
|
||
dprintf(fd, "[AML_HAL] SPEAKER gain : %10f | HDMI gain: %f | USB SPK gain: %f | BT gain: %f\n",
|
||
aml_dev->sink_gain[OUTPORT_SPEAKER], aml_dev->sink_gain[OUTPORT_HDMI], aml_dev->sink_gain[OUTPORT_USB_HEADSET], aml_dev->sink_gain[OUTPORT_BT_SCO_HEADSET]);
|
||
dprintf(fd, "[AML_HAL] dtv_src gain : %10f | atv gain: %f | hdmi gain: %f | hdmi1 gain: %f | linein: %f | media gain: %f\n",
|
||
get_inport_gain(aml_dev, INPORT_TUNER), get_inport_gain(aml_dev, INPORT_ATV), get_inport_gain(aml_dev, INPORT_HDMIIN), get_inport_gain(aml_dev, INPORT_HDMIIN1), get_inport_gain(aml_dev, INPORT_LINEIN), get_inport_gain(aml_dev, INPORT_MEDIA));
|
||
dprintf(fd, "[AML_HAL] ms12 main volume : %10f\n", aml_dev->ms12.main_volume);
|
||
dprintf(fd, "[AML_HAL] decoder DRC control : %10d\n", aml_dev->decoder_drc_control);
|
||
dprintf(fd, "[AML_HAL] DAP DRC control : %10d\n", aml_dev->dap_drc_control);
|
||
dprintf(fd, "[AML_HAL] downmix type : %10d\n", aml_dev->downmix_type);
|
||
dprintf(fd, "[AML_HAL] UI disable dap : %10d\n", aml_dev->ms12.UI_disable_dap);
|
||
dprintf(fd, "[AML_HAL] internal disable dap : %10d\n", aml_dev->ms12.internal_disable_dap);
|
||
dprintf(fd, "[AML_HAL] pic mode : %10d\n", get_dev_pic_mode());
|
||
|
||
dprintf(fd, "[AML_HAL] dap_enable : %10d\n", aml_dev->ms12.dap_enable);
|
||
dprintf(fd, "[AML_HAL] ms12.main_input_fmt : %10d\n", aml_dev->ms12.main_input_fmt);
|
||
dprintf(fd, "[AML_HAL] dolby_drc_mode : %10d(0:line,1:RF)\n", aml_dev->ms12.dolby_drc_mode);
|
||
dprintf(fd, "[AML_HAL]stereo_out_drc_cur_volume : %10f\n", aml_dev->ms12.stereo_out_drc_cur_volume);
|
||
dprintf(fd, "[AML_HAL]stereo_out_drc_target_volume: %10f\n", aml_dev->ms12.stereo_out_drc_target_volume);
|
||
dprintf(fd, "[AML_HAL]dap_out_drc_cur_volume : %10f\n", aml_dev->ms12.dap_out_drc_cur_volume);
|
||
dprintf(fd, "[AML_HAL]dap_out_drc_target_volume : %10f\n", aml_dev->ms12.dap_out_drc_target_volume);
|
||
dprintf(fd, "[AML_HAL] ac4_de : %10d\n", aml_dev->ms12.ac4_de);
|
||
dprintf(fd, "[AML_HAL] dap_de : %10d,%d\n", aml_dev->ms12.dap_de_enable, aml_dev->ms12.dap_de_amount);
|
||
dprintf(fd, "[AML_HAL] dap_leveler : %10d,%d\n", aml_dev->ms12.dap_leveler[0], aml_dev->ms12.dap_leveler[1]);
|
||
|
||
dprintf(fd, "[AML_HAL] master volume: %10f, mute: %d\n", aml_dev->master_volume, aml_dev->master_mute);
|
||
dprintf(fd, "[AML_HAL] ad vol: %10d, mix level: %10d\n", aml_dev->advol_level, aml_dev->mixing_level);
|
||
dprintf(fd, "[AML_HAL] sys stream level: %d bytes, app stream level: %d ms\n", dolby_ms12_get_system_buffer_avail(NULL), buffer_frames / 48);
|
||
aml_decoder_info_dump(aml_dev, fd);
|
||
if (aml_dev->dolby_lib_type == eDolbyMS12Lib) {
|
||
dolby_ms12_info_dump(fd);
|
||
} else {
|
||
mixer_dump(aml_dev, fd);
|
||
}
|
||
aml_adev_stream_out_dump(aml_dev, fd);
|
||
dprintf(fd, "\nAML stream outs:\n");
|
||
|
||
dprintf(fd, "[AML_HAL] sink format: %#x\n", aml_dev->sink_format);
|
||
if (OUTPORT_HDMI_ARC == aml_dev->active_outport) {
|
||
struct aml_arc_hdmi_desc *hdmi_desc = get_arc_hdmi_cap(aml_dev);
|
||
bool dd_is_support = hdmi_desc->dd_fmt.is_support;
|
||
bool ddp_is_support = hdmi_desc->ddp_fmt.is_support;
|
||
bool mat_is_support = hdmi_desc->mat_fmt.is_support;
|
||
|
||
dprintf(fd, "[AML_HAL] -dd: %d, ddp: %d, mat: %d\n",
|
||
dd_is_support, ddp_is_support, mat_is_support);
|
||
}
|
||
|
||
#ifdef AML_MALLOC_DEBUG
|
||
aml_audio_debug_malloc_showinfo(MEMINFO_SHOW_PRINT);
|
||
#endif
|
||
|
||
audio_hal_info_dump(aml_dev, fd);
|
||
aml_audio_spdif_info_dump(aml_dev, fd);
|
||
audio_input_dump(fd);
|
||
aml_audio_hwmixer_out_dump(aml_dev, fd);
|
||
aml_alsa_device_status_dump(aml_dev, fd);
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
aml_external_device_status_dump(aml_dev, fd);
|
||
#endif
|
||
aml_dump_policy_mappings(aml_dev, fd);
|
||
aml_alsa_mixer_status_dump(&aml_dev->alsa_mixer, fd);
|
||
karaoke_manager_dump(aml_dev->kara_manager, fd);
|
||
dprintf(fd, "\n-------------[AML_HAL] MS12 config info------------------\n");
|
||
switch (aml_dev->dolby_ms12_audio_config) {
|
||
case MS12_CONFIG_Y:
|
||
dprintf(fd, "[Ms12 Info] Dolby MS12 Config: %s\n", "Y");
|
||
break;
|
||
case MS12_CONFIG_X:
|
||
dprintf(fd, "[Ms12 Info] Dolby MS12 Config: %s\n", "X");
|
||
dprintf(fd, "[Ms12 Info] MS12 tuning config path: %s\n", DOLBY_TUNING_DAT);
|
||
break;
|
||
case MS12_CONFIG_Z:
|
||
dprintf(fd, "[Ms12 Info] Dolby MS12 Config: %s\n", "Z");
|
||
dprintf(fd, "[Ms12 Info] MS12 tuning config path: %s\n", DOLBY_TUNING_DAT);
|
||
break;
|
||
}
|
||
|
||
//#ifdef ENABLE_BT_A2DP
|
||
#ifndef BUILD_LINUX
|
||
a2dp_hal_dump(aml_dev, fd);
|
||
#endif
|
||
|
||
#ifdef BUILD_LINUX
|
||
size = lseek(fd, 0, SEEK_CUR);
|
||
if (size >= 0) {
|
||
string = aml_audio_calloc(size + 1, 1);
|
||
if (string) {
|
||
lseek(fd, 0, SEEK_SET);
|
||
ret = read(fd, string, size);
|
||
if (ret < 0) {
|
||
ALOGE("%s(), fail to read", __func__);
|
||
}
|
||
}
|
||
}
|
||
close(fd);
|
||
unlink("/tmp/haldump");
|
||
#endif
|
||
dprintf(fd, "\n-------------[AML_HAL] primary audio hal End---------------------\n");
|
||
return string;
|
||
}
|
||
|
||
pthread_mutex_t adev_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
static void * g_adev = NULL;
|
||
void *adev_get_handle(void) {
|
||
/*coverity[missing_lock]: g_adev does not need to be lock*/
|
||
return (void *)g_adev;
|
||
}
|
||
|
||
int adev_ms12_prepare(struct audio_hw_device *dev) {
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
int ret = -1;
|
||
audio_format_t aformat = AUDIO_FORMAT_E_AC3;
|
||
|
||
struct dolby_ms12_desc *ms12 = &(adev->ms12);
|
||
AM_LOGD("enter");
|
||
if (ms12->dap_only_enable) {
|
||
aml_dap_close(ms12);
|
||
}
|
||
|
||
get_sink_format(adev);
|
||
|
||
adev->ms12.is_continuous_paused = false;
|
||
ret = get_the_dolby_ms12_prepared(ms12, aformat, AUDIO_CHANNEL_OUT_STEREO, 48000);
|
||
|
||
AM_LOGD("exit");
|
||
return 0;
|
||
}
|
||
|
||
|
||
void adev_ms12_cleanup(struct audio_hw_device *dev) {
|
||
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
|
||
AM_LOGD("enter");
|
||
|
||
get_dolby_ms12_cleanup(&adev->ms12, true);
|
||
|
||
AM_LOGD("exit");
|
||
return;
|
||
}
|
||
|
||
static int adev_headphone_limiter_init(struct aml_audio_device *adev) {
|
||
int ret = -EXIT_FAILURE;
|
||
int headphone_limiter_enable = aml_get_json_int_value("Headphone_Limiter_Enable", 0);
|
||
if (!headphone_limiter_enable) {
|
||
ALOGI("Not support headpone limiter module");
|
||
return ret;
|
||
}
|
||
int format = adev->audio_process_bitwidth == 32 ? AUDIO_FORMAT_PCM_32_BIT : AUDIO_FORMAT_PCM_16_BIT;
|
||
int headphone_limiter_release_time = aml_get_json_int_value("Headphone_Limiter_ReleaseTime", 100);
|
||
adev->headphone_limiter = aml_audio_limiter_new(format);
|
||
if (adev->headphone_limiter) {
|
||
char *headphone_drc_peak_str = aml_get_json_string_value("Headphone_Limiter_Threshold");
|
||
if (!headphone_drc_peak_str) {
|
||
headphone_drc_peak_str = "-12.0f";
|
||
}
|
||
char *endptr;
|
||
float headphone_drc_peak = strtof(headphone_drc_peak_str, &endptr);
|
||
if (endptr == headphone_drc_peak_str) {
|
||
AM_LOGE("Invalid Headphone_DRC_Threshold value, use default -12.0f");
|
||
headphone_drc_peak = -12.0f;
|
||
}
|
||
float headphone_drc_peak_gain = DbToAmpl(headphone_drc_peak);
|
||
ret = aml_audio_limiter_set(adev->headphone_limiter, headphone_drc_peak_gain, 1, headphone_limiter_release_time, AML_LIMITER_PROC_FRAME, AML_LIMITER_DRC);
|
||
if (ret != 0) {
|
||
aml_audio_limiter_free(adev->headphone_limiter);
|
||
adev->headphone_limiter = NULL;
|
||
AM_LOGE("aml_audio_headphone_drc_set fail");
|
||
} else {
|
||
aml_audio_limiter_enable(adev->headphone_limiter, true);
|
||
if (adev->eq_data.p_gain.headphone > DbToAmpl(-headphone_drc_peak)) {
|
||
adev->eq_data.p_gain.headphone = DbToAmpl(-headphone_drc_peak);
|
||
AM_LOGE("HP post gain < Headphone_Limiter_Threshold with HP limiter, need reset to %fdb",-headphone_drc_peak);
|
||
}
|
||
AM_LOGI("Enable heaphone drc:%p, limiter peak is %f, release time is %d", adev->headphone_limiter, headphone_drc_peak_gain, headphone_limiter_release_time);
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static int adev_headphone_limiter_deint(struct aml_audio_device *adev) {
|
||
if (adev->headphone_limiter) {
|
||
aml_audio_limiter_free(adev->headphone_limiter);
|
||
adev->headphone_limiter = NULL;
|
||
}
|
||
return 0;
|
||
}
|
||
static int adev_close(hw_device_t *device)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)device;
|
||
|
||
pthread_mutex_lock(&adev_mutex);
|
||
ALOGD("%s: count:%d enter", __func__, adev->count);
|
||
adev->count--;
|
||
if (adev->count > 0) {
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
return 0;
|
||
}
|
||
|
||
pthread_mutex_destroy(&(adev->llp_lock));
|
||
|
||
/* destroy thread for communication between Audio Hal and MS12 */
|
||
if ((eDolbyMS12Lib == adev->dolby_lib_type)) {
|
||
ms12_mesg_thread_destroy(&adev->ms12);
|
||
ALOGD("%s, ms12_mesg_thread_destroy finished!\n", __func__);
|
||
}
|
||
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
adev_ms12_cleanup((struct audio_hw_device *)device);
|
||
pthread_mutex_destroy(&adev->ms12.bypass_ms12_lock);
|
||
}
|
||
|
||
#ifdef USE_MEDIAINFO
|
||
minfo_destroy(adev->minfo_h);
|
||
adev->minfo_h = NULL;
|
||
#endif
|
||
|
||
if (adev->effect_buf) {
|
||
aml_audio_free(adev->effect_buf);
|
||
}
|
||
if (adev->spdif_output_buf) {
|
||
aml_audio_free(adev->spdif_output_buf);
|
||
}
|
||
if (adev->hp_output_buf) {
|
||
aml_audio_free(adev->hp_output_buf);
|
||
}
|
||
if (adev->tmp_process_buf) {
|
||
aml_audio_free(adev->tmp_process_buf);
|
||
}
|
||
if (adev->tmp_buffer_8ch) {
|
||
aml_audio_free(adev->tmp_buffer_8ch);
|
||
adev->tmp_buffer_8ch = NULL;
|
||
}
|
||
if (adev->low_latency_buf) {
|
||
aml_audio_free(adev->low_latency_buf);
|
||
adev->low_latency_buf = NULL;
|
||
}
|
||
|
||
ring_buffer_release(&(adev->spk_tuning_rbuf));
|
||
ring_buffer_release(&(adev->spdif_rbuf));
|
||
#ifdef USE_EQ_DRC
|
||
eq_drc_release(&adev->eq_data);
|
||
#endif
|
||
|
||
if (adev->audio_mixer) {
|
||
deleteHalSubMixing(adev);
|
||
}
|
||
pthread_mutex_destroy(&adev->audio_mixer_lock);
|
||
|
||
if (adev->hw_mixer.start_buf) {
|
||
aml_hw_mixer_deinit(&adev->hw_mixer);
|
||
}
|
||
|
||
/** rlease some global shared resources **/
|
||
destroy_hdmi_capability_manager(adev);
|
||
destroy_hw_resource_mgr(adev);
|
||
destroy_patch_manager(adev);
|
||
|
||
pthread_mutex_destroy(&adev->dtv_patch_lock);
|
||
pthread_mutex_destroy(&adev->patch_lock);
|
||
pthread_mutex_destroy(&adev->active_outputs_lock);
|
||
pthread_mutex_destroy(&adev->low_latency_param_lock);
|
||
for (int i = I2S_DEVICE; i < ALSA_DEVICE_CNT; i++) {
|
||
pthread_mutex_destroy(&adev->alsa_lock[i]);
|
||
}
|
||
for (int i = SPDIF_HANDLE_1; i < SPDIF_HANDLE_CNT; i++) {
|
||
pthread_mutex_destroy(&adev->spdif_handle_lock[i]);
|
||
}
|
||
for (int i = 0; i < AUDIO_INPUT_TYPE_CNT; i++) {
|
||
pthread_mutex_destroy(&adev->input_handle_lock[i]);
|
||
}
|
||
pthread_mutex_destroy(&adev->hwmixer_mgr_lock);
|
||
aml_audio_delay_deinit();
|
||
release_alsa_device();
|
||
#ifdef NO_SERVER
|
||
adev->audio_debug_thread_exit = true;
|
||
if (adev->audio_debug_thread) {
|
||
pthread_join(adev->audio_debug_thread, NULL);
|
||
}
|
||
#endif
|
||
if (adev->mpegh_ui_persistencemem) {
|
||
aml_audio_free(adev->mpegh_ui_persistencemem);
|
||
adev->mpegh_ui_persistencememsize = 0;
|
||
adev->mpegh_ui_persistencemem = NULL;
|
||
}
|
||
if (adev->mpegh_base64_encode_mem) {
|
||
aml_audio_free(adev->mpegh_base64_encode_mem);
|
||
adev->mpegh_base64_encode_mem = NULL;
|
||
}
|
||
if (adev->mpegh_audioscenexml) {
|
||
aml_audio_free(adev->mpegh_audioscenexml);
|
||
adev->mpegh_audioscenexmlsize = 0;
|
||
adev->mpegh_audioscenexml = NULL;
|
||
}
|
||
|
||
if (adev->aml_command_worker) {
|
||
aml_audio_cmd_worker_thread_destroy(adev);
|
||
adev->aml_command_worker = NULL;
|
||
}
|
||
|
||
karaoke_manager_release(adev->kara_manager);
|
||
if (adev->enable_deep_unit) {
|
||
deep_buffer_unit_deinit(adev->deep_unit);
|
||
}
|
||
mixer_out_unit_deinit(adev->mixer_unit);
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
pthread_mutex_destroy(&adev->external_handle_lock);
|
||
aml_external_device_port_deinit(adev);
|
||
#endif
|
||
|
||
g_adev = NULL;
|
||
audio_effect_unload_interface(&(adev->hw_device));
|
||
if (is_STB(adev)) {
|
||
aml_audio_uevent_close();
|
||
}
|
||
close_mixer_handle(&adev->alsa_mixer);
|
||
adev_headphone_limiter_deint(adev);
|
||
aml_audio_free(device);
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
aml_audio_debug_malloc_close();
|
||
aml_audio_debug_close();
|
||
|
||
ALOGD("%s: exit", __func__);
|
||
return 0;
|
||
}
|
||
|
||
static int adev_set_audio_port_config (struct audio_hw_device *dev, const struct audio_port_config *config)
|
||
{
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *) dev;
|
||
enum OUT_PORT outport = OUTPORT_SPEAKER;
|
||
enum IN_PORT inport = INPORT_HDMIIN;
|
||
float volume = 0.0;
|
||
|
||
if (config == NULL) {
|
||
ALOGE("[%s:%d] audio_port_config is null", __func__, __LINE__);
|
||
return -EINVAL;
|
||
}
|
||
if ((config->config_mask & AUDIO_PORT_CONFIG_GAIN) == 0) {
|
||
ALOGE("[%s:%d] config_mask:%#x invalid", __func__, __LINE__, config->config_mask);
|
||
return -EINVAL;
|
||
}
|
||
ALOGI("++[%s:%d] audio_port id:%d, role:%d, type:%d", __func__, __LINE__, config->id, config->role, config->type);
|
||
|
||
if (config->type == AUDIO_PORT_TYPE_DEVICE) {
|
||
if (config->role == AUDIO_PORT_ROLE_SINK) {
|
||
android_dev_convert_to_hal_dev(config->ext.device.type, (int *)&outport);
|
||
aml_dev->sink_gain[outport] = DbToAmpl(config->gain.values[0] / 100.0);
|
||
if (outport == OUTPORT_HDMI_ARC) {
|
||
aml_dev->sink_gain[outport] = 1.0;
|
||
}
|
||
ALOGI(" - set sink device[%#x](outport:%s): volume_dB[%d], gain[%f]",
|
||
config->ext.device.type, outputPort2Str(outport),
|
||
config->gain.values[0], aml_dev->sink_gain[outport]);
|
||
ALOGI(" - now the sink gains are:");
|
||
ALOGI("\t- OUTPORT_SPEAKER->gain[%f]", aml_dev->sink_gain[OUTPORT_SPEAKER]);
|
||
ALOGI("\t- OUTPORT_HDMI_ARC->gain[%f]", aml_dev->sink_gain[OUTPORT_HDMI_ARC]);
|
||
ALOGI("\t- OUTPORT_HEADPHONE->gain[%f]", aml_dev->sink_gain[OUTPORT_HEADPHONE]);
|
||
ALOGI("\t- OUTPORT_HDMI->gain[%f]", aml_dev->sink_gain[OUTPORT_HDMI]);
|
||
ALOGI("\t- OUTPORT_USB_HEADSET->gain[%f]", aml_dev->sink_gain[OUTPORT_USB_HEADSET]);
|
||
ALOGI("\t- OUTPORT_BT_SOC_HEADSET->gain[%f]", aml_dev->sink_gain[OUTPORT_BT_SCO_HEADSET]);
|
||
ALOGI("\t- active outport is: %s", outputPort2Str(aml_dev->active_outport));
|
||
// sync volume to hwmixer
|
||
if (aml_dev->hwmixer_manager) {
|
||
hwmixer_mgr_set_volume_by_port(aml_dev->hwmixer_manager, aml_dev->active_outport);
|
||
}
|
||
} else if (config->role == AUDIO_PORT_ROLE_SOURCE) {
|
||
android_dev_convert_to_hal_dev(config->ext.device.type, (int *)&inport);
|
||
volume = DbToAmpl(config->gain.values[0] / 100.0);
|
||
if (volume < FLOAT_ZERO) {
|
||
volume = 0.0;
|
||
}
|
||
//aml_dev->src_gain[inport] = volume;
|
||
set_inport_gain(aml_dev, inport, volume);
|
||
ALOGI(" - set src device[%#x](inport:%s): volume db[%d], gain[%f][%f]",
|
||
config->ext.device.type, inputPort2Str(inport),
|
||
config->gain.values[0], volume, get_inport_gain(aml_dev, inport));
|
||
ALOGI(" - now the source gains are:");
|
||
ALOGI(" - INPORT_DTV->gain[%f]", get_inport_gain(aml_dev, INPORT_TUNER));
|
||
ALOGI(" - INPORT_ATV->gain[%f]", get_inport_gain(aml_dev, INPORT_ATV));
|
||
ALOGI(" - INPORT_HDMI->gain[%f]", get_inport_gain(aml_dev, INPORT_HDMIIN));
|
||
ALOGI(" - INPORT_HDMI1->gain[%f]", get_inport_gain(aml_dev, INPORT_HDMIIN1));
|
||
ALOGI(" - INPORT_AV->gain[%f]", get_inport_gain(aml_dev, INPORT_LINEIN));
|
||
ALOGI(" - INPORT_MEDIA->gain[%f]", get_inport_gain(aml_dev, INPORT_MEDIA));
|
||
ALOGI(" - set gain for in_port:%s, active inport is:%s", inputPort2Str(inport), inputPort2Str(get_active_inport(aml_dev)));
|
||
} else {
|
||
ALOGI("[%s:%d] unsupported role:%d type.", __func__, __LINE__, config->role);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int adev_get_dvb_standards ()
|
||
{
|
||
enum dtv_standards dtv_type = DTV_STANDARDS_EUDVB;
|
||
char *tuner_type = getenv("ro_vendor_platform_digitaltv_standards");
|
||
|
||
if (tuner_type != NULL) {
|
||
if (0 == strcmp(tuner_type, "atsc")) {
|
||
dtv_type = DTV_STANDARDS_ATSC;
|
||
} else if (0 == strcmp(tuner_type, "dtmb")) {
|
||
dtv_type = DTV_STANDARDS_DTMB;
|
||
} else if (0 == strcmp(tuner_type, "isdb")) {
|
||
dtv_type = DTV_STANDARDS_ISDB;
|
||
} else if (0 == strcmp(tuner_type, "sdtvb")) {
|
||
dtv_type = DTV_STANDARDS_SDTVB;
|
||
} else {
|
||
dtv_type = DTV_STANDARDS_EUDVB;
|
||
}
|
||
}
|
||
|
||
AM_LOGI("dtv tuner_type: %d", dtv_type);
|
||
return dtv_type;
|
||
}
|
||
|
||
static int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *port)
|
||
{
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *) dev;
|
||
enum OUT_PORT outport = OUTPORT_SPEAKER;
|
||
enum IN_PORT inport = INPORT_HDMIIN;
|
||
|
||
if (port == NULL) {
|
||
ALOGE("[%s:%d] port is null", __func__, __LINE__);
|
||
return -EINVAL;
|
||
}
|
||
ALOGI("++[%s:%d] audio_port_config id:%d, type:%x", __func__, __LINE__, port->active_config.id, port->ext.device.type);
|
||
|
||
if (port->active_config.id == AUDIO_PORT_ROLE_SOURCE) {
|
||
android_dev_convert_to_hal_dev(port->ext.device.type, (int *)&inport);
|
||
port->active_config.gain.values[0] = get_inport_gain(aml_dev, inport) * 100;
|
||
ALOGI("[%s:%d] device %x, inport %d, gain %d", __func__, __LINE__,
|
||
port->ext.device.type, inport, port->active_config.gain.values[0] );
|
||
} else if (port->active_config.id == AUDIO_PORT_ROLE_SINK) {
|
||
android_dev_convert_to_hal_dev(port->ext.device.type, (int *)&outport);
|
||
port->active_config.gain.values[0] = aml_dev->sink_gain[outport] * 100;
|
||
ALOGI("[%s:%d] device %x, outport %d, gain %d", __func__, __LINE__,
|
||
port->ext.device.type, outport, port->active_config.gain.values[0]);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Disable the treblebass attenuation parameter
|
||
*{0,4,4,3,1}
|
||
* 0 : states;
|
||
* 4 : psize;
|
||
* 4 : vsize;
|
||
* 3 : trebless comand;
|
||
* 1 : trebless comand value;
|
||
*/
|
||
#define SEND_TREBLEBASS_CMD(e) do { \
|
||
uint32_t _cmd[] = {0,4,4,3,1}; \
|
||
uint32_t _replySize = sizeof(uint32_t); \
|
||
uint32_t _replyData = 0; \
|
||
(*(e))->command(e, EFFECT_CMD_SET_PARAM, sizeof(_cmd), \
|
||
(effect_param_t *)_cmd, &_replySize, &_replyData); \
|
||
} while(0)
|
||
|
||
static int adev_add_device_effect(struct audio_hw_device *dev,
|
||
audio_port_handle_t device, effect_handle_t effect)
|
||
{
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *) dev;
|
||
int i;
|
||
int status = 0;
|
||
pthread_mutex_lock (&aml_dev->lock);
|
||
|
||
if (aml_dev->native_postprocess.num_postprocessors >= MAX_POSTPROCESSORS) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
|
||
/* Check if the effect already exists in the array */
|
||
for (i = 0; i < aml_dev->native_postprocess.num_postprocessors; i++) {
|
||
if (aml_dev->native_postprocess.postprocessors[i] == effect) {
|
||
status = 0;
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
effect_descriptor_t tmpdesc;
|
||
(*effect)->get_descriptor(effect, &tmpdesc);
|
||
int is_virtualx = (0 == strncmp(tmpdesc.name, "VirtualX", strlen("VirtualX")));
|
||
int is_hpeq = (0 == strncmp(tmpdesc.name, "Hpeq", strlen("Hpeq")));
|
||
int is_treblebass = (0 == strncmp(tmpdesc.name, "TrebleBass", strlen("TrebleBass")));
|
||
|
||
/* Determine insertion position */
|
||
int insert_pos = aml_dev->native_postprocess.num_postprocessors;
|
||
|
||
if (is_virtualx) {
|
||
aml_dev->native_postprocess.libvx_exist = true;
|
||
insert_pos = 0; // VirtualX always goes to first position
|
||
} else if (is_hpeq) {
|
||
// Check if VirtualX exists in current processors
|
||
int has_virtualx = 0;
|
||
if (aml_dev->native_postprocess.num_postprocessors > 0) {
|
||
effect_descriptor_t first_desc;
|
||
(*aml_dev->native_postprocess.postprocessors[0])->get_descriptor(aml_dev->native_postprocess.postprocessors[0], &first_desc);
|
||
has_virtualx = (0 == strncmp(first_desc.name, "VirtualX", strlen("VirtualX")));
|
||
}
|
||
insert_pos = has_virtualx ? 1 : 0; // Second position if VirtualX exists, else first
|
||
}
|
||
|
||
/* Shift subsequent elements and insert new effect */
|
||
for (i = aml_dev->native_postprocess.num_postprocessors; i > insert_pos; i--) {
|
||
aml_dev->native_postprocess.postprocessors[i] = aml_dev->native_postprocess.postprocessors[i-1];
|
||
}
|
||
aml_dev->native_postprocess.postprocessors[insert_pos] = effect;
|
||
aml_dev->native_postprocess.num_postprocessors++;
|
||
|
||
if (is_hpeq || is_treblebass) {
|
||
|
||
/* Find companion effect */
|
||
effect_handle_t target_soundeffect_handle = NULL;
|
||
const char *target_name = is_hpeq ? "TrebleBass" : "Hpeq";
|
||
for (int i = 0; i < aml_dev->native_postprocess.num_postprocessors; i++) {
|
||
effect_descriptor_t d;
|
||
(*aml_dev->native_postprocess.postprocessors[i])->get_descriptor(aml_dev->native_postprocess.postprocessors[i], &d);
|
||
if (!strncmp(d.name, target_name, strlen(target_name))) {
|
||
target_soundeffect_handle = aml_dev->native_postprocess.postprocessors[i];
|
||
break;
|
||
}
|
||
}
|
||
/* Both HPEQ+TrebleBass ,Use HPEQ attenuation only */
|
||
if (target_soundeffect_handle) {
|
||
SEND_TREBLEBASS_CMD(is_hpeq ? target_soundeffect_handle : effect);
|
||
}
|
||
|
||
/*Since Hpeq and Treblebass attenuates the signal, full band drc is used for signal compensation*/
|
||
aml_mixer_ctrl_set_int(&aml_dev->alsa_mixer, AML_MIXER_ID_AED_FULL_DRC_ENABLE, 1);
|
||
AM_LOGI("Enable EQ_DRC compensation for %s", tmpdesc.name);
|
||
}
|
||
|
||
AM_LOGD("add audio effect: %s in audio hal, effect_handle: %p, total num of effects: %d active_outport:%d",
|
||
tmpdesc.name, effect, aml_dev->native_postprocess.num_postprocessors, aml_dev->active_outport);
|
||
|
||
exit:
|
||
pthread_mutex_unlock (&aml_dev->lock);
|
||
return status;
|
||
}
|
||
|
||
static int adev_remove_device_effect(struct audio_hw_device *dev,
|
||
audio_port_handle_t device, effect_handle_t effect)
|
||
{
|
||
int i;
|
||
int status = -EINVAL;
|
||
bool found = false;
|
||
struct aml_audio_device *aml_dev = (struct aml_audio_device *) dev;
|
||
|
||
pthread_mutex_lock (&aml_dev->lock);
|
||
if (aml_dev->native_postprocess.num_postprocessors <= 0) {
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
effect_descriptor_t tmpdesc_in_queue;
|
||
effect_descriptor_t tmpdesc_remove;
|
||
if (!effect) {
|
||
ALOGE("%s:Check parameters correctly",__func__);
|
||
status = -ENOSYS;
|
||
goto exit;
|
||
}
|
||
(*effect)->get_descriptor(effect, &tmpdesc_remove);
|
||
for (i = 0; i < aml_dev->native_postprocess.num_postprocessors; i++) {
|
||
(*aml_dev->native_postprocess.postprocessors[i])->get_descriptor(aml_dev->native_postprocess.postprocessors[i], &tmpdesc_in_queue);
|
||
if (0 == strcmp(tmpdesc_in_queue.name, tmpdesc_remove.name)) {
|
||
aml_dev->native_postprocess.postprocessors[i] = NULL;
|
||
status = 0;
|
||
found = true;
|
||
aml_dev->native_postprocess.num_postprocessors--;
|
||
ALOGI("%s, remove audio effect: %s in audio hal",__FUNCTION__, tmpdesc_in_queue.name);
|
||
}
|
||
|
||
if (found) {
|
||
aml_dev->native_postprocess.postprocessors[i] = aml_dev->native_postprocess.postprocessors[i + 1];
|
||
if (0 == strncmp(tmpdesc_remove.name, "Hpeq", strlen("Hpeq"))) {
|
||
aml_mixer_ctrl_set_int(&aml_dev->alsa_mixer, AML_MIXER_ID_AED_FULL_DRC_ENABLE, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!found) {
|
||
ALOGI("%s %d, not found %s sound effect", __FUNCTION__, __LINE__, tmpdesc_remove.name);
|
||
} else {
|
||
ALOGI("%s %d, total num of effects: %d", __FUNCTION__, __LINE__, aml_dev->native_postprocess.num_postprocessors);
|
||
}
|
||
|
||
ALOGD("func:%s effect_handle_t:%p, active_outport:%d", __func__, effect, aml_dev->active_outport);
|
||
|
||
exit:
|
||
pthread_mutex_unlock (&aml_dev->lock);
|
||
return status;
|
||
}
|
||
|
||
static int aml_audio_focus(struct aml_audio_device *adev, bool on)
|
||
{
|
||
if (!adev)
|
||
return -1;
|
||
|
||
pthread_mutex_lock (&adev->lock);
|
||
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
||
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
||
struct audio_stream_out *out = (struct audio_stream_out *)aml_out;
|
||
if (aml_out && aml_out->stream_type != STREAM_APP_INPUT) {
|
||
AM_LOGI("focus on:%d focus_ratio:%f", on , adev->audio_focus_ratio);
|
||
out_set_volume_l(out, aml_out->last_volume_l_org, aml_out->last_volume_l_org);
|
||
}
|
||
}
|
||
pthread_mutex_unlock (&adev->lock);
|
||
|
||
return 0;
|
||
}
|
||
|
||
#ifdef NO_SERVER
|
||
#define AUDIO_DEBUG_FIFO_NAME "/data/audio_debug_fifo"
|
||
static void *audio_debug_threadloop(void *data)
|
||
{
|
||
struct aml_audio_device *adev = (struct aml_audio_device *)data;
|
||
int fd = 0;
|
||
char read_msg[256] = {0};
|
||
|
||
AM_LOGI("entry. adev: %p", adev);
|
||
if (adev == NULL) {
|
||
AM_LOGE("adev pointer invalid!");
|
||
goto Error;
|
||
}
|
||
|
||
prctl(PR_SET_NAME, (unsigned long)"audio_debug_thread");
|
||
|
||
fd = open(AUDIO_DEBUG_FIFO_NAME, O_RDONLY|O_NONBLOCK);
|
||
|
||
if (fd > 0) {
|
||
while (!adev->audio_debug_thread_exit) {
|
||
memset(read_msg, 0, sizeof(read_msg));
|
||
int ret = read(fd, read_msg, sizeof(read_msg));
|
||
if (ret > 0) {
|
||
AM_LOGI("msg: %s", read_msg);
|
||
size_t read_msg_len = strlen(read_msg);
|
||
if (read_msg_len > 0 && '\n' == read_msg[read_msg_len-1]) {
|
||
read_msg[read_msg_len-1] = '\0';
|
||
}
|
||
adev->hw_device.set_parameters(&adev->hw_device, read_msg);
|
||
} else {
|
||
aml_audio_sleep(2000000);
|
||
}
|
||
}
|
||
close(fd);
|
||
}
|
||
|
||
Error:
|
||
AM_LOGI("exit");
|
||
return ((void *)0);
|
||
}
|
||
#endif
|
||
|
||
static int adev_uevent_callback(int uevent_type) {
|
||
struct aml_audio_device *adev = adev_get_handle();
|
||
|
||
AM_LOGI("uevent type=%d", uevent_type);
|
||
switch (uevent_type) {
|
||
case UEVENT_TYPE_VMODE_CHANGE:
|
||
adev->reset_hdmitx_audio = true;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int adev_ioctl(struct audio_hw_device *dev, int cmd, void *param, int size) {
|
||
AM_LOGI("cmd: %d, size: %d", cmd, size);
|
||
if (cmd == AUDIO_IOCTL_CMD_TEST) {
|
||
int *arg_int = (int *)param;
|
||
for (int i = 0; i * 4 < size; i++) {
|
||
AM_LOGI("arg[%d]:%d", i, arg_int[i]);
|
||
arg_int[i] ++;
|
||
}
|
||
goto exit;
|
||
}
|
||
#ifdef L_PROJECT
|
||
else if (cmd >= AUDIO_IOCTL_CMD_KCONTROL_START && cmd <= AUDIO_IOCTL_CMD_KCONTROL_END) {
|
||
aml_kctl_func(cmd, param, size);
|
||
goto exit;
|
||
}
|
||
#endif
|
||
|
||
exit:
|
||
return 0;
|
||
}
|
||
|
||
static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
|
||
{
|
||
struct aml_audio_device *adev;
|
||
aml_audio_debug_malloc_open();
|
||
size_t bytes_per_frame = audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT)
|
||
* audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
|
||
int buffer_size = PLAYBACK_PERIOD_COUNT * DEFAULT_PLAYBACK_PERIOD_SIZE * bytes_per_frame;
|
||
int spk_tuning_buf_size = MAX_SPK_EXTRA_LATENCY_MS
|
||
* bytes_per_frame * MM_FULL_POWER_SAMPLING_RATE / 1000;
|
||
int spdif_ring_buf_size = SPDIF_RBUF_DATA_STORAGE_MS
|
||
* bytes_per_frame * MM_FULL_POWER_SAMPLING_RATE / 1000;
|
||
int spdif_tuning_latency = aml_audio_get_spdif_tuning_latency();
|
||
int card = CARD_AMLOGIC_BOARD;
|
||
int ret = 0, i;
|
||
audio_effect_t *audio_effect;
|
||
bool earctx_mode = true;
|
||
|
||
ALOGD("%s: enter, ver:%s", __func__, libVersion_audio_hal);
|
||
pthread_mutex_lock(&adev_mutex);
|
||
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
|
||
ret = -EINVAL;
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
goto err;
|
||
}
|
||
|
||
if (g_adev != NULL) {
|
||
ALOGI("adev exsits ,reuse");
|
||
adev = (struct aml_audio_device *)g_adev;
|
||
adev->count++;
|
||
*device = &adev->hw_device.common;
|
||
ALOGI("*device:%p",*device);
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
goto err;
|
||
}
|
||
|
||
adev = aml_audio_calloc(1, sizeof(struct aml_audio_device));
|
||
if (!adev) {
|
||
ret = -ENOMEM;
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
goto err;
|
||
}
|
||
g_adev = (void *)adev;
|
||
adev->count = 1;
|
||
pthread_mutex_unlock(&adev_mutex);
|
||
|
||
adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
|
||
adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_3_0;
|
||
adev->hw_device.common.module = (struct hw_module_t *)module;
|
||
adev->hw_device.common.close = adev_close;
|
||
|
||
adev->hw_device.init_check = adev_init_check;
|
||
adev->hw_device.set_voice_volume = adev_set_voice_volume;
|
||
adev->hw_device.set_master_volume = adev_set_master_volume;
|
||
adev->hw_device.get_master_volume = adev_get_master_volume;
|
||
adev->hw_device.set_master_mute = adev_set_master_mute;
|
||
adev->hw_device.get_master_mute = adev_get_master_mute;
|
||
adev->hw_device.set_mode = adev_set_mode;
|
||
adev->hw_device.set_mic_mute = adev_set_mic_mute;
|
||
adev->hw_device.get_mic_mute = adev_get_mic_mute;
|
||
adev->hw_device.set_parameters = adev_set_parameters;
|
||
adev->hw_device.get_parameters = adev_get_parameters;
|
||
adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
|
||
adev->hw_device.open_output_stream = adev_open_output_stream_new;
|
||
adev->hw_device.close_output_stream = adev_close_output_stream_new;
|
||
adev->hw_device.open_input_stream = adev_open_input_stream;
|
||
adev->hw_device.close_input_stream = adev_close_input_stream;
|
||
adev->hw_device.create_audio_patch = adev_create_audio_patch;
|
||
adev->hw_device.release_audio_patch = adev_release_audio_patch;
|
||
adev->hw_device.set_audio_port_config = adev_set_audio_port_config;
|
||
adev->hw_device.add_device_effect = adev_add_device_effect;
|
||
adev->hw_device.remove_device_effect = adev_remove_device_effect;
|
||
adev->hw_device.get_microphones = adev_get_microphones;
|
||
adev->hw_device.get_audio_port = adev_get_audio_port;
|
||
adev->hw_device.dump = adev_dump;
|
||
adev->hw_device.ioctl = adev_ioctl;
|
||
adev->hdmi_format = AUTO;
|
||
adev->is_hdmi_arc_interact_done = false;
|
||
adev->is_netflix_hide = false;
|
||
adev->user_setting_scaletempo = true;
|
||
adev->next_unique_ID = 0;
|
||
adev->audio_focus_ratio = 1.0;
|
||
adev->auto_test_debug_flag = false;
|
||
adev->sink_configured_dolby_capability = AUDIO_FORMAT_INVALID;
|
||
adev->sink_configured_dts_capability = AUDIO_FORMAT_INVALID;
|
||
adev->enable_soundbar_mode = false;
|
||
adev->is_early_suspend = false;
|
||
adev->dtv_mute = false;
|
||
pthread_mutex_init(&adev->llp_lock, NULL);
|
||
card = alsa_device_get_card_index();
|
||
if ((card < 0) || (card > 7)) {
|
||
ALOGE("error to get audio card");
|
||
ret = -EINVAL;
|
||
goto err_adev;
|
||
}
|
||
|
||
adev->card = card;
|
||
adev->has_hwmixer = alsa_device_has_hwmixer();
|
||
pthread_mutex_init(&adev->hwmixer_mgr_lock, NULL);
|
||
/* Set the default route before the PCM stream is opened */
|
||
adev->mode = AUDIO_MODE_NORMAL;
|
||
adev->out_device = AUDIO_DEVICE_OUT_SPEAKER;
|
||
adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
|
||
|
||
adev->eq_data.card = adev->card;
|
||
|
||
ret = aml_audio_output_routing(&adev->hw_device, OUTPORT_SPEAKER, false);
|
||
if (ret < 0) {
|
||
ALOGE("%s() routing failed", __func__);
|
||
ret = -EINVAL;
|
||
goto err_adev;
|
||
}
|
||
|
||
adev->effect_buf_size = buffer_size;
|
||
adev->effect_buf = aml_audio_malloc(buffer_size);
|
||
if (adev->effect_buf == NULL) {
|
||
ALOGE("malloc effect buffer failed");
|
||
ret = -ENOMEM;
|
||
goto err_adev;
|
||
}
|
||
memset(adev->effect_buf, 0, buffer_size);
|
||
adev->effect_ctrl.dap_enable = 0;
|
||
adev->effect_ctrl.vx_enable = 0;
|
||
adev->effect_ctrl.effect_mode = EFFECT_MODE_OFF;
|
||
adev->native_postprocess.effect_ctrl.effect_mode = EFFECT_MODE_OFF;
|
||
adev->effect_ctrl.virtualXlib1_state = 0;
|
||
|
||
adev->spdif_output_buf = aml_audio_malloc(buffer_size * 2);
|
||
if (adev->spdif_output_buf == NULL) {
|
||
ALOGE("no memory for spdif output buffer");
|
||
ret = -ENOMEM;
|
||
goto err_effect_buf;
|
||
}
|
||
memset(adev->spdif_output_buf, 0, buffer_size * 2);
|
||
|
||
adev->hp_output_buf = aml_audio_malloc(buffer_size);
|
||
if (adev->hp_output_buf == NULL) {
|
||
ALOGE("no memory for hp output buffer");
|
||
ret = -ENOMEM;
|
||
goto err_spdif_buf;
|
||
}
|
||
memset(adev->hp_output_buf, 0, buffer_size);
|
||
|
||
adev->tmp_process_buf_size = buffer_size;
|
||
adev->tmp_process_buf = aml_audio_malloc(buffer_size);
|
||
if (adev->tmp_process_buf == NULL) {
|
||
ALOGE("no memory for usb output buffer");
|
||
ret = -ENOMEM;
|
||
goto err_hp_buf;
|
||
}
|
||
memset(adev->tmp_process_buf, 0, buffer_size);
|
||
|
||
if (0 != aml_audio_config_parser()) {
|
||
ALOGE("%s() Audio Config file parsing error\n",__FUNCTION__);
|
||
} else {
|
||
audio_hal_property_list_loading();
|
||
adev->dvb_standards = adev_get_dvb_standards();
|
||
}
|
||
if (0 != aml_audio_avsync_parser()) {
|
||
ALOGE("%s() Audio Config file parsing error\n",__FUNCTION__);
|
||
} else {
|
||
audio_hal_avsync_latency_loading();
|
||
}
|
||
|
||
/* init speaker tuning buffers */
|
||
ret = ring_buffer_init(&(adev->spk_tuning_rbuf), spk_tuning_buf_size);
|
||
if (ret < 0) {
|
||
ALOGE("Fail to init audio spk_tuning_rbuf!");
|
||
goto err_tmp_process_buf;
|
||
}
|
||
adev->spk_tuning_buf_size = spk_tuning_buf_size;
|
||
|
||
/* init spdif ring buffers */
|
||
ret = ring_buffer_init(&(adev->spdif_rbuf), spdif_ring_buf_size);
|
||
if (ret < 0) {
|
||
ALOGE("Fail to init audio spdif_rbuf!");
|
||
goto err_ringbuf;
|
||
}
|
||
|
||
/* if no latency set by prop, use default one */
|
||
if (spdif_tuning_latency == 0) {
|
||
spdif_tuning_latency = DEFAULT_SPK_EXTRA_LATENCY_MS;
|
||
} else if (spdif_tuning_latency > MAX_SPK_EXTRA_LATENCY_MS) {
|
||
spdif_tuning_latency = MAX_SPK_EXTRA_LATENCY_MS;
|
||
} else if (spdif_tuning_latency < 0) {
|
||
spdif_tuning_latency = 0;
|
||
}
|
||
|
||
// try to detect which dolby lib is readable
|
||
adev->dolby_lib_type = detect_dolby_lib_type();
|
||
adev->dolby_lib_type_last = adev->dolby_lib_type;
|
||
adev->aml_dolby_lib_version = get_aml_dolby_lib_version();
|
||
adev->dev_ms12_version = adev->aml_dolby_lib_version->eDevVersion;
|
||
ALOGI("%s(), dolby_lib_type: %d, dev_ms12_version: %d", __func__,
|
||
adev->dolby_lib_type, adev->dev_ms12_version);
|
||
|
||
adev->dolby_decode_enable = dolby_lib_decode_enable(adev->dolby_lib_type_last);
|
||
bool dts_decoder_support = (aml_get_json_int_value("AML_Dts_Decoder_Support", 1) == 1) ? true : false;
|
||
adev->dts_lib_type = detect_dts_lib_type(dts_decoder_support);
|
||
if (adev->dts_lib_type == eDTSXLib) {
|
||
adev->dts_decode_enable = 1;
|
||
adev->dts_x_spk_drc_cut = aml_get_json_int_value("AML_Dts_Speaker_Drc_Cut", 100);
|
||
adev->dts_x_spk_drc_boost = aml_get_json_int_value("AML_Dts_Speaker_Drc_Boost", 100);
|
||
adev->dts_x_spk_drc_curve = aml_get_json_int_value("AML_Dts_Speaker_Drc_Curve", 2);
|
||
adev->dts_x_hdmi_drc_cut = aml_get_json_int_value("AML_Dts_HDMI_Drc_Cut", 100);
|
||
adev->dts_x_hdmi_drc_boost = aml_get_json_int_value("AML_Dts_HDMI_Drc_Boost", 100);
|
||
adev->dts_x_hdmi_drc_curve = aml_get_json_int_value("AML_Dts_HDMI_Drc_Curve", 2);
|
||
adev->dts_x_spdif_drc_cut = aml_get_json_int_value("AML_Dts_Spdif_Drc_Cut", 100);
|
||
adev->dts_x_spdif_drc_boost = aml_get_json_int_value("AML_Dts_Spdif_Drc_Boost", 100);
|
||
adev->dts_x_spdif_drc_curve = aml_get_json_int_value("AML_Dts_Spdif_Drc_Curve", 2);
|
||
adev->dts_x_hp_drc_cut = aml_get_json_int_value("AML_Dts_Headphone_Drc_Cut", 100);
|
||
adev->dts_x_hp_drc_boost = aml_get_json_int_value("AML_Dts_Headphone_Drc_Boost", 100);
|
||
adev->dts_x_hp_drc_curve = aml_get_json_int_value("AML_Dts_Headphone_Drc_Curve", 2);
|
||
if (is_TV(adev)) {
|
||
dtsx_spk_loudness_enable(aml_get_json_int_value("AML_Dts_SPK_Loudness_Enable", 1));
|
||
dtsx_spk_loudness_target(aml_get_json_int_value("AML_Dts_SPK_Loudness_Target", -20));
|
||
} else {
|
||
dtsx_spk_loudness_enable(aml_get_json_int_value("AML_Dts_PCM_Loudness_Output_Enable", 1));
|
||
dtsx_spk_loudness_target(aml_get_json_int_value("AML_Dts_PCM_Loudness_Output_Target", -20));
|
||
}
|
||
} else {
|
||
adev->dts_decode_enable = dts_lib_decode_enable();
|
||
}
|
||
adev->mpegh_decode_enable = mpegh_lib_decode_enable();
|
||
adev->dtsx_drc_enable = false;
|
||
|
||
/* convert MS to data buffer length need to cache */
|
||
adev->spk_tuning_lvl = (spdif_tuning_latency * bytes_per_frame * MM_FULL_POWER_SAMPLING_RATE) / 1000;
|
||
/* end of spker tuning things */
|
||
*device = &adev->hw_device.common;
|
||
adev->dts_post_gain = 1.0;
|
||
for (i = 0; i < OUTPORT_MAX; i++) {
|
||
adev->sink_gain[i] = 1.0f;
|
||
adev->last_volume[i] = 1.0f;
|
||
}
|
||
/* get the device Loudness level */
|
||
adev->loudness_level = get_loudness_level();
|
||
|
||
adev->need_remove_conti_mode = false;
|
||
adev->audio_process_bitwidth = aml_get_json_int_value("Audio_Process_BitWidth", 16);
|
||
adev->dual_spdif_support = aml_get_json_int_value(DUAL_SPDIF,0);
|
||
adev->ms12_force_ddp_out = aml_get_json_int_value(FORCE_DDP,0);
|
||
adev->ms12_cpu_affinity = aml_get_json_int_value("Ms12_CPU_Affinity", 12);
|
||
adev->ms12_thread_priority = aml_get_json_int_value("Ms12_Thread_Priority", 5);
|
||
adev->out_write_thread_priority = aml_get_json_int_value("Out_Write_Thread_Priority", 5);
|
||
adev->spdif_enable = true;
|
||
adev->ms12_dynamic_sleep = aml_audio_property_get_bool("ro.vendor.media.audio.ms12.dynamic_sleep", false);
|
||
adev->mpegh_ui_persistencemem = aml_audio_malloc(AML_MPEGH_PERSISTENCE_BUFSIZE);
|
||
adev->mpegh_ui_persistencememsize = AML_MPEGH_PERSISTENCE_BUFSIZE;
|
||
adev->mpegh_audioscenexml = NULL;
|
||
adev->mpegh_audioscenexmlsize = 0;
|
||
|
||
adev->hdmitx_multi_ch_src = aml_get_json_int_value("HDMITX_Multi_CH_Src_Select", -1);
|
||
adev->hdmitx_hbr_src = aml_get_json_int_value("HDMITX_HBR_Src_Select", -1);
|
||
adev->hdmitx_src = aml_get_json_int_value("HDMITX_Src_Select", -1);
|
||
adev->sbr_spk_ott_hbr_same_tdm = aml_get_json_int_value("SBR_Speaker_OTT_HBR_Same_TDM", 0);
|
||
if (adev->hdmitx_src != -1) {
|
||
adev->spdif_independent = true;
|
||
}
|
||
|
||
open_mixer_handle(&adev->alsa_mixer);
|
||
if (init_audio_hw_resource_mgr(adev, &adev->alsa_mixer) < 0) {
|
||
AM_LOGE("ERROR: init_audio_hw_resource_mgr failed");
|
||
ret = -EINVAL;
|
||
goto err_spdifbuf;
|
||
}
|
||
|
||
/*for ms12 case, we set default continuous mode*/
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
adev->is_ms12_tuning_dat = false;
|
||
adev->dolby_ms12_dap_init_mode = DAP_NO_PROC;
|
||
char* str_val = aml_get_json_string_value(DOLBY_MS12_CONFIG_TYPE);
|
||
if (NULL != str_val) {
|
||
adev->dolby_ms12_audio_config = (strcasestr(str_val, "Z") != NULL) ? MS12_CONFIG_Z : \
|
||
(strcasestr(str_val, "X") != NULL) ? MS12_CONFIG_X : MS12_CONFIG_Y;
|
||
if (adev->dolby_ms12_audio_config == MS12_CONFIG_Z || adev->dolby_ms12_audio_config == MS12_CONFIG_X) {
|
||
char *tuning_dat_ini_path = aml_audio_cfg_path_get("AMLOG_MS12_TUNING_DATA");
|
||
aml_ms12_version_t *ms12_version = get_aml_dolby_lib_version();
|
||
const char *default_tuing_data = (eDolbyMS12_V282 == ms12_version->eDevVersion) ? DOLBY_TUNING_DAT_V28 : DOLBY_TUNING_DAT;
|
||
const char *path_to_use = tuning_dat_ini_path ? tuning_dat_ini_path : default_tuing_data;
|
||
AM_LOGI("ms12_version:%d path_to_use %s tuning_dat_ini_path:%s default_tuing_data:%s",
|
||
ms12_version->eDevVersion, path_to_use, tuning_dat_ini_path, default_tuing_data);
|
||
adev->is_ms12_tuning_dat = is_ms12_tuning_dat_in_dut(path_to_use);
|
||
if (adev->is_ms12_tuning_dat) {
|
||
memset(adev->ms12_tuning_dat_path, 0, AUDIO_HAL_CHAR_MAX_LEN);
|
||
memcpy(adev->ms12_tuning_dat_path, path_to_use, strlen(path_to_use));
|
||
AM_LOGI("use dolby config %d, ms12_tuning_dat=%d, ms12_tuning_dat_path=%s", adev->dolby_ms12_audio_config, adev->is_ms12_tuning_dat, adev->ms12_tuning_dat_path);
|
||
}
|
||
if (is_STB(adev)) {
|
||
//STB set to Dolby config X, no DOLBY_TUNING_DAT, set DAP mode to DAP_CONTENT_PROC for content processing.
|
||
//If DOLBY_TUNING_DAT is present, it indicates soundbar product, requiring dap to be mounted at boot.
|
||
adev->dolby_ms12_dap_init_mode = adev->is_ms12_tuning_dat ? DAP_CONTENT_PROC_DEVICE_PROC_MODE : DAP_CONTENT_PROC_MODE;
|
||
} else {
|
||
if (!adev->is_ms12_tuning_dat) {
|
||
adev->dolby_ms12_audio_config = MS12_CONFIG_Y;
|
||
AM_LOGE("DOLBY_TUNING_DAT is missing, updated dolby config to Y (%s)", str_val);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
adev->dolby_ms12_audio_config = MS12_CONFIG_Y;
|
||
ALOGE("dolby config type needs to be configured");
|
||
}
|
||
}
|
||
|
||
pthread_mutex_init(&adev->patch_lock, NULL);
|
||
pthread_mutex_init(&adev->active_outputs_lock, NULL);
|
||
pthread_mutex_init(&adev->dtv_patch_lock, NULL);
|
||
pthread_mutex_init(&adev->low_latency_param_lock, NULL);
|
||
for (int i = I2S_DEVICE; i < ALSA_DEVICE_CNT; i++) {
|
||
pthread_mutex_init(&adev->alsa_lock[i], NULL);
|
||
}
|
||
for (int i = SPDIF_HANDLE_1; i < SPDIF_HANDLE_CNT; i++) {
|
||
pthread_mutex_init(&adev->spdif_handle_lock[i], NULL);
|
||
}
|
||
for (int i = 0; i < AUDIO_INPUT_TYPE_CNT; i++) {
|
||
pthread_mutex_init(&adev->input_handle_lock[i], NULL);
|
||
}
|
||
|
||
//set HDMI EDID
|
||
//add "Hdmi_EDID": "18,15,07,50,57,06,01,3e,1e,c0,5f,7e,07,67,04,03,7b,04,5a", to /vendor/etc/halaudio/aml_audio_config.json
|
||
//18(decimalism) is the length of EDID,
|
||
//SAD(hexadecimal) are 15,07,50(dd);57,06,01(ddp);3e,1e,c0(dts);5f,7e,07(dts-hd);67,04,03(mat);7b,04,5a(mpegh)
|
||
//Note:We don't need to set PCM EDID(09,7f,05),since AML_MIXER_ID_HDMIIN_AUDIO_EDID will keep the original PCM EDID
|
||
char* str_EDID = aml_get_json_string_value(HDMI_EDID);
|
||
if (NULL != str_EDID) {
|
||
AM_LOGI("str_EDID=%s", str_EDID);
|
||
unsigned int *ptr = (unsigned int *)(adev->Hdmi_EDID);
|
||
char *pt = NULL, *tmp = NULL;
|
||
int i = 0;
|
||
int edid_length = 0;
|
||
int array_length = EDID_ARRAY_MAX_LEN - TLV_HEADER_SIZE;
|
||
pt = strtok_r (str_EDID, ", ", &tmp);
|
||
//The format of HDMIIN EDID is:
|
||
//4 bytes (default value is 0), 4 bytes (EDID length), SAD,SAD... The length of SAD is 3 bytes
|
||
ptr[0] = 0;
|
||
while (pt != NULL && i < array_length) {
|
||
char *endptr;
|
||
if (i == 0) {
|
||
AM_LOGI("[%d] edid_length:%d(0x%x)", i , atoi(pt), atoi(pt));
|
||
edid_length = atoi (pt);//EDID_len
|
||
ptr[1] = edid_length;
|
||
}
|
||
else {
|
||
AM_LOGI("[%d] %ld(0x%lx)", i , strtol (pt, &endptr, 16), strtol (pt, &endptr, 16));
|
||
if (TLV_HEADER_SIZE + i - 1 < EDID_ARRAY_MAX_LEN) {
|
||
adev->Hdmi_EDID[TLV_HEADER_SIZE + i - 1] = strtol (pt, &endptr, 16);
|
||
} else {
|
||
AM_LOGE("index(%zd) is greater than or equal to total num(%d)", TLV_HEADER_SIZE + i - 1, EDID_ARRAY_MAX_LEN);
|
||
break;
|
||
}
|
||
}
|
||
pt = strtok_r (NULL, ", ", &tmp);
|
||
i++;
|
||
}
|
||
if (edid_length == (i - 1)) {
|
||
int suitable_edid_len = (edid_length <= (EDID_ARRAY_MAX_LEN - TLV_HEADER_SIZE)) ? (edid_length) : (EDID_ARRAY_MAX_LEN - TLV_HEADER_SIZE);
|
||
adev->Hdmi_EDID_len = suitable_edid_len;
|
||
aml_mixer_ctrl_set_array(&adev->alsa_mixer, AML_MIXER_ID_HDMIIN_AUDIO_EDID,
|
||
adev->Hdmi_EDID, (suitable_edid_len + TLV_HEADER_SIZE));
|
||
} else {
|
||
AM_LOGE("The EDID is error in json, edid_length(%d)!=real_len(%d)", edid_length, i - 1);
|
||
}
|
||
|
||
} else {
|
||
if (is_TV(adev)) {
|
||
char edid_string[3];
|
||
if (aml_mixer_ctrl_set_array(&adev->alsa_mixer, AML_MIXER_ID_HDMIIN_AUDIO_EDID, edid_string, TLV_HEADER_SIZE)) {
|
||
AM_LOGE("Set default EDID fail");
|
||
} else {
|
||
AM_LOGI("Set default EDID success");
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Set the earctx mode by the property, only need set false */
|
||
earctx_mode = aml_audio_property_get_bool("persist.sys.vendor.earc_settings", true);
|
||
if (!earctx_mode) {
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_EARC_TX_EARC_MODE, earctx_mode);
|
||
ALOGI("eARC_TX eARC Mode get from property: %d\n", earctx_mode);
|
||
}
|
||
|
||
adev->atoms_lock_flag = false;
|
||
|
||
if (eDolbyDcvLib == adev->dolby_lib_type) {
|
||
adev->dcvlib_bypass_enable = 1;
|
||
}
|
||
|
||
memset(&adev->dts_hd, 0, sizeof(struct dca_dts_dec));
|
||
adev->sound_track_mode = 0;
|
||
adev->downmix_type = AM_DOWNMIX_LORO;
|
||
|
||
ALOGI("%s() adev->dolby_lib_type = %d", __FUNCTION__, adev->dolby_lib_type);
|
||
adev->audio_type = LPCM;
|
||
|
||
/* init arc hdmi capability manager */
|
||
if (init_hdmi_capability_manager(adev) < 0) {
|
||
ALOGE("%s() line:%d error! new hdmi_capability_manager failed", __func__, __LINE__);
|
||
ret = -EINVAL;
|
||
goto err_spdifbuf;
|
||
}
|
||
|
||
/* init device patch manager */
|
||
if (init_patch_manager(adev) < 0) {
|
||
ALOGE("%s() line:%d error! new patch_manger failed", __func__, __LINE__);
|
||
ret = -EINVAL;
|
||
goto err_spdifbuf;
|
||
}
|
||
|
||
#ifdef USE_EQ_DRC
|
||
ret = eq_drc_init(&adev->eq_data);
|
||
if (ret >= 0) {
|
||
if (0 != (ret & NO_AMLOGIC_EFFECT_INI)) {
|
||
/*If AMLOGIC_EFFECT_INI file missing, set default EQ_DRC full band params
|
||
*#Amlogic_DRC_Param_Generator -M 0 -m 2 -b 0 -a 2 -r 100 -e 10 -k 0 -t 0 -o 10
|
||
*/
|
||
adev->Drc_data.band_id = 0;
|
||
adev->Drc_data.attrack_time = 2;
|
||
adev->Drc_data.release_time = 100;
|
||
adev->Drc_data.estimate_time = 10;
|
||
adev->Drc_data.K = 0;
|
||
adev->Drc_data.threshold = 0;
|
||
adev->Drc_data.offset = 10;
|
||
setfb_drc(adev->Drc_data.band_id,adev->Drc_data.attrack_time,adev->Drc_data.release_time,
|
||
adev->Drc_data.estimate_time, adev->Drc_data.K, adev->Drc_data.threshold, adev->Drc_data.offset);
|
||
aml_mixer_ctrl_set_int(&adev->alsa_mixer, AML_MIXER_ID_AED_FULL_DRC_ENABLE, 0);
|
||
}
|
||
ALOGI("%s() audio source gain: atv:%f, dtv:%f, hdmiin:%f, av:%f, media:%f", __func__,
|
||
adev->eq_data.s_gain.atv, adev->eq_data.s_gain.dtv,
|
||
adev->eq_data.s_gain.hdmi, adev->eq_data.s_gain.av, adev->eq_data.s_gain.media);
|
||
ALOGI("%s() audio device gain: speaker:%f, spdif_arc:%f, headphone:%f", __func__,
|
||
adev->eq_data.p_gain.speaker, adev->eq_data.p_gain.spdif_arc,
|
||
adev->eq_data.p_gain.headphone);
|
||
struct component_noise_gate *noise_gate = get_noise_gate_instance(adev);
|
||
aml_noise_gate_set_param(noise_gate, adev->eq_data.noise_gate.aml_ng_enable,
|
||
adev->eq_data.noise_gate.aml_ng_level,
|
||
adev->eq_data.noise_gate.aml_ng_attack_time,
|
||
adev->eq_data.noise_gate.aml_ng_release_time);
|
||
}
|
||
#else
|
||
adev->eq_data.s_gain.atv = 1.0;
|
||
adev->eq_data.s_gain.dtv = 1.0;
|
||
adev->eq_data.s_gain.hdmi= 1.0;
|
||
adev->eq_data.s_gain.av = 1.0;
|
||
adev->eq_data.s_gain.media = 1.0;
|
||
adev->eq_data.p_gain.speaker= 1.0;
|
||
adev->eq_data.p_gain.spdif_arc = 1.0;
|
||
adev->eq_data.p_gain.headphone = 1.0;
|
||
#endif
|
||
adev->aml_ai_audio_type = aml_ai_audio_support();
|
||
AM_LOGI("AI %s, type is %d", (adev->aml_ai_audio_type != eAmlAiAudioUnsupported) ? "support": "not support", adev->aml_ai_audio_type);
|
||
/* set source volume to audio_hw_resource_mgr, audiohal subsequent processing uses the value in audio_hw_resource_mgr */
|
||
set_inport_gain(adev, INPORT_ATV, adev->eq_data.s_gain.atv);
|
||
set_inport_gain(adev, INPORT_TUNER, adev->eq_data.s_gain.dtv);
|
||
set_inport_gain(adev, INPORT_HDMIIN, adev->eq_data.s_gain.hdmi);
|
||
set_inport_gain(adev, INPORT_HDMIIN1, adev->eq_data.s_gain.hdmi);
|
||
set_inport_gain(adev, INPORT_LINEIN, adev->eq_data.s_gain.av);
|
||
set_inport_gain(adev, INPORT_MEDIA, adev->eq_data.s_gain.media);
|
||
|
||
if (is_TV(adev) || is_SBR(adev)) {
|
||
adev->default_alsa_ch = aml_audio_get_default_alsa_output_ch();
|
||
} else {
|
||
/* for stb/ott, fixed 2 channels speaker output for alsa*/
|
||
adev->default_alsa_ch = 2;
|
||
}
|
||
adev_headphone_limiter_init(adev);
|
||
if (NULL == adev->headphone_limiter && adev->eq_data.p_gain.headphone > 1.0) {
|
||
adev->eq_data.p_gain.headphone = 1.0;
|
||
AM_LOGE("HP post gain < 0dB without HP limiter, reset to 0dB");
|
||
}
|
||
//Enable audio delay feature
|
||
//If the platform need audio delay feature, please add "Audio_Delay_Max": 1000 to aml_audio_config.json
|
||
adev->max_audio_delay = aml_get_json_int_value(AUDIO_DELAY_MAX, 0);
|
||
if (adev->max_audio_delay) {
|
||
ret = aml_audio_delay_init(adev->max_audio_delay);
|
||
if (ret < 0) {
|
||
ALOGE("[%s:%d] aml_audio_delay_init fail", __func__, __LINE__);
|
||
goto err_spdifbuf;
|
||
}
|
||
} else {
|
||
AM_LOGI("This platform doesn't support audio delay feature");
|
||
}
|
||
adev->advol_level = 75;
|
||
adev->master_volume = 1.0;
|
||
|
||
// FIXME: current MS12 is not compatible with SUBMIXER, when MS12 lib exists, use ms12 system.
|
||
if (eDolbyMS12Lib == adev->dolby_lib_type) {
|
||
adev->useSubMix = false;
|
||
} else {
|
||
adev->useSubMix = true;
|
||
}
|
||
pthread_mutex_init(&adev->audio_mixer_lock, NULL);
|
||
if (adev->useSubMix) {
|
||
ret = initHalSubMixing(MIXER_LPCM, adev, is_TV(adev));
|
||
if (0 != ret) {
|
||
AM_LOGE("initHalSubMixing err, need check!!");
|
||
}
|
||
adev->restart_device_flag = false;
|
||
}
|
||
|
||
#ifdef USE_MEDIAINFO
|
||
adev->minfo_h = minfo_init();
|
||
if (!adev->minfo_h) {
|
||
ALOGE("Mediainfo init failed");
|
||
}
|
||
adev->info_rid = -1;
|
||
adev->minfo_atmos_flag = -1;
|
||
#endif
|
||
|
||
// adev->debug_flag is set in hw_write()
|
||
// however, sometimes function didn't goto hw_write() before encounting error.
|
||
// set debug_flag here to see more debug log when debugging.
|
||
adev->debug_flag = aml_audio_get_debug_flag();
|
||
aml_audio_debug_open(aml_get_json_string_value(DUMP_DEFAULT_PATH));
|
||
|
||
#ifndef NO_AUDIO_CAP
|
||
pthread_mutex_init(&adev->cap_handle_lock, NULL);
|
||
#endif
|
||
|
||
//set default mode to line
|
||
aml_audio_set_drc_control("-drc 0 -bs 100 -cs 100", &adev->decoder_drc_control);
|
||
aml_audio_set_drc_control("-dap_drc 0 -b 100 -c 100", &adev->dap_drc_control);
|
||
adev->drc_mode_ui_config = false;
|
||
AM_LOGD("adev->decoder_drc_control(%d),adev->dap_drc_control(%d) adev->drc_mode_ui_config (%d)", adev->decoder_drc_control, adev->dap_drc_control,adev->drc_mode_ui_config);
|
||
|
||
if (is_STB(adev)) {
|
||
aml_audio_uevent_open(adev_uevent_callback);
|
||
AM_LOGI("regist uevent callback");
|
||
} else {
|
||
AM_LOGI("Not STB, do not regist uevent callback");
|
||
}
|
||
|
||
ALOGD("%s adev->dolby_lib_type:%d is_TV:%d", __func__, adev->dolby_lib_type, is_TV(adev));
|
||
//set msync log level
|
||
log_set_level(AVS_LOG_INFO);
|
||
|
||
adev->last_stream_write_data = true;
|
||
adev->native_postprocess.effect_ctrl.is_dts = false;
|
||
|
||
adev->tmp_buffer_8ch_size = 1024 * 4 * adev->default_alsa_ch;
|
||
/* coverity[TAINTED_SCALAR]: adev->default_alsa_ch may come from getenv, but under control */
|
||
adev->tmp_buffer_8ch = aml_audio_malloc(adev->tmp_buffer_8ch_size);
|
||
if (!adev->tmp_buffer_8ch) {
|
||
AM_LOGE("alloc tmp_buffer_8ch failed");
|
||
ret = -ENOMEM;
|
||
goto err_spdifbuf;
|
||
}
|
||
memset(adev->tmp_buffer_8ch, 0, adev->tmp_buffer_8ch_size);
|
||
|
||
karaoke_manager_init(&adev->kara_manager);
|
||
|
||
/* create thread for communication between Audio Hal and MS12 */
|
||
if ((eDolbyMS12Lib == adev->dolby_lib_type)) {
|
||
ret = dolby_ms12_desc_init(adev);
|
||
if (0 != ret) {
|
||
AM_LOGE("ms12_desc init fail!");
|
||
goto Err_MS12_Init;
|
||
}
|
||
adev->enable_deep_unit = aml_get_json_int_value("DEEP_BUFFER_UNIT_ENABLE", 0);
|
||
if (adev->enable_deep_unit) {
|
||
deep_buffer_unit_config deep_config;
|
||
deep_config.ms12_pointer = &adev->ms12;
|
||
deep_buffer_unit_init(&adev->deep_unit, &deep_config);
|
||
AM_LOGI("deep_buffer_unit_init success!");
|
||
}
|
||
}
|
||
|
||
mixer_out_unit_init(&adev->mixer_unit);
|
||
#ifdef SUPPORT_EXTERNAL_OUTPUT
|
||
pthread_mutex_init(&adev->external_handle_lock, NULL);
|
||
aml_external_device_port_init(adev);
|
||
#endif
|
||
audio_effect_load_interface(&(adev->hw_device), &audio_effect);
|
||
#ifdef __LP64__
|
||
adev->hw_device.common.reserved[0] = (uint64_t)audio_effect;
|
||
#else
|
||
adev->hw_device.common.reserved[0] = (uint32_t)audio_effect;
|
||
#endif
|
||
|
||
|
||
#ifdef NO_SERVER
|
||
adev->audio_debug_thread_exit = false;
|
||
if (pthread_create(&(adev->audio_debug_thread), NULL, &audio_debug_threadloop, (void *)adev)) {
|
||
AM_LOGE("create audio debug thread fail!!!");
|
||
} else {
|
||
AM_LOGI("create audio debug thread success!!!");
|
||
}
|
||
#endif
|
||
|
||
if (aml_audio_cmd_worker_thread_create(adev) < 0) {
|
||
ALOGE("%s() line:%d error! new aml_audio_cmd_worker_thread_create failed", __func__, __LINE__);
|
||
ret = -EINVAL;
|
||
goto err_adev;
|
||
}
|
||
|
||
AM_LOGD("exit dual_spdif_support(%d) audio_process_bitwidth(%d)", adev->dual_spdif_support, adev->audio_process_bitwidth);
|
||
return 0;
|
||
|
||
Err_MS12_Init:
|
||
aml_audio_free(adev->tmp_buffer_8ch);
|
||
err_spdifbuf:
|
||
ring_buffer_release(&adev->spdif_rbuf);
|
||
err_ringbuf:
|
||
ring_buffer_release(&adev->spk_tuning_rbuf);
|
||
err_tmp_process_buf:
|
||
aml_audio_free(adev->tmp_process_buf);
|
||
err_hp_buf:
|
||
aml_audio_free(adev->hp_output_buf);
|
||
err_spdif_buf:
|
||
aml_audio_free(adev->spdif_output_buf);
|
||
err_effect_buf:
|
||
aml_audio_free(adev->effect_buf);
|
||
err_adev:
|
||
aml_audio_free(adev);
|
||
/*coverity[LOCK_EVASION]: There will be no competition here*/
|
||
g_adev = NULL;
|
||
*device = NULL;
|
||
err:
|
||
return ret;
|
||
}
|
||
|
||
static struct hw_module_methods_t hal_module_methods = {
|
||
.open = adev_open,
|
||
};
|
||
|
||
struct audio_module HAL_MODULE_INFO_SYM = {
|
||
.common = {
|
||
.tag = HARDWARE_MODULE_TAG,
|
||
.module_api_version = AUDIO_MODULE_API_VERSION_0_1,
|
||
.hal_api_version = HARDWARE_HAL_API_VERSION,
|
||
.id = AUDIO_HARDWARE_MODULE_ID,
|
||
.name = "aml audio HW HAL",
|
||
.author = "amlogic, Corp.",
|
||
.methods = &hal_module_methods,
|
||
},
|
||
};
|