252 lines
9.5 KiB
C
252 lines
9.5 KiB
C
/*
|
|
* Copyright (C) 2025 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 "aml_policy"
|
|
#include "audio_hw.h"
|
|
#include "aml_policy.h"
|
|
#include "aml_audio_log.h"
|
|
|
|
typedef struct {
|
|
aml_output_device_type out_device;
|
|
aml_output_source_type src_type; //from mixer or main decoder
|
|
int decoder_id; //main decoder id
|
|
} aml_policy_mapping_t;
|
|
|
|
aml_policy_mapping_t g_policy_mappings[] = {
|
|
{AML_OUTPUT_DEVICE_DEFAULT, AML_OUTPUT_SOURCE_MIXER_OUTPUT, -1},
|
|
{AML_OUTPUT_DEVICE_HEADPHONE, AML_OUTPUT_SOURCE_MIXER_OUTPUT, -1},
|
|
{AML_OUTPUT_DEVICE_USB_SPEAKER, AML_OUTPUT_SOURCE_MIXER_OUTPUT, -1},
|
|
{AML_OUTPUT_DEVICE_BLUETOOTH_SPEAKER, AML_OUTPUT_SOURCE_MIXER_OUTPUT, -1},
|
|
};
|
|
pthread_mutex_t g_policy_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
aml_output_device_type aml_get_output_device_by_id(int decoder_id) {
|
|
aml_output_device_type device = AML_OUTPUT_DEVICE_DEFAULT;
|
|
if (decoder_id < 0) {
|
|
AM_LOGV("Invalid decoder_id: %d", decoder_id);
|
|
return device;
|
|
}
|
|
|
|
pthread_mutex_lock(&g_policy_lock);
|
|
for (int i = 0; i < AML_OUTPUT_DEVICE_MAX; i++) {
|
|
if (g_policy_mappings[i].decoder_id == decoder_id) {
|
|
device = g_policy_mappings[i].out_device;
|
|
AM_LOGV("Found decoder_id %d mapped to device %d", decoder_id, device);
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&g_policy_lock);
|
|
|
|
if (device == AML_OUTPUT_DEVICE_MAX) {
|
|
AM_LOGV("Decoder_id %d not found in policy mappings", decoder_id);
|
|
}
|
|
|
|
return device;
|
|
}
|
|
|
|
aml_policy_type aml_get_policy_by_id(int decoder_id) {
|
|
aml_policy_type policy = AML_POLICY_TYPE_NORMAL;
|
|
aml_output_device_type device = AML_OUTPUT_DEVICE_DEFAULT;
|
|
device = aml_get_output_device_by_id(decoder_id);
|
|
switch (device) {
|
|
case AML_OUTPUT_DEVICE_DEFAULT:
|
|
policy = AML_POLICY_TYPE_NORMAL;
|
|
break;
|
|
case AML_OUTPUT_DEVICE_HEADPHONE:
|
|
policy = AML_POLICY_TYPE_HEADPHONE;
|
|
break;
|
|
case AML_OUTPUT_DEVICE_USB_SPEAKER:
|
|
policy = AML_POLICY_TYPE_USB_SPEAKER;
|
|
break;
|
|
case AML_OUTPUT_DEVICE_BLUETOOTH_SPEAKER:
|
|
policy = AML_POLICY_TYPE_BLUETOOTH_SPEAKER;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return policy;
|
|
}
|
|
|
|
aml_policy_type aml_get_stream_policy(struct aml_stream_out *out, aml_stream_port_type out_type) {
|
|
aml_policy_type policy = AML_POLICY_TYPE_NORMAL;
|
|
struct aml_audio_device *adev = out->dev;
|
|
|
|
switch (out_type) {
|
|
case AML_STREAM_STEREO_PORT:
|
|
policy = aml_get_policy_by_id(out->decoder_id);
|
|
break;
|
|
case AML_STREAM_MULTI_CHANNEL_PORT:
|
|
policy = AML_POLICY_TYPE_NORMAL;
|
|
break;
|
|
case AML_STREAM_BYPASS_PORT:
|
|
//for dcv decoder, bypass port means ddp
|
|
if (out->optical_format >= out->hal_internal_format) {
|
|
policy = AML_POLICY_TYPE_NORMAL;
|
|
}
|
|
break;
|
|
case AML_STREAM_TRANSCODE_PORT:
|
|
if (out->optical_format >= out->hal_internal_format) {
|
|
if (out->hal_internal_format == AUDIO_FORMAT_E_AC3) {
|
|
if (adev->dual_spdif_support) {
|
|
policy = AML_POLICY_TYPE_NORMAL;
|
|
}
|
|
} else {
|
|
policy = AML_POLICY_TYPE_NORMAL;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
AM_LOGE("unsupported output port type: %d", out_type);
|
|
policy = AML_POLICY_TYPE_NONE;
|
|
break;
|
|
}
|
|
|
|
return policy;
|
|
|
|
}
|
|
|
|
aml_output_source_type aml_get_output_device_src_type(aml_output_device_type device) {
|
|
return g_policy_mappings[device].src_type;
|
|
}
|
|
|
|
int aml_restore_output_device_to_mixer_by_id(int id) {
|
|
if (id < 0) {
|
|
AM_LOGW("Invalid decoder_id: %d", id);
|
|
return 0;
|
|
}
|
|
|
|
//restore output_device by id
|
|
pthread_mutex_lock(&g_policy_lock);
|
|
for (int i = 0; i < AML_OUTPUT_DEVICE_MAX; i++) {
|
|
if (g_policy_mappings[i].decoder_id == id) {
|
|
g_policy_mappings[i].src_type = AML_OUTPUT_SOURCE_MIXER_OUTPUT;
|
|
g_policy_mappings[i].decoder_id = -1;
|
|
AM_LOGI("restore device %d to mixer out, id from %d to -1", g_policy_mappings[i].out_device, id);
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&g_policy_lock);
|
|
return 0;
|
|
}
|
|
|
|
int aml_restore_stream_by_output_device(aml_output_device_type device) {
|
|
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
|
int i = 0;
|
|
int decoder_id = g_policy_mappings[device].decoder_id;
|
|
|
|
//restore output_device
|
|
pthread_mutex_lock(&g_policy_lock);
|
|
if (g_policy_mappings[device].src_type != AML_OUTPUT_SOURCE_DECODER_OUTPUT) {
|
|
pthread_mutex_unlock(&g_policy_lock);
|
|
return 0;
|
|
}
|
|
g_policy_mappings[device].src_type = AML_OUTPUT_SOURCE_MIXER_OUTPUT;
|
|
g_policy_mappings[device].decoder_id = -1;
|
|
pthread_mutex_unlock(&g_policy_lock);
|
|
|
|
//restore old bound stream
|
|
pthread_mutex_lock (&adev->active_outputs_lock);
|
|
for (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 && decoder_id == aml_out->decoder_id) {
|
|
aml_out->out_device = AUDIO_DEVICE_OUT_SPEAKER;
|
|
out_set_stream_mute((struct audio_stream_out *)aml_out, false, false);
|
|
AM_LOGI("restore device %d to mixer out<--->restore stream:%p to speaker out",device, aml_out);
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock (&adev->active_outputs_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aml_set_output_device_by_id(int id, aml_output_device_type device) {
|
|
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
|
int i = 0;
|
|
audio_devices_t hal_device = AUDIO_DEVICE_OUT_SPEAKER;
|
|
|
|
//If output device is bound to an old id, unbind it first.
|
|
aml_restore_stream_by_output_device(device);
|
|
pthread_mutex_lock (&adev->active_outputs_lock);
|
|
for (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) {
|
|
// if the id is already bound to the old device, unbind it first.
|
|
aml_restore_output_device_to_mixer_by_id(id);
|
|
//set internal mute when binding to specified device
|
|
if (device != AML_OUTPUT_DEVICE_DEFAULT) {
|
|
out_set_stream_mute((struct audio_stream_out *)aml_out, true, false);
|
|
}
|
|
//set output device
|
|
switch (device) {
|
|
case AML_OUTPUT_DEVICE_DEFAULT:
|
|
hal_device = AUDIO_DEVICE_OUT_SPEAKER;
|
|
out_set_stream_mute((struct audio_stream_out *)aml_out, false, false);
|
|
break;
|
|
case AML_OUTPUT_DEVICE_HEADPHONE:
|
|
hal_device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
|
|
break;
|
|
case AML_OUTPUT_DEVICE_USB_SPEAKER:
|
|
hal_device = AUDIO_DEVICE_OUT_USB_HEADSET;
|
|
break;
|
|
case AML_OUTPUT_DEVICE_BLUETOOTH_SPEAKER:
|
|
hal_device = AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
aml_out->out_device = hal_device;
|
|
pthread_mutex_lock (&g_policy_lock);
|
|
g_policy_mappings[device].decoder_id = id;
|
|
g_policy_mappings[device].src_type = AML_OUTPUT_SOURCE_DECODER_OUTPUT;
|
|
pthread_mutex_unlock (&g_policy_lock);
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock (&adev->active_outputs_lock);
|
|
if (i == STREAM_NUM_MAX) {
|
|
AM_LOGI("can't find stream which id = %d", id);
|
|
}
|
|
AM_LOGI("set output device by id: %d, device: 0x%x", id, device);
|
|
return 0;
|
|
}
|
|
|
|
void aml_dump_policy_mappings(struct aml_audio_device* adev, int fd) {
|
|
pthread_mutex_lock(&g_policy_lock);
|
|
dprintf(fd, "\n-------------[AML_HAL] Current policy mappings: ---------------\n");
|
|
for (int i = 0; i < AML_OUTPUT_DEVICE_MAX; i++) {
|
|
const char *device_name = "Unknown";
|
|
const char *source_name = "Unknown";
|
|
|
|
switch (g_policy_mappings[i].out_device) {
|
|
case AML_OUTPUT_DEVICE_DEFAULT: device_name = "Default"; break;
|
|
case AML_OUTPUT_DEVICE_HEADPHONE: device_name = "Headphone"; break;
|
|
case AML_OUTPUT_DEVICE_USB_SPEAKER: device_name = "USB Speaker"; break;
|
|
case AML_OUTPUT_DEVICE_BLUETOOTH_SPEAKER: device_name = "Bluetooth"; break;
|
|
default: break;
|
|
}
|
|
|
|
switch (g_policy_mappings[i].src_type) {
|
|
case AML_OUTPUT_SOURCE_MIXER_OUTPUT: source_name = "Mixer"; break;
|
|
case AML_OUTPUT_SOURCE_DECODER_OUTPUT: source_name = "Decoder"; break;
|
|
default: break;
|
|
}
|
|
|
|
dprintf(fd,"\t\tDevice: %s, Source: %s, Decoder ID: %d\n",
|
|
device_name, source_name, g_policy_mappings[i].decoder_id);
|
|
}
|
|
pthread_mutex_unlock(&g_policy_lock);
|
|
}
|