summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:19:28 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:19:28 +0000
commit6de7526b05fe7c7eecc43e99ecdb100be7962a21 (patch)
tree8c013069e7442e5c4e240b876dccf71f6de28ee2
parent1648c555a806dafa5b618b49c8dc69e4f27cfe55 (diff)
parent643e59a3056ea3f1fd4e791a818229fbb42cabf7 (diff)
downloadlibhardware-android14-mainline-uwb-release.tar.gz
Change-Id: I924c8c4209ada3bba22e200c9b8bcf210aacd19d
-rw-r--r--Android.bp11
-rw-r--r--hardware.c9
-rw-r--r--include/hardware/keymaster_defs.h2
-rw-r--r--include/hardware/sensors.h3
-rw-r--r--modules/audio_remote_submix/audio_hw.cpp3
-rw-r--r--modules/gralloc/gralloc.cpp4
-rw-r--r--modules/sensors/dynamic_sensor/Android.bp25
-rw-r--r--modules/sensors/dynamic_sensor/ConnectionDetector.cpp4
-rw-r--r--modules/sensors/dynamic_sensor/DynamicSensorManager.h7
-rw-r--r--modules/sensors/dynamic_sensor/HidRawDevice.cpp14
-rw-r--r--modules/sensors/dynamic_sensor/HidRawSensor.cpp5
-rw-r--r--modules/sensors/dynamic_sensor/HidRawSensor.h6
-rw-r--r--modules/sensors/dynamic_sensor/README.md20
-rw-r--r--modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp7
-rw-r--r--modules/soundtrigger/sound_trigger_hw.c28
-rw-r--r--modules/usbaudio/audio_hal.c162
16 files changed, 246 insertions, 64 deletions
diff --git a/Android.bp b/Android.bp
index 92c77faa..6baab685 100644
--- a/Android.bp
+++ b/Android.bp
@@ -57,10 +57,14 @@ cc_library_headers {
"libbluetooth-types-header",
],
},
+ windows: {
+ enabled: true,
+ },
},
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
+ "com.android.media",
"com.android.media.swcodec",
],
min_sdk_version: "29",
@@ -75,7 +79,6 @@ cc_library_shared {
shared_libs: [
"libcutils",
"liblog",
- "libdl",
"libvndksupport",
],
cflags: [
@@ -87,6 +90,7 @@ cc_library_shared {
header_libs: ["libhardware_headers"],
export_header_lib_headers: ["libhardware_headers"],
+ host_supported: true,
recovery_available: true,
vendor_available: true,
vndk: {
@@ -94,6 +98,9 @@ cc_library_shared {
support_system_process: true,
},
target: {
+ host: {
+ exclude_shared_libs: ["libvndksupport"],
+ },
recovery: {
exclude_shared_libs: ["libvndksupport"],
},
diff --git a/hardware.c b/hardware.c
index 6e72ce9f..d0e91e97 100644
--- a/hardware.c
+++ b/hardware.c
@@ -30,7 +30,7 @@
#define LOG_TAG "HAL"
#include <log/log.h>
-#if !defined(__ANDROID_RECOVERY__)
+#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__)
#include <vndksupport/linker.h>
#endif
@@ -97,7 +97,7 @@ static int load(const char *id,
*/
handle = dlopen(path, RTLD_NOW);
} else {
-#if defined(__ANDROID_RECOVERY__)
+#if defined(__ANDROID_RECOVERY__) || !defined(__ANDROID__)
handle = dlopen(path, RTLD_NOW);
#else
handle = android_load_sphal_library(path, RTLD_NOW);
@@ -206,8 +206,13 @@ int hw_get_module_by_class(const char *class_id, const char *inst,
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
+#if defined(__ANDROID__)
else
strlcpy(name, class_id, PATH_MAX);
+#else
+ else
+ snprintf(name, PATH_MAX, "%s", class_id);
+#endif
/*
* Here we rely on the fact that calling dlopen multiple times on
diff --git a/include/hardware/keymaster_defs.h b/include/hardware/keymaster_defs.h
index 930aceb0..dd286d6d 100644
--- a/include/hardware/keymaster_defs.h
+++ b/include/hardware/keymaster_defs.h
@@ -175,6 +175,8 @@ typedef enum {
attestation is requested. */
KM_TAG_IDENTITY_CREDENTIAL_KEY = KM_BOOL | 721, /* This is an identity credential key */
KM_TAG_STORAGE_KEY = KM_BOOL | 722, /* storage encryption key */
+ KM_TAG_ATTESTATION_ID_SECOND_IMEI = KM_BYTES | 723, /* Used to provide the device's second
+ IMEI to be included in attestation */
/* Tags used only to provide data to or receive data from operations */
KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000, /* Used to provide associated data for AEAD modes. */
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index 6f4baf8f..7b844b8a 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -367,9 +367,11 @@ typedef struct {
float accuracy;
} heading_event_t;
+// LINT.IfChange
/**
* Union of the various types of sensor data
* that can be returned.
+ * This type needs to remain identical to ASensorEvent.
*/
typedef struct sensors_event_t {
/* must be sizeof(struct sensors_event_t) */
@@ -479,6 +481,7 @@ typedef struct sensors_event_t {
uint32_t reserved1[3];
} sensors_event_t;
+// LINT.ThenChange (frameworks/native/include/android/sensor.h)
/* see SENSOR_TYPE_META_DATA */
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp
index f96854b5..5019ae5b 100644
--- a/modules/audio_remote_submix/audio_hw.cpp
+++ b/modules/audio_remote_submix/audio_hw.cpp
@@ -679,7 +679,8 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
// FIXME this is using hard-coded strings but in the future, this functionality will be
// converted to use audio HAL extensions required to support tunneling
- if ((parms.getInt(String8("exiting"), exiting) == NO_ERROR) && (exiting > 0)) {
+ if ((parms.getInt(String8(AUDIO_PARAMETER_KEY_EXITING), exiting) == NO_ERROR)
+ && (exiting > 0)) {
struct submix_audio_device * const rsxadev =
audio_stream_get_submix_stream_out(stream)->dev;
pthread_mutex_lock(&rsxadev->lock);
diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp
index 87bda975..f7ea01cf 100644
--- a/modules/gralloc/gralloc.cpp
+++ b/modules/gralloc/gralloc.cpp
@@ -224,7 +224,11 @@ static int gralloc_alloc(alloc_device_t* dev,
case HAL_PIXEL_FORMAT_RAW16:
bytesPerPixel = 2;
break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ bytesPerPixel = 1;
+ break;
default:
+ ALOGE("gralloc_alloc bad format %d", format);
return -EINVAL;
}
diff --git a/modules/sensors/dynamic_sensor/Android.bp b/modules/sensors/dynamic_sensor/Android.bp
index bad60481..890da82d 100644
--- a/modules/sensors/dynamic_sensor/Android.bp
+++ b/modules/sensors/dynamic_sensor/Android.bp
@@ -157,3 +157,28 @@ cc_binary_host {
"test/HidRawDeviceTest.cpp",
],
}
+
+//
+// Android device test for HidRawDevice and HidRawSensor
+//
+// Assuming lunch target 1
+// $ cd test
+// $ mma -j .
+// $ adb push $ANDROID_BUILD_TOP/out/target/product/generic/vendor/bin/hidrawdevice_test /vendor/bin
+// $ adb shell hidrawdevice_test /dev/hidraw0
+//
+cc_binary {
+ name: "hidrawdevice_test",
+ defaults: ["dynamic_sensor_defaults"],
+
+ srcs: [
+ "test/HidRawDeviceTest.cpp",
+ ],
+
+ cflags: ["-DLOG_TO_CONSOLE=1"],
+
+ local_include_dirs: [
+ "test",
+ "HidUtils/test",
+ ],
+}
diff --git a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
index 85b99017..99dab5b0 100644
--- a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
+++ b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
@@ -194,9 +194,9 @@ void FileConnectionDetector::handleInotifyData(ssize_t len, const char *data) {
}
bool FileConnectionDetector::readInotifyData() {
- struct {
+ union {
struct inotify_event ev;
- char padding[NAME_MAX + 1];
+ char raw[sizeof(inotify_event) + NAME_MAX + 1];
} buffer;
bool ret = true;
diff --git a/modules/sensors/dynamic_sensor/DynamicSensorManager.h b/modules/sensors/dynamic_sensor/DynamicSensorManager.h
index b8a73203..2cae1208 100644
--- a/modules/sensors/dynamic_sensor/DynamicSensorManager.h
+++ b/modules/sensors/dynamic_sensor/DynamicSensorManager.h
@@ -125,10 +125,11 @@ private:
// daemons
std::vector<sp<BaseDynamicSensorDaemon>> mDaemonVector;
- // Sensor operation queue. Calls to the sensor HAL must complete within 1
- // second.
+ // Sensor operation queue. Calls to the sensor HAL should complete within ~1
+ // second, but to permit delayed replies due to sniff mode, etc., we use a
+ // slightly longer timeout here.
static constexpr std::chrono::milliseconds
- kSensorOpTimeout = std::chrono::milliseconds(900);
+ kSensorOpTimeout = std::chrono::milliseconds(1600);
std::mutex mSensorOpQueueLock;
std::queue<std::pair<uint64_t, std::shared_future<int>>> mSensorOpQueue;
uint64_t mNextSensorOpIndex = 0;
diff --git a/modules/sensors/dynamic_sensor/HidRawDevice.cpp b/modules/sensors/dynamic_sensor/HidRawDevice.cpp
index 2588483a..6032ed95 100644
--- a/modules/sensors/dynamic_sensor/HidRawDevice.cpp
+++ b/modules/sensors/dynamic_sensor/HidRawDevice.cpp
@@ -204,7 +204,7 @@ bool HidRawDevice::getFeature(uint8_t id, std::vector<uint8_t> *out) {
int res = ::ioctl(mDevFd, HIDIOCGFEATURE(size), mIoBuffer.data());
if (res < 0) {
LOG_E << "HidRawDevice::getFeature: feature " << static_cast<int>(id)
- << " ioctl returns " << res << " (" << ::strerror(res) << ")" << LOG_ENDL;
+ << " ioctl returned " << res << ", errno: " << ::strerror(errno) << LOG_ENDL;
return false;
}
@@ -249,8 +249,8 @@ bool HidRawDevice::setFeature(uint8_t id, const std::vector<uint8_t> &in) {
std::copy(in.begin(), in.end(), &mIoBuffer[1]);
int res = ::ioctl(mDevFd, HIDIOCSFEATURE(size), mIoBuffer.data());
if (res < 0) {
- LOG_E << "HidRawDevice::setFeature: feature " << id << " ioctl returns " << res
- << " (" << ::strerror(res) << ")" << LOG_ENDL;
+ LOG_E << "HidRawDevice::setFeature: feature " << id << " ioctl returned " << res
+ << ", errno: " << ::strerror(errno) << LOG_ENDL;
return false;
}
return true;
@@ -287,8 +287,8 @@ bool HidRawDevice::sendReport(uint8_t id, std::vector<uint8_t> &data) {
res = ::write(mDevFd, data.data(), size);
}
if (res < 0) {
- LOG_E << "HidRawDevice::sendReport: output " << id << " write returns " << res
- << " (" << ::strerror(res) << ")" << LOG_ENDL;
+ LOG_E << "HidRawDevice::sendReport: output " << id << " write returned "
+ << res << ", errno: " << ::strerror(errno) << LOG_ENDL;
return false;
}
return true;
@@ -302,8 +302,8 @@ bool HidRawDevice::receiveReport(uint8_t *id, std::vector<uint8_t> *data) {
uint8_t buffer[256];
int res = ::read(mDevFd, buffer, 256);
if (res < 0) {
- LOG_E << "HidRawDevice::receiveReport: read returns " << res
- << " (" << ::strerror(res) << ")" << LOG_ENDL;
+ LOG_E << "HidRawDevice::receiveReport: read returned " << res
+ << ", errno: " << ::strerror(errno) << LOG_ENDL;
return false;
}
diff --git a/modules/sensors/dynamic_sensor/HidRawSensor.cpp b/modules/sensors/dynamic_sensor/HidRawSensor.cpp
index 3759e7e9..c90f4f1a 100644
--- a/modules/sensors/dynamic_sensor/HidRawSensor.cpp
+++ b/modules/sensors/dynamic_sensor/HidRawSensor.cpp
@@ -1066,7 +1066,10 @@ bool HidRawSensor::getHeadTrackerEventData(const std::vector<uint8_t> &message,
bool HidRawSensor::getSensorEventData(const std::vector<uint8_t> &message,
sensors_event_t *event) {
for (const auto &rec : mTranslateTable) {
- int64_t v = (message[rec.byteOffset + rec.byteSize - 1] & 0x80) ? -1 : 0;
+ int64_t v = 0;
+ if (rec.minValue < 0) {
+ v = (message[rec.byteOffset + rec.byteSize - 1] & 0x80) ? -1 : 0;
+ }
for (int i = static_cast<int>(rec.byteSize) - 1; i >= 0; --i) {
v = (v << 8) | message[rec.byteOffset + i]; // HID is little endian
}
diff --git a/modules/sensors/dynamic_sensor/HidRawSensor.h b/modules/sensors/dynamic_sensor/HidRawSensor.h
index 074482a8..e4564a0f 100644
--- a/modules/sensors/dynamic_sensor/HidRawSensor.h
+++ b/modules/sensors/dynamic_sensor/HidRawSensor.h
@@ -154,9 +154,11 @@ private:
bool getReportFieldValue(const std::vector<uint8_t> &message,
ReportTranslateRecord* rec, ValueType* value) {
bool valid = true;
- int64_t v;
+ int64_t v = 0;
+ if (rec->minValue < 0) {
+ v = (message[rec->byteOffset + rec->byteSize - 1] & 0x80) ? -1 : 0;
+ }
- v = (message[rec->byteOffset + rec->byteSize - 1] & 0x80) ? -1 : 0;
for (int i = static_cast<int>(rec->byteSize) - 1; i >= 0; --i) {
v = (v << 8) | message[rec->byteOffset + i]; // HID is little endian
}
diff --git a/modules/sensors/dynamic_sensor/README.md b/modules/sensors/dynamic_sensor/README.md
index 5d5bd6d3..8af15a90 100644
--- a/modules/sensors/dynamic_sensor/README.md
+++ b/modules/sensors/dynamic_sensor/README.md
@@ -11,9 +11,9 @@
A few files need to be modified to add dynamic sensor support to a device. The
dynamic sensor HAL must be enabled in the device product makefile and in the
-sensor sub-HAL configuration file, raw HID devices must be configured, and raw
-HID device and dynamic sensor property permissions must be set up in the SELinux
-policy files.
+sensor sub-HAL configuration file, support for raw HID devices must be configured
+in the Linux kernel (`CONFIG_HIDRAW=y`), and SELinux policy files must be updated
+to provide the necessary permissions. Example changes are provided below.
```shell
acme-co$ git -C device/acme/rocket-phone diff
@@ -123,10 +123,8 @@ Once the file modifications are made, rebuild and flash. The dynamic sensor HAL
should be initialized and appear in the sensor service.
```shell
-acme-co$ make -j28 && fastboot flashall
-.
-.
-.
+acme-co$ build_and_flash_android
+...
acme-co$ adb logcat -d | grep DynamicSensorHal
12-15 18:18:45.735 791 791 D DynamicSensorHal: DynamicSensorsSubHal::getSensorsList_2_1 invoked.
12-15 18:18:47.474 791 791 D DynamicSensorHal: DynamicSensorsSubHal::initialize invoked.
@@ -134,8 +132,6 @@ acme-co$ adb shell dumpsys sensorservice | grep Dynamic
0000000000) Dynamic Sensor Manager | Google | ver: 1 | type: android.sensor.dynamic_sensor_meta(32) | perm: n/a | flags: 0x00000007
Dynamic Sensor Manager (handle=0x00000000, connections=1)
Dynamic Sensor Manager 0x00000000 | status: active | pending flush events 0
-acme-co$ adb logcat -c
-acme-co$
```
When a dynamic sensor is paired with the device (e.g., Bluetooth rocket buds),
@@ -145,9 +141,9 @@ it will appear in the sensor service.
acme-co$ adb logcat -d | grep "DynamicSensorHal\|hidraw\|Rocket"
12-15 18:19:55.268 157 157 I hid-generic 0003: 1234:5678.0001: hidraw0: BLUETOOTH HID v0.00 Device [RocketBuds] on
12-15 18:19:55.235 791 809 E DynamicSensorHal: return 1 sensors
-12-15 18:19:56.239 1629 1787 I SensorService: Dynamic sensor handle 0x1 connected, type 65536, name RocketBuds
-acme-co$ adb shell dumpsys sensorservice | grep Rocket
-0x00000001) RocketBuds | BLUETOOTH 1234:1234 | ver: 1 | type: com.google.hardware.sensor.hid_dynamic.headtracker(65536) | perm: n/a | flags: 0x00000020
+12-15 18:19:56.239 1629 1787 I SensorService: Dynamic sensor handle 0x1 connected, type 37, name RocketBuds
+acme-co$ adb shell dumpsys sensorservice | grep head_tracker
+0x00000001) RocketBuds | BLUETOOTH 1234:5678 | ver: 1 | type: android.sensor.head_tracker(37) | perm: n/a | flags: 0x00000020
acme-co$
```
diff --git a/modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp b/modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp
index 2a68e39a..7522ca75 100644
--- a/modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp
+++ b/modules/sensors/dynamic_sensor/test/HidRawDeviceTest.cpp
@@ -38,8 +38,7 @@ public:
std::unordered_set<unsigned int> interestedUsage{
ACCELEROMETER_3D, GYROMETER_3D, COMPASS_3D, CUSTOM};
- SP(HidRawDevice) device =
- std::make_shared<HidRawDevice>(std::string(devicePath), interestedUsage);
+ SP(HidRawDevice) device{new HidRawDevice(std::string(devicePath), interestedUsage)};
const HidDevice::HidDeviceInfo &info = device->getDeviceInfo();
LOG_V << "Sizeof descriptor: " << info.descriptor.size() << LOG_ENDL;
@@ -69,8 +68,8 @@ public:
// use HidRawSensor to operate the device, pick first digest
//
auto &reportDigest = device->mDigestVector[0];
- SP(HidRawSensor) sensor = std::make_shared<HidRawSensor>(
- device, reportDigest.fullUsage, reportDigest.packets);
+ SP(HidRawSensor) sensor{
+ new HidRawSensor(device, reportDigest.fullUsage, reportDigest.packets)};
if (!sensor->isValid()) {
LOG_E << "Sensor is not valid " << LOG_ENDL;
diff --git a/modules/soundtrigger/sound_trigger_hw.c b/modules/soundtrigger/sound_trigger_hw.c
index 38212c45..cae91cab 100644
--- a/modules/soundtrigger/sound_trigger_hw.c
+++ b/modules/soundtrigger/sound_trigger_hw.c
@@ -246,12 +246,10 @@ static void unload_all_sound_models(struct stub_sound_trigger_device *stdev);
static char *sound_trigger_keyphrase_event_alloc(sound_model_handle_t handle,
struct sound_trigger_recognition_config *config,
int recognition_status) {
- char *data;
- struct sound_trigger_phrase_recognition_event *event;
- data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
- if (!data)
+ struct sound_trigger_phrase_recognition_event *event =
+ calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
+ if (!event)
return NULL;
- event = (struct sound_trigger_phrase_recognition_event *)data;
event->common.status = recognition_status;
event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
event->common.model = handle;
@@ -279,18 +277,16 @@ static char *sound_trigger_keyphrase_event_alloc(sound_model_handle_t handle,
event->common.audio_config.sample_rate = 16000;
event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
- return data;
+ return (char*) event;
}
static char *sound_trigger_generic_event_alloc(sound_model_handle_t handle,
struct sound_trigger_recognition_config *config,
int recognition_status) {
- char *data;
- struct sound_trigger_generic_recognition_event *event;
- data = (char *)calloc(1, sizeof(struct sound_trigger_generic_recognition_event));
- if (!data)
+ struct sound_trigger_generic_recognition_event *event =
+ calloc(1, sizeof(struct sound_trigger_generic_recognition_event));
+ if (!event)
return NULL;
- event = (struct sound_trigger_generic_recognition_event *)data;
event->common.status = recognition_status;
event->common.type = SOUND_MODEL_TYPE_GENERIC;
event->common.model = handle;
@@ -301,7 +297,7 @@ static char *sound_trigger_generic_event_alloc(sound_model_handle_t handle,
event->common.audio_config.sample_rate = 16000;
event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
- return data;
+ return (char*) event;
}
void send_event_with_handle(sound_model_handle_t* model_handle_str,
@@ -338,15 +334,13 @@ void send_event_with_handle(sound_model_handle_t* model_handle_str,
ALOGI("Unknown Sound Model Type, No Event to Send");
}
} else if (event_type == EVENT_SOUND_MODEL) {
- char *data;
- data = (char *)calloc(1, sizeof(struct sound_trigger_model_event));
- if (!data) {
+ struct sound_trigger_model_event *event =
+ calloc(1, sizeof(struct sound_trigger_model_event));
+ if (!event) {
ALOGW("%s Could not allocate event", __func__);
return;
}
- struct sound_trigger_model_event *event;
- event = (struct sound_trigger_model_event *)data;
event->status = SOUND_MODEL_STATUS_UPDATED;
event->model = model_context->model_handle;
if (event) {
diff --git a/modules/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index fe921d69..d77f7ec6 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <inttypes.h>
+#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
@@ -118,6 +119,15 @@ struct stream_out {
audio_io_handle_t handle; // Unique constant for a stream
audio_patch_handle_t patch_handle; // Patch handle for this stream
+
+ bool is_bit_perfect; // True if the stream is open with bit-perfect output flag
+
+ // Mixer information used for volume handling
+ struct mixer* mixer;
+ struct mixer_ctl* volume_ctl;
+ int volume_ctl_num_values;
+ int max_volume_level;
+ int min_volume_level;
};
struct stream_in {
@@ -223,6 +233,14 @@ static const audio_channel_mask_t CHANNEL_INDEX_MASKS_MAP[FCC_24 + 1] = {
};
static const int CHANNEL_INDEX_MASKS_SIZE = AUDIO_ARRAY_SIZE(CHANNEL_INDEX_MASKS_MAP);
+static const char* ALL_VOLUME_CONTROL_NAMES[] = {
+ "PCM Playback Volume",
+ "Headset Playback Volume",
+ "Headphone Playback Volume",
+ "Master Playback Volume",
+};
+static const int VOLUME_CONTROL_NAMES_NUM = AUDIO_ARRAY_SIZE(ALL_VOLUME_CONTROL_NAMES);
+
/*
* Locking Helpers
*/
@@ -495,6 +513,45 @@ static bool are_devices_the_same(unsigned int left_num_devices,
left_num_devices, left_cards, left_devices);
}
+static void out_stream_find_mixer_volume_control(struct stream_out* out, int card) {
+ out->mixer = mixer_open(card);
+ if (out->mixer == NULL) {
+ ALOGI("%s, no mixer found for card=%d", __func__, card);
+ return;
+ }
+ unsigned int num_ctls = mixer_get_num_ctls(out->mixer);
+ for (int i = 0; i < VOLUME_CONTROL_NAMES_NUM; ++i) {
+ for (unsigned int j = 0; j < num_ctls; ++j) {
+ struct mixer_ctl *ctl = mixer_get_ctl(out->mixer, j);
+ enum mixer_ctl_type ctl_type = mixer_ctl_get_type(ctl);
+ if (strcasestr(mixer_ctl_get_name(ctl), ALL_VOLUME_CONTROL_NAMES[i]) == NULL ||
+ ctl_type != MIXER_CTL_TYPE_INT) {
+ continue;
+ }
+ ALOGD("%s, mixer volume control(%s) found", __func__, ALL_VOLUME_CONTROL_NAMES[i]);
+ out->volume_ctl_num_values = mixer_ctl_get_num_values(ctl);
+ if (out->volume_ctl_num_values <= 0) {
+ ALOGE("%s the num(%d) of volume ctl values is wrong",
+ __func__, out->volume_ctl_num_values);
+ out->volume_ctl_num_values = 0;
+ continue;
+ }
+ out->max_volume_level = mixer_ctl_get_range_max(ctl);
+ out->min_volume_level = mixer_ctl_get_range_min(ctl);
+ if (out->max_volume_level < out->min_volume_level) {
+ ALOGE("%s the max volume level(%d) is less than min volume level(%d)",
+ __func__, out->max_volume_level, out->min_volume_level);
+ out->max_volume_level = 0;
+ out->min_volume_level = 0;
+ continue;
+ }
+ out->volume_ctl = ctl;
+ return;
+ }
+ }
+ ALOGI("%s, no volume control found", __func__);
+}
+
/*
* HAl Functions
*/
@@ -544,7 +601,8 @@ static int stream_set_new_devices(struct pcm_config *config,
unsigned int num_devices,
const int cards[],
const int devices[],
- int direction)
+ int direction,
+ bool is_bit_perfect)
{
int status = 0;
stream_clear_devices(alsa_devices);
@@ -561,7 +619,7 @@ static int stream_set_new_devices(struct pcm_config *config,
__func__, cards[i], devices[i]);
goto exit;
}
- status = proxy_prepare(&device_info->proxy, &device_info->profile, config);
+ status = proxy_prepare(&device_info->proxy, &device_info->profile, config, is_bit_perfect);
if (status != 0) {
ALOGE("%s failed to prepare device card=%d;device=%d",
__func__, cards[i], devices[i]);
@@ -709,7 +767,31 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream)
static int out_set_volume(struct audio_stream_out *stream, float left, float right)
{
- return -ENOSYS;
+ struct stream_out *out = (struct stream_out *)stream;
+ int result = -ENOSYS;
+ stream_lock(&out->lock);
+ if (out->volume_ctl != NULL) {
+ int left_volume =
+ out->min_volume_level + ceil((out->max_volume_level - out->min_volume_level) * left);
+ int right_volume =
+ out->min_volume_level + ceil((out->max_volume_level - out->min_volume_level) * right);
+ int volumes[out->volume_ctl_num_values];
+ if (out->volume_ctl_num_values == 1) {
+ volumes[0] = left_volume;
+ } else {
+ volumes[0] = left_volume;
+ volumes[1] = right_volume;
+ for (int i = 2; i < out->volume_ctl_num_values; ++i) {
+ volumes[i] = left_volume;
+ }
+ }
+ result = mixer_ctl_set_array(out->volume_ctl, volumes, out->volume_ctl_num_values);
+ if (result != 0) {
+ ALOGE("%s error=%d left=%f right=%f", __func__, result, left, right);
+ }
+ }
+ stream_unlock(&out->lock);
+ return result;
}
/* must be called with hw device and output stream mutexes locked */
@@ -847,6 +929,16 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
ALOGV("adev_open_output_stream() handle:0x%X, devicesSpec:0x%X, flags:0x%X, addr:%s",
handle, devicesSpec, flags, address);
+ const bool is_bit_perfect = ((flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE);
+ if (is_bit_perfect && (config->format == AUDIO_FORMAT_DEFAULT ||
+ config->sample_rate == 0 ||
+ config->channel_mask == AUDIO_CHANNEL_NONE)) {
+ ALOGE("%s request bit perfect playback, config(format=%#x, sample_rate=%u, "
+ "channel_mask=%#x) must be specified", __func__, config->format,
+ config->sample_rate, config->channel_mask);
+ return -EINVAL;
+ }
+
struct stream_out *out;
out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
@@ -901,9 +993,14 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
} else if (profile_is_sample_rate_valid(&device_info->profile, config->sample_rate)) {
proxy_config.rate = config->sample_rate;
} else {
+ ret = -EINVAL;
+ if (is_bit_perfect) {
+ ALOGE("%s requesting bit-perfect but the sample rate(%u) is not valid",
+ __func__, config->sample_rate);
+ return ret;
+ }
proxy_config.rate = config->sample_rate =
profile_get_default_sample_rate(&device_info->profile);
- ret = -EINVAL;
}
/* TODO: This is a problem if the input does not support this rate */
@@ -920,9 +1017,14 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
if (profile_is_format_valid(&device_info->profile, fmt)) {
proxy_config.format = fmt;
} else {
+ ret = -EINVAL;
+ if (is_bit_perfect) {
+ ALOGE("%s request bit-perfect but the format(%#x) is not valid",
+ __func__, config->format);
+ return ret;
+ }
proxy_config.format = profile_get_default_format(&device_info->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
- ret = -EINVAL;
}
}
@@ -960,11 +1062,25 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
// and store THAT in proxy_config.channels
proxy_config.channels =
profile_get_closest_channel_count(&device_info->profile, out->hal_channel_count);
- proxy_prepare(&device_info->proxy, &device_info->profile, &proxy_config);
+ if (is_bit_perfect && proxy_config.channels != out->hal_channel_count) {
+ ALOGE("%s request bit-perfect, but channel mask(%#x) cannot find exact match",
+ __func__, config->channel_mask);
+ return -EINVAL;
+ }
+
+ ret = proxy_prepare(&device_info->proxy, &device_info->profile, &proxy_config, is_bit_perfect);
+ if (is_bit_perfect && ret != 0) {
+ ALOGE("%s failed to prepare proxy for bit-perfect playback, err=%d", __func__, ret);
+ return ret;
+ }
out->config = proxy_config;
list_add_tail(&out->alsa_devices, &device_info->list_node);
+ if ((flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE) {
+ out_stream_find_mixer_volume_control(out, device_info->profile.card);
+ }
+
/* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger
* So clear any errors that may have occurred above.
*/
@@ -998,6 +1114,17 @@ static void adev_close_output_stream(struct audio_hw_device *hw_dev,
out->conversion_buffer = NULL;
out->conversion_buffer_size = 0;
+ if (out->volume_ctl != NULL) {
+ for (int i = 0; i < out->volume_ctl_num_values; ++i) {
+ mixer_ctl_set_value(out->volume_ctl, i, out->max_volume_level);
+ }
+ out->volume_ctl = NULL;
+ }
+ if (out->mixer != NULL) {
+ mixer_close(out->mixer);
+ out->mixer = NULL;
+ }
+
device_lock(out->adev);
list_remove(&out->list_node);
out->adev->device_sample_rate = 0;
@@ -1383,6 +1510,8 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
ret = 0;
}
}
+ } else if (profile_is_sample_rate_valid(&device_info->profile, config->sample_rate)) {
+ in->config.rate = config->sample_rate;
}
} else if (profile_is_sample_rate_valid(&device_info->profile, config->sample_rate)) {
in->config.rate = config->sample_rate;
@@ -1449,7 +1578,8 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
// and store THAT in proxy_config.channels
in->config.channels =
profile_get_closest_channel_count(&device_info->profile, in->hal_channel_count);
- ret = proxy_prepare(&device_info->proxy, &device_info->profile, &in->config);
+ ret = proxy_prepare(&device_info->proxy, &device_info->profile, &in->config,
+ false /*require_exact_match*/);
if (ret == 0) {
in->standby = true;
@@ -1616,6 +1746,7 @@ static int adev_create_audio_patch(struct audio_hw_device *dev,
struct pcm_config *config = NULL;
struct stream_in *in = NULL;
struct stream_out *out = NULL;
+ bool is_bit_perfect = false;
unsigned int num_saved_devices = 0;
int saved_cards[AUDIO_PATCH_PORTS_MAX];
@@ -1656,6 +1787,7 @@ static int adev_create_audio_patch(struct audio_hw_device *dev,
alsa_devices = &out->alsa_devices;
lock = &out->lock;
config = &out->config;
+ is_bit_perfect = out->is_bit_perfect;
}
// Check if the patch handle match the recorded one if a valid patch handle is passed.
@@ -1704,12 +1836,14 @@ static int adev_create_audio_patch(struct audio_hw_device *dev,
struct alsa_device_info *device_info = stream_get_first_alsa_device(alsa_devices);
if (device_info != NULL) saved_transferred_frames = device_info->proxy.transferred;
- int ret = stream_set_new_devices(config, alsa_devices, num_configs, cards, devices, direction);
+ int ret = stream_set_new_devices(
+ config, alsa_devices, num_configs, cards, devices, direction, is_bit_perfect);
if (ret != 0) {
*handle = generatedPatchHandle ? AUDIO_PATCH_HANDLE_NONE : *handle;
stream_set_new_devices(
- config, alsa_devices, num_saved_devices, saved_cards, saved_devices, direction);
+ config, alsa_devices, num_saved_devices, saved_cards, saved_devices, direction,
+ is_bit_perfect);
} else {
*patch_handle = *handle;
}
@@ -1723,10 +1857,16 @@ static int adev_create_audio_patch(struct audio_hw_device *dev,
if (!wasStandby) {
device_lock(adev);
if (in != NULL) {
- start_input_stream(in);
+ ret = start_input_stream(in);
+ if (!ret) {
+ in->standby = false;
+ }
}
if (out != NULL) {
- start_output_stream(out);
+ ret = start_output_stream(out);
+ if (!ret) {
+ out->standby = false;
+ }
}
device_unlock(adev);
}