Merge "camera: initialize smart pointer before usage" am: 8f89886dad am: b893b0cedb
am: c8083cac38
Change-Id: I11bdbcdb80fa772d17c9088f43c01581d00e7851
diff --git a/hardware.c b/hardware.c
index 40ae1d1..6e72ce9 100644
--- a/hardware.c
+++ b/hardware.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#define LOG_TAG "HAL"
@@ -148,6 +149,25 @@
}
/*
+ * If path is in in_path.
+ */
+static bool path_in_path(const char *path, const char *in_path) {
+ char real_path[PATH_MAX];
+ if (realpath(path, real_path) == NULL) return false;
+
+ char real_in_path[PATH_MAX];
+ if (realpath(in_path, real_in_path) == NULL) return false;
+
+ const size_t real_in_path_len = strlen(real_in_path);
+ if (strncmp(real_path, real_in_path, real_in_path_len) != 0) {
+ return false;
+ }
+
+ return strlen(real_path) > real_in_path_len &&
+ real_path[real_in_path_len] == '/';
+}
+
+/*
* Check if a HAL with given name and subname exists, if so return 0, otherwise
* otherwise return negative. On success path will contain the path to the HAL.
*/
@@ -156,18 +176,18 @@
{
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH3, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH3) && access(path, R_OK) == 0)
return 0;
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH2) && access(path, R_OK) == 0)
return 0;
#ifndef __ANDROID_VNDK__
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH1) && access(path, R_OK) == 0)
return 0;
#endif
diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h
index edd1ada..be9e63a 100644
--- a/include/hardware/camera_common.h
+++ b/include/hardware/camera_common.h
@@ -117,6 +117,14 @@
* 4. Module initialization method. This will be called by the camera service
* right after the HAL module is loaded, to allow for one-time initialization
* of the HAL. It is called before any other module methods are invoked.
+ *
+ *******************************************************************************
+ * Version: 2.5 [CAMERA_MODULE_API_VERSION_2_5]
+ *
+ * This camera module version adds support to query characteristics of a
+ * non-standalone physical camera, which can only be accessed as part of a
+ * logical camera.
+ *
*/
/**
@@ -133,8 +141,9 @@
#define CAMERA_MODULE_API_VERSION_2_2 HARDWARE_MODULE_API_VERSION(2, 2)
#define CAMERA_MODULE_API_VERSION_2_3 HARDWARE_MODULE_API_VERSION(2, 3)
#define CAMERA_MODULE_API_VERSION_2_4 HARDWARE_MODULE_API_VERSION(2, 4)
+#define CAMERA_MODULE_API_VERSION_2_5 HARDWARE_MODULE_API_VERSION(2, 5)
-#define CAMERA_MODULE_API_VERSION_CURRENT CAMERA_MODULE_API_VERSION_2_4
+#define CAMERA_MODULE_API_VERSION_CURRENT CAMERA_MODULE_API_VERSION_2_5
/**
* All device versions <= HARDWARE_DEVICE_API_VERSION(1, 0xFF) must be treated
@@ -909,8 +918,41 @@
*/
int (*init)();
+ /**
+ * get_physical_camera_info:
+ *
+ * Return the static metadata for a physical camera as a part of a logical
+ * camera device. This function is only called for those physical camera
+ * ID(s) that are not exposed independently. In other words, camera_id will
+ * be greater or equal to the return value of get_number_of_cameras().
+ *
+ * Return values:
+ *
+ * 0: On a successful operation
+ *
+ * -ENODEV: The information cannot be provided due to an internal
+ * error.
+ *
+ * -EINVAL: The input arguments are invalid, i.e. the id is invalid,
+ * and/or the module is invalid.
+ *
+ * Version information (based on camera_module_t.common.module_api_version):
+ *
+ * CAMERA_MODULE_API_VERSION_1_x/2_0/2_1/2_2/2_3/2_4:
+ * Not provided by HAL module. Framework will not call this function.
+ *
+ * CAMERA_MODULE_API_VERSION_2_5 or higher:
+ * If any of the camera devices accessible through this camera module is
+ * a logical multi-camera, and at least one of the physical cameras isn't
+ * a stand-alone camera device, this function will be called by the camera
+ * framework. Calling this function with invalid physical_camera_id will
+ * get -EINVAL, and NULL static_metadata.
+ */
+ int (*get_physical_camera_info)(int physical_camera_id,
+ camera_metadata_t **static_metadata);
+
/* reserved for future use */
- void* reserved[5];
+ void* reserved[4];
} camera_module_t;
__END_DECLS
diff --git a/include/hardware/hwcomposer2.h b/include/hardware/hwcomposer2.h
index c9809ce..8d09393 100644
--- a/include/hardware/hwcomposer2.h
+++ b/include/hardware/hwcomposer2.h
@@ -270,7 +270,11 @@
HWC2_FUNCTION_GET_READBACK_BUFFER_FENCE,
HWC2_FUNCTION_GET_RENDER_INTENTS,
HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT,
- HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX
+ HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX,
+
+ // composer 2.3
+ HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
+ HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
} hwc2_function_descriptor_t;
/* Layer requests returned from getDisplayRequests */
@@ -524,6 +528,10 @@
case HWC2_FUNCTION_GET_RENDER_INTENTS: return "GetRenderIntents";
case HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT: return "SetColorModeWithRenderIntent";
case HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX: return "GetDataspaceSaturationMatrix";
+
+ // composer 2.3
+ case HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA: return "GetDisplayIdentificationData";
+ case HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM: return "SetLayerColorTransform";
default: return "Unknown";
}
}
@@ -722,6 +730,10 @@
GetRenderIntents = HWC2_FUNCTION_GET_RENDER_INTENTS,
SetColorModeWithRenderIntent = HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT,
GetDataspaceSaturationMatrix = HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX,
+
+ // composer 2.3
+ GetDisplayIdentificationData = HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
+ SetLayerColorTransform = HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
};
TO_STRING(hwc2_function_descriptor_t, FunctionDescriptor,
getFunctionDescriptorName)
@@ -1374,6 +1386,35 @@
hwc2_device_t* device, hwc2_display_t display,
int32_t* /*hwc2_display_type_t*/ outType);
+/* getDisplayIdentificationData(..., outPort, outDataSize, outData)
+ * Descriptor: HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA
+ * Optional for HWC2 devices
+ *
+ * If supported, getDisplayIdentificationData returns the port and data that
+ * describe a physical display. The port is a unique number that identifies a
+ * physical connector (e.g. eDP, HDMI) for display output. The data blob is
+ * parsed to determine its format, typically EDID 1.3 as specified in VESA
+ * E-EDID Standard Release A Revision 1.
+ *
+ * Devices for which display identification is unsupported must return null when
+ * getFunction is called with HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA.
+ *
+ * Parameters:
+ * outPort - the connector to which the display is connected;
+ * pointer will be non-NULL
+ * outDataSize - if outData is NULL, the size in bytes of the data which would
+ * have been returned; if outData is not NULL, the size of outData, which
+ * must not exceed the value stored in outDataSize prior to the call;
+ * pointer will be non-NULL
+ * outData - the EDID 1.3 blob identifying the display
+ *
+ * Returns HWC2_ERROR_NONE or one of the following errors:
+ * HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+ */
+typedef int32_t /*hwc2_error_t*/ (*HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA)(
+ hwc2_device_t* device, hwc2_display_t display, uint8_t* outPort,
+ uint32_t* outDataSize, uint8_t* outData);
+
/* getDozeSupport(..., outSupport)
* Descriptor: HWC2_FUNCTION_GET_DOZE_SUPPORT
* Must be provided by all HWC2 devices
@@ -2326,6 +2367,50 @@
hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
uint32_t z);
+/* setLayerColorTransform(..., matrix)
+ * Descriptor: HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM
+ * Optional by all HWC2 devices
+ *
+ * Sets a matrix for color transform which will be applied on this layer
+ * before composition.
+ *
+ * If the device is not capable of apply the matrix on this layer, it must force
+ * this layer to client composition during VALIDATE_DISPLAY.
+ *
+ * The matrix provided is an affine color transformation of the following form:
+ *
+ * |r.r r.g r.b 0|
+ * |g.r g.g g.b 0|
+ * |b.r b.g b.b 0|
+ * |Tr Tg Tb 1|
+ *
+ * This matrix must be provided in row-major form:
+ *
+ * {r.r, r.g, r.b, 0, g.r, ...}.
+ *
+ * Given a matrix of this form and an input color [R_in, G_in, B_in],
+ * the input color must first be converted to linear space
+ * [R_linear, G_linear, B_linear], then the output linear color
+ * [R_out_linear, G_out_linear, B_out_linear] will be:
+ *
+ * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
+ * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
+ * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
+ *
+ * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
+ * gamma space: [R_out, G_out, B_out] before blending.
+ *
+ * Parameters:
+ * matrix - a 4x4 transform matrix (16 floats) as described above
+ *
+ * Returns HWC2_ERROR_NONE or one of the following errors:
+ * HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+ * HWC2_ERROR_BAD_LAYER - an invalid layer handle was passed in
+ */
+typedef int32_t /*hwc2_error_t*/ (*HWC2_PFN_SET_LAYER_COLOR_TRANSFORM)(
+ hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ const float* matrix);
+
__END_DECLS
#endif
diff --git a/include/hardware/sound_trigger.h b/include/hardware/sound_trigger.h
index d7828ac..696b634 100644
--- a/include/hardware/sound_trigger.h
+++ b/include/hardware/sound_trigger.h
@@ -40,7 +40,8 @@
#define SOUND_TRIGGER_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0)
#define SOUND_TRIGGER_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION(1, 1)
-#define SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT SOUND_TRIGGER_DEVICE_API_VERSION_1_1
+#define SOUND_TRIGGER_DEVICE_API_VERSION_1_2 HARDWARE_DEVICE_API_VERSION(1, 2)
+#define SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT SOUND_TRIGGER_DEVICE_API_VERSION_1_2
/**
* List of known sound trigger HAL modules. This is the base name of the sound_trigger HAL
@@ -114,6 +115,15 @@
* If no implementation is provided, stop_recognition will be called for each running model.
*/
int (*stop_all_recognitions)(const struct sound_trigger_hw_device* dev);
+
+ /* Get the current state of a given model.
+ * The state is returned as a recognition event, or null if not implemented or on error.
+ * Caller takes ownership of the returned event memory.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+ */
+ struct sound_trigger_recognition_event* (*get_model_state)(
+ const struct sound_trigger_hw_device *dev,
+ sound_model_handle_t sound_model_handle);
};
typedef struct sound_trigger_hw_device sound_trigger_hw_device_t;
diff --git a/modules/camera/3_4/v4l2_camera_hal.cpp b/modules/camera/3_4/v4l2_camera_hal.cpp
index 386160f..c2101d0 100644
--- a/modules/camera/3_4/v4l2_camera_hal.cpp
+++ b/modules/camera/3_4/v4l2_camera_hal.cpp
@@ -238,4 +238,5 @@
.open_legacy = v4l2_camera_hal::open_legacy,
.set_torch_mode = v4l2_camera_hal::set_torch_mode,
.init = nullptr,
- .reserved = {nullptr, nullptr, nullptr, nullptr, nullptr}};
+ .get_physical_camera_info = nullptr,
+ .reserved = {nullptr, nullptr, nullptr, nullptr}};
diff --git a/modules/soundtrigger/sound_trigger_hw.c b/modules/soundtrigger/sound_trigger_hw.c
index 0089f98..25d4813 100644
--- a/modules/soundtrigger/sound_trigger_hw.c
+++ b/modules/soundtrigger/sound_trigger_hw.c
@@ -811,6 +811,39 @@
return 0;
}
+// Caller is responsible for freeing the memory
+static struct sound_trigger_recognition_event * stdev_get_model_state(
+ const struct sound_trigger_hw_device *dev,
+ sound_model_handle_t handle) {
+ struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
+ ALOGI("%s", __func__);
+ pthread_mutex_lock(&stdev->lock);
+
+ struct recognition_context *model_context = get_model_context(stdev, handle);
+ if (!model_context) {
+ ALOGW("Can't find sound model handle %d in registered list", handle);
+ pthread_mutex_unlock(&stdev->lock);
+ return NULL;
+ }
+
+ struct sound_trigger_recognition_event *event = NULL;
+ if (model_context->model_type == SOUND_MODEL_TYPE_GENERIC) {
+ // TODO(mdooley): define a new status for this use case?
+ int status = RECOGNITION_STATUS_SUCCESS;
+ event = (struct sound_trigger_recognition_event *)
+ sound_trigger_generic_event_alloc(model_context->model_handle,
+ model_context->config, status);
+ } else {
+ ALOGI("Unsupported sound model type: %d, state not available.",
+ model_context->model_type);
+ }
+
+ pthread_mutex_unlock(&stdev->lock);
+ ALOGI("%s done for handle %d", __func__, handle);
+
+ return event;
+}
+
__attribute__ ((visibility ("default")))
int sound_trigger_open_for_streaming() {
int ret = 0;
@@ -863,6 +896,7 @@
stdev->device.start_recognition = stdev_start_recognition;
stdev->device.stop_recognition = stdev_stop_recognition;
stdev->device.stop_all_recognitions = stdev_stop_all_recognitions;
+ stdev->device.get_model_state = stdev_get_model_state;
pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
@@ -890,4 +924,3 @@
.methods = &hal_module_methods,
},
};
-
diff --git a/modules/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index 81c9fd6..cddcc14 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "modules.usbaudio.audio_hal"
-/*#define LOG_NDEBUG 0*/
+/* #define LOG_NDEBUG 0 */
#include <errno.h>
#include <inttypes.h>
@@ -47,27 +47,26 @@
/* Lock play & record samples rates at or above this threshold */
#define RATELOCK_THRESHOLD 96000
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
struct audio_device {
struct audio_hw_device hw_device;
pthread_mutex_t lock; /* see note below on mutex acquisition order */
/* output */
- alsa_device_profile out_profile;
struct listnode output_stream_list;
/* input */
- alsa_device_profile in_profile;
struct listnode input_stream_list;
/* lock input & output sample rates */
/*FIXME - How do we address multiple output streams? */
- uint32_t device_sample_rate;
+ uint32_t device_sample_rate; // this should be a rate that is common to both input & output
bool mic_muted;
- bool standby;
-
int32_t inputs_open; /* number of input streams currently open. */
};
@@ -79,16 +78,13 @@
struct stream_out {
struct audio_stream_out stream;
- struct stream_lock lock;
+ struct stream_lock lock;
bool standby;
struct audio_device *adev; /* hardware information - only using this for the lock */
- const alsa_device_profile *profile; /* Points to the alsa_device_profile in the audio_device.
- * Const, so modifications go through adev->out_profile
- * and thus should have the hardware lock and ensure
- * stream is not active and no other open output streams.
+ alsa_device_profile profile; /* The profile of the ALSA device connected to the stream.
*/
alsa_device_proxy proxy; /* state of the stream */
@@ -121,10 +117,7 @@
struct audio_device *adev; /* hardware information - only using this for the lock */
- const alsa_device_profile *profile; /* Points to the alsa_device_profile in the audio_device.
- * Const, so modifications go through adev->out_profile
- * and thus should have the hardware lock and ensure
- * stream is not active and no other open input streams.
+ alsa_device_profile profile; /* The profile of the ALSA device connected to the stream.
*/
alsa_device_proxy proxy; /* state of the stream */
@@ -344,9 +337,7 @@
stream_lock(&out->lock);
if (!out->standby) {
- device_lock(out->adev);
proxy_close(&out->proxy);
- device_unlock(out->adev);
out->standby = true;
}
stream_unlock(&out->lock);
@@ -358,7 +349,7 @@
if (out_stream != NULL) {
dprintf(fd, "Output Profile:\n");
- profile_dump(out_stream->profile, fd);
+ profile_dump(&out_stream->profile, fd);
dprintf(fd, "Output Proxy:\n");
proxy_dump(&out_stream->proxy, fd);
@@ -383,27 +374,23 @@
}
stream_lock(&out->lock);
- /* Lock the device because that is where the profile lives */
- device_lock(out->adev);
-
- if (!profile_is_cached_for(out->profile, card, device)) {
+ if (!profile_is_cached_for(&out->profile, card, device)) {
/* cannot read pcm device info if playback is active */
if (!out->standby)
ret_value = -ENOSYS;
else {
- int saved_card = out->profile->card;
- int saved_device = out->profile->device;
- out->adev->out_profile.card = card;
- out->adev->out_profile.device = device;
- ret_value = profile_read_device_info(&out->adev->out_profile) ? 0 : -EINVAL;
+ int saved_card = out->profile.card;
+ int saved_device = out->profile.device;
+ out->profile.card = card;
+ out->profile.device = device;
+ ret_value = profile_read_device_info(&out->profile) ? 0 : -EINVAL;
if (ret_value != 0) {
- out->adev->out_profile.card = saved_card;
- out->adev->out_profile.device = saved_device;
+ out->profile.card = saved_card;
+ out->profile.device = saved_device;
}
}
}
- device_unlock(out->adev);
stream_unlock(&out->lock);
return ret_value;
@@ -413,11 +400,7 @@
{
struct stream_out *out = (struct stream_out *)stream;
stream_lock(&out->lock);
- device_lock(out->adev);
-
- char * params_str = device_get_parameters(out->profile, keys);
-
- device_unlock(out->adev);
+ char * params_str = device_get_parameters(&out->profile, keys);
stream_unlock(&out->lock);
return params_str;
}
@@ -436,7 +419,7 @@
/* must be called with hw device and output stream mutexes locked */
static int start_output_stream(struct stream_out *out)
{
- ALOGV("start_output_stream(card:%d device:%d)", out->profile->card, out->profile->device);
+ ALOGV("start_output_stream(card:%d device:%d)", out->profile.card, out->profile.device);
return proxy_open(&out->proxy);
}
@@ -448,9 +431,7 @@
stream_lock(&out->lock);
if (out->standby) {
- device_lock(out->adev);
ret = start_output_stream(out);
- device_unlock(out->adev);
if (ret != 0) {
goto err;
}
@@ -573,43 +554,45 @@
stream_lock_init(&out->lock);
out->adev = (struct audio_device *)hw_dev;
- device_lock(out->adev);
- out->profile = &out->adev->out_profile;
+
+ profile_init(&out->profile, PCM_OUT);
// build this to hand to the alsa_device_proxy
struct pcm_config proxy_config;
memset(&proxy_config, 0, sizeof(proxy_config));
/* Pull out the card/device pair */
- parse_card_device_params(address, &out->adev->out_profile.card, &out->adev->out_profile.device);
+ parse_card_device_params(address, &out->profile.card, &out->profile.device);
- profile_read_device_info(&out->adev->out_profile);
+ profile_read_device_info(&out->profile);
int ret = 0;
/* Rate */
if (config->sample_rate == 0) {
- proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
- } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
+ proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&out->profile);
+ } else if (profile_is_sample_rate_valid(&out->profile, config->sample_rate)) {
proxy_config.rate = config->sample_rate;
} else {
- proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
+ proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&out->profile);
ret = -EINVAL;
}
+ /* TODO: This is a problem if the input does not support this rate */
+ device_lock(out->adev);
out->adev->device_sample_rate = config->sample_rate;
device_unlock(out->adev);
/* Format */
if (config->format == AUDIO_FORMAT_DEFAULT) {
- proxy_config.format = profile_get_default_format(out->profile);
+ proxy_config.format = profile_get_default_format(&out->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
} else {
enum pcm_format fmt = pcm_format_from_audio_format(config->format);
- if (profile_is_format_valid(out->profile, fmt)) {
+ if (profile_is_format_valid(&out->profile, fmt)) {
proxy_config.format = fmt;
} else {
- proxy_config.format = profile_get_default_format(out->profile);
+ proxy_config.format = profile_get_default_format(&out->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
ret = -EINVAL;
}
@@ -619,7 +602,7 @@
bool calc_mask = false;
if (config->channel_mask == AUDIO_CHANNEL_NONE) {
/* query case */
- out->hal_channel_count = profile_get_default_channel_count(out->profile);
+ out->hal_channel_count = profile_get_default_channel_count(&out->profile);
calc_mask = true;
} else {
/* explicit case */
@@ -647,8 +630,9 @@
// Validate the "logical" channel count against support in the "actual" profile.
// if they differ, choose the "actual" number of channels *closest* to the "logical".
// and store THAT in proxy_config.channels
- proxy_config.channels = profile_get_closest_channel_count(out->profile, out->hal_channel_count);
- proxy_prepare(&out->proxy, out->profile, &proxy_config);
+ proxy_config.channels =
+ profile_get_closest_channel_count(&out->profile, out->hal_channel_count);
+ proxy_prepare(&out->proxy, &out->profile, &proxy_config);
/* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger
* So clear any errors that may have occurred above.
@@ -672,9 +656,7 @@
struct audio_stream_out *stream)
{
struct stream_out *out = (struct stream_out *)stream;
- ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
-
- adev_remove_stream_from_list(out->adev, &out->list_node);
+ ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile.card, out->profile.device);
/* Close the pcm device */
out_standby(&stream->common);
@@ -684,6 +666,8 @@
out->conversion_buffer = NULL;
out->conversion_buffer_size = 0;
+ adev_remove_stream_from_list(out->adev, &out->list_node);
+
device_lock(out->adev);
out->adev->device_sample_rate = 0;
device_unlock(out->adev);
@@ -746,12 +730,9 @@
stream_lock(&in->lock);
if (!in->standby) {
- device_lock(in->adev);
proxy_close(&in->proxy);
- device_unlock(in->adev);
in->standby = true;
}
-
stream_unlock(&in->lock);
return 0;
@@ -762,7 +743,7 @@
const struct stream_in* in_stream = (const struct stream_in*)stream;
if (in_stream != NULL) {
dprintf(fd, "Input Profile:\n");
- profile_dump(in_stream->profile, fd);
+ profile_dump(&in_stream->profile, fd);
dprintf(fd, "Input Proxy:\n");
proxy_dump(&in_stream->proxy, fd);
@@ -789,19 +770,20 @@
stream_lock(&in->lock);
device_lock(in->adev);
- if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
- /* cannot read pcm device info if playback is active, or more than one open stream */
+ if (card >= 0 && device >= 0 && !profile_is_cached_for(&in->profile, card, device)) {
+ /* cannot read pcm device info if capture is active, or more than one open stream */
if (!in->standby || in->adev->inputs_open > 1)
ret_value = -ENOSYS;
else {
- int saved_card = in->profile->card;
- int saved_device = in->profile->device;
- in->adev->in_profile.card = card;
- in->adev->in_profile.device = device;
- ret_value = profile_read_device_info(&in->adev->in_profile) ? 0 : -EINVAL;
+ int saved_card = in->profile.card;
+ int saved_device = in->profile.device;
+ in->profile.card = card;
+ in->profile.device = device;
+ ret_value = profile_read_device_info(&in->profile) ? 0 : -EINVAL;
if (ret_value != 0) {
- in->adev->in_profile.card = saved_card;
- in->adev->in_profile.device = saved_device;
+ ALOGE("Can't read device profile. card:%d, device:%d", card, device);
+ in->profile.card = saved_card;
+ in->profile.device = saved_device;
}
}
}
@@ -817,11 +799,7 @@
struct stream_in *in = (struct stream_in *)stream;
stream_lock(&in->lock);
- device_lock(in->adev);
-
- char * params_str = device_get_parameters(in->profile, keys);
-
- device_unlock(in->adev);
+ char * params_str = device_get_parameters(&in->profile, keys);
stream_unlock(&in->lock);
return params_str;
@@ -845,7 +823,7 @@
/* must be called with hw device and output stream mutexes locked */
static int start_input_stream(struct stream_in *in)
{
- ALOGV("start_input_stream(card:%d device:%d)", in->profile->card, in->profile->device);
+ ALOGV("start_input_stream(card:%d device:%d)", in->profile.card, in->profile.device);
return proxy_open(&in->proxy);
}
@@ -862,9 +840,7 @@
stream_lock(&in->lock);
if (in->standby) {
- device_lock(in->adev);
ret = start_input_stream(in);
- device_unlock(in->adev);
if (ret != 0) {
goto err;
}
@@ -929,6 +905,19 @@
return 0;
}
+static int in_get_capture_position(const struct audio_stream_in *stream,
+ int64_t *frames, int64_t *time)
+{
+ struct stream_in *in = (struct stream_in *)stream; // discard const qualifier
+ stream_lock(&in->lock);
+
+ const alsa_device_proxy *proxy = &in->proxy;
+ const int ret = proxy_get_capture_position(proxy, frames, time);
+
+ stream_unlock(&in->lock);
+ return ret;
+}
+
static int adev_open_input_stream(struct audio_hw_device *hw_dev,
audio_io_handle_t handle,
audio_devices_t devicesSpec __unused,
@@ -972,68 +961,85 @@
in->stream.set_gain = in_set_gain;
in->stream.read = in_read;
in->stream.get_input_frames_lost = in_get_input_frames_lost;
+ in->stream.get_capture_position = in_get_capture_position;
stream_lock_init(&in->lock);
in->adev = (struct audio_device *)hw_dev;
- device_lock(in->adev);
- in->profile = &in->adev->in_profile;
+ profile_init(&in->profile, PCM_IN);
struct pcm_config proxy_config;
memset(&proxy_config, 0, sizeof(proxy_config));
int ret = 0;
+ device_lock(in->adev);
+ int num_open_inputs = in->adev->inputs_open;
+ device_unlock(in->adev);
+
/* Check if an input stream is already open */
- if (in->adev->inputs_open > 0) {
- if (!profile_is_cached_for(in->profile, card, device)) {
+ if (num_open_inputs > 0) {
+ if (!profile_is_cached_for(&in->profile, card, device)) {
ALOGW("%s fail - address card:%d device:%d doesn't match existing profile",
__func__, card, device);
ret = -EINVAL;
}
} else {
/* Read input profile only if necessary */
- in->adev->in_profile.card = card;
- in->adev->in_profile.device = device;
- if (!profile_read_device_info(&in->adev->in_profile)) {
+ in->profile.card = card;
+ in->profile.device = device;
+ if (!profile_read_device_info(&in->profile)) {
ALOGW("%s fail - cannot read profile", __func__);
ret = -EINVAL;
}
}
if (ret != 0) {
- device_unlock(in->adev);
free(in);
*stream_in = NULL;
return ret;
}
/* Rate */
+ int request_config_rate = config->sample_rate;
if (config->sample_rate == 0) {
- config->sample_rate = profile_get_default_sample_rate(in->profile);
+ config->sample_rate = profile_get_default_sample_rate(&in->profile);
}
- if (in->adev->device_sample_rate != 0 && /* we are playing, so lock the rate */
+ if (in->adev->device_sample_rate != 0 && /* we are playing, so lock the rate if possible */
in->adev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
- ret = config->sample_rate != in->adev->device_sample_rate ? -EINVAL : 0;
- proxy_config.rate = config->sample_rate = in->adev->device_sample_rate;
- } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
+ if (config->sample_rate != in->adev->device_sample_rate) {
+ unsigned highest_rate = profile_get_highest_sample_rate(&in->profile);
+ if (highest_rate == 0) {
+ ret = -EINVAL; /* error with device */
+ } else {
+ proxy_config.rate = config->sample_rate =
+ min(highest_rate, in->adev->device_sample_rate);
+ if (request_config_rate != 0 && proxy_config.rate != config->sample_rate) {
+ /* Changing the requested rate */
+ ret = -EINVAL;
+ } else {
+ /* Everything AOK! */
+ ret = 0;
+ }
+ }
+ }
+ } else if (profile_is_sample_rate_valid(&in->profile, config->sample_rate)) {
proxy_config.rate = config->sample_rate;
} else {
- proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
+ proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&in->profile);
ret = -EINVAL;
}
- device_unlock(in->adev);
/* Format */
if (config->format == AUDIO_FORMAT_DEFAULT) {
- proxy_config.format = profile_get_default_format(in->profile);
+ proxy_config.format = profile_get_default_format(&in->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
} else {
enum pcm_format fmt = pcm_format_from_audio_format(config->format);
- if (profile_is_format_valid(in->profile, fmt)) {
+ if (profile_is_format_valid(&in->profile, fmt)) {
proxy_config.format = fmt;
} else {
- proxy_config.format = profile_get_default_format(in->profile);
+ proxy_config.format = profile_get_default_format(&in->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
ret = -EINVAL;
}
@@ -1043,7 +1049,7 @@
bool calc_mask = false;
if (config->channel_mask == AUDIO_CHANNEL_NONE) {
/* query case */
- in->hal_channel_count = profile_get_default_channel_count(in->profile);
+ in->hal_channel_count = profile_get_default_channel_count(&in->profile);
calc_mask = true;
} else {
/* explicit case */
@@ -1080,8 +1086,8 @@
// if they differ, choose the "actual" number of channels *closest* to the "logical".
// and store THAT in proxy_config.channels
proxy_config.channels =
- profile_get_closest_channel_count(in->profile, in->hal_channel_count);
- ret = proxy_prepare(&in->proxy, in->profile, &proxy_config);
+ profile_get_closest_channel_count(&in->profile, in->hal_channel_count);
+ ret = proxy_prepare(&in->proxy, &in->profile, &proxy_config);
if (ret == 0) {
in->standby = true;
@@ -1121,7 +1127,7 @@
struct audio_stream_in *stream)
{
struct stream_in *in = (struct stream_in *)stream;
- ALOGV("adev_close_input_stream(c:%d d:%d)", in->profile->card, in->profile->device);
+ ALOGV("adev_close_input_stream(c:%d d:%d)", in->profile.card, in->profile.device);
adev_remove_stream_from_list(in->adev, &in->list_node);
@@ -1249,8 +1255,7 @@
if (!adev)
return -ENOMEM;
- profile_init(&adev->out_profile, PCM_OUT);
- profile_init(&adev->in_profile, PCM_IN);
+ pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
list_init(&adev->output_stream_list);
list_init(&adev->input_stream_list);
diff --git a/tests/hardware/struct-offset.cpp b/tests/hardware/struct-offset.cpp
index 6f86f03..8ec1a27 100644
--- a/tests/hardware/struct-offset.cpp
+++ b/tests/hardware/struct-offset.cpp
@@ -216,7 +216,8 @@
CHECK_MEMBER_AT(camera_module_t, open_legacy, 144, 280);
CHECK_MEMBER_AT(camera_module_t, set_torch_mode, 148, 288);
CHECK_MEMBER_AT(camera_module_t, init, 152, 296);
- CHECK_MEMBER_AT(camera_module_t, reserved, 156, 304);
+ CHECK_MEMBER_AT(camera_module_t, get_physical_camera_info, 156, 304);
+ CHECK_MEMBER_AT(camera_module_t, reserved, 160, 312);
//Types defined in camera3.h
CHECK_MEMBER_AT(camera3_device_ops_t, initialize, 0, 0);