From 539c9936aec9cdd75054e24e07e7decdd1d4de39 Mon Sep 17 00:00:00 2001 From: suyi Yuan Date: Thu, 15 Mar 2012 15:27:02 +0800 Subject: remove seemed useless gralloc_open() call in fb_device_open() Change-Id: I520e460bd558934c71042b5a4fdb03b3935ad720 Signed-off-by: suyi Yuan --- modules/gralloc/framebuffer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/gralloc/framebuffer.cpp b/modules/gralloc/framebuffer.cpp index f908976..52c838b 100644 --- a/modules/gralloc/framebuffer.cpp +++ b/modules/gralloc/framebuffer.cpp @@ -312,11 +312,6 @@ int fb_device_open(hw_module_t const* module, const char* name, { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { - alloc_device_t* gralloc_device; - status = gralloc_open(module, &gralloc_device); - if (status < 0) - return status; - /* initialize our state here */ fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); -- cgit v1.1 From 1d1775bb4dfc6d266e3f111dacaa546dc775732f Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 24 Apr 2012 13:39:15 -0700 Subject: hardware: libhardware: Power HAL add power hints Change-Id: I8ab0376e4f5d8ef09d5b1062cbfbb30c30c5bb96 Signed-off-by: Todd Poynor --- include/hardware/power.h | 34 +++++++++++++++++++++++++++++++++- modules/power/power.c | 8 ++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/hardware/power.h b/include/hardware/power.h index 825a74a..1cb2134 100644 --- a/include/hardware/power.h +++ b/include/hardware/power.h @@ -30,6 +30,17 @@ __BEGIN_DECLS */ #define POWER_HARDWARE_MODULE_ID "power" +/* + * Power hint identifiers passed to (*powerHint) + */ + +typedef enum { + /* + * VSYNC pulse request from SurfaceFlinger started or stopped. + */ + POWER_HINT_VSYNC = 0x00000001, +} power_hint_t; + /** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t @@ -40,7 +51,9 @@ typedef struct power_module { /* * (*init)() performs power management setup actions at runtime - * startup, such as to set default cpufreq parameters. + * startup, such as to set default cpufreq parameters. This is + * called only by the Power HAL instance loaded by + * PowerManagerService. */ void (*init)(struct power_module *module); @@ -71,6 +84,25 @@ typedef struct power_module { * interactive state prior to turning on the screen. */ void (*setInteractive)(struct power_module *module, int on); + + /* + * (*powerHint) is called to pass hints on power requirements, which + * may result in adjustment of power/performance parameters of the + * cpufreq governor and other controls. The possible hints are: + * + * POWER_HINT_VSYNC + * + * Foreground app has started or stopped requesting a VSYNC pulse + * from SurfaceFlinger. If the app has started requesting VSYNC + * then CPU and GPU load is expected soon, and it may be appropriate + * to raise speeds of CPU, memory bus, etc. The data parameter is + * non-zero to indicate VSYNC pulse is now requested, or zero for + * VSYNC pulse no longer requested. + * + * A particular platform may choose to ignore any hint. + */ + void (*powerHint)(struct power_module *module, power_hint_t hint, + void *data); } power_module_t; diff --git a/modules/power/power.c b/modules/power/power.c index ef3fe94..7d8c112 100644 --- a/modules/power/power.c +++ b/modules/power/power.c @@ -59,6 +59,13 @@ static void power_set_interactive(struct power_module *module, int on) } } +static void power_hint(struct power_module *module, power_hint_t hint, + void *data) { + switch (hint) { + default: + break; + } +} static struct hw_module_methods_t power_module_methods = { .open = NULL, @@ -77,4 +84,5 @@ struct power_module HAL_MODULE_INFO_SYM = { .init = power_init, .setInteractive = power_set_interactive, + .powerHint = power_hint, }; -- cgit v1.1 From 984272d92e40941f3d140f2cecb5f05986ac66b1 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 13 Apr 2012 10:08:47 -0700 Subject: Add RAW_SENSOR to gralloc sample Change-Id: I0621bd70896385c3d522d283a1be714f5f29df3b --- modules/gralloc/gralloc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp index a6b4edd..99aeb01 100644 --- a/modules/gralloc/gralloc.cpp +++ b/modules/gralloc/gralloc.cpp @@ -219,6 +219,7 @@ static int gralloc_alloc(alloc_device_t* dev, case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_RGBA_5551: case HAL_PIXEL_FORMAT_RGBA_4444: + case HAL_PIXEL_FORMAT_RAW_SENSOR: bpp = 2; break; default: -- cgit v1.1 From 567b4a24fa9fedf0086af5e0bb8e45bd3294bc9d Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 23 Apr 2012 09:29:38 -0700 Subject: Substantial cleanup of camera2 HAL, and some initial unit tests - Clean up const/struct usage in HAL - Add user pointer to notify callback - Revamp allocate_stream, now it picks its own ID. - Much simpler stream interface - Merged request/reprocess input queues - Frame queue interface no longer a mirror of request queue - Added triggers/notifications - Added default request creation - Lots of comments Unit tests added: - Lots of utility code to speed up test writing - Basic open/close - Capturing 1 raw buffer (request input, frame output, buffer output) - Capturing a burst of 10 raw buffers Bug: 6243944 Change-Id: I490bd5df81079a44c43d87b02c9a7f7ca251f531 --- include/hardware/camera2.h | 607 ++++++++++++++++++++++++++++++++-------- tests/camera2/Android.mk | 8 +- tests/camera2/camera2.cpp | 513 +++++++++++++++++++++++++++++++-- tests/camera2/camera2_utils.cpp | 583 ++++++++++++++++++++++++++++++++++++++ tests/camera2/camera2_utils.h | 235 ++++++++++++++++ 5 files changed, 1791 insertions(+), 155 deletions(-) create mode 100644 tests/camera2/camera2_utils.cpp create mode 100644 tests/camera2/camera2_utils.h diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 36f2a9e..7f06c52 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -18,6 +18,7 @@ #define ANDROID_INCLUDE_CAMERA2_H #include "camera_common.h" +#include "system/camera_metadata.h" /** * Camera device HAL 2.0 [ CAMERA_DEVICE_API_VERSION_2_0 ] @@ -35,7 +36,7 @@ * version 2.0 of the camera module interface (as defined by * camera_module_t.common.module_api_version). * - * See camera_common.h for more details. + * See camera_common.h for more versioning details. * */ @@ -43,105 +44,219 @@ __BEGIN_DECLS struct camera2_device; -/** - * Output image stream queue management +/********************************************************************** + * + * Input/output stream buffer queue interface definitions + * */ +/** + * Output image stream queue interface. A set of these methods is provided to + * the HAL device in allocate_stream(), and are used to interact with the + * gralloc buffer queue for that stream. They may not be called until after + * allocate_stream returns. + */ typedef struct camera2_stream_ops { + /** + * Get a buffer to fill from the queue. The size and format of the buffer + * are fixed for a given stream (defined in allocate_stream), and the stride + * should be queried from the platform gralloc module. The gralloc buffer + * will have been allocated based on the usage flags provided by + * allocate_stream, and will be locked for use. + */ int (*dequeue_buffer)(struct camera2_stream_ops* w, - buffer_handle_t** buffer, int *stride); + buffer_handle_t** buffer); + + /** + * Push a filled buffer to the stream to be used by the consumer. + * + * The timestamp represents the time at start of exposure of the first row + * of the image; it must be from a monotonic clock, and is measured in + * nanoseconds. The timestamps do not need to be comparable between + * different cameras, or consecutive instances of the same camera. However, + * they must be comparable between streams from the same camera. If one + * capture produces buffers for multiple streams, each stream must have the + * same timestamp for that buffer, and that timestamp must match the + * timestamp in the output frame metadata. + */ int (*enqueue_buffer)(struct camera2_stream_ops* w, - buffer_handle_t* buffer); + int64_t timestamp, + buffer_handle_t* buffer); + /** + * Return a buffer to the queue without marking it as filled. + */ int (*cancel_buffer)(struct camera2_stream_ops* w, - buffer_handle_t* buffer); - int (*set_buffer_count)(struct camera2_stream_ops* w, int count); - int (*set_buffers_geometry)(struct camera2_stream_ops* pw, - int w, int h, int format); + buffer_handle_t* buffer); + /** + * Set the crop window for subsequently enqueued buffers. The parameters are + * measured in pixels relative to the buffer width and height. + */ int (*set_crop)(struct camera2_stream_ops *w, - int left, int top, int right, int bottom); - // Timestamps are measured in nanoseconds, and must be comparable - // and monotonically increasing between two frames in the same - // preview stream. They do not need to be comparable between - // consecutive or parallel preview streams, cameras, or app runs. - // The timestamp must be the time at the start of image exposure. - int (*set_timestamp)(struct camera2_stream_ops *w, int64_t timestamp); - int (*set_usage)(struct camera2_stream_ops* w, int usage); - int (*get_min_undequeued_buffer_count)(const struct camera2_stream_ops *w, - int *count); - int (*lock_buffer)(struct camera2_stream_ops* w, - buffer_handle_t* buffer); + int left, int top, int right, int bottom); + } camera2_stream_ops_t; /** + * Special pixel format value used to indicate that the framework does not care + * what exact pixel format is to be used for an output stream. The device HAL is + * free to select any pixel format, platform-specific and otherwise, and this + * opaque value will be passed on to the platform gralloc module when buffers + * need to be allocated for the stream. + */ +enum { + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = -1 +}; + +/** + * Input reprocess stream queue management. A set of these methods is provided + * to the HAL device in allocate_reprocess_stream(); they are used to interact with the + * reprocess stream's input gralloc buffer queue. + */ +typedef struct camera2_stream_in_ops { + /** + * Get the next buffer of image data to reprocess. The width, height, and + * format of the buffer is fixed in allocate_reprocess_stream(), and the + * stride and other details should be queried from the platform gralloc + * module as needed. The buffer will already be locked for use. + */ + int (*acquire_buffer)(struct camera2_stream_in_ops *w, + buffer_handle_t** buffer); + /** + * Return a used buffer to the buffer queue for reuse. + */ + int (*release_buffer)(struct camera2_stream_in_ops *w, + buffer_handle_t* buffer); + +} camera2_stream_in_ops_t; + +/********************************************************************** + * * Metadata queue management, used for requests sent to HAL module, and for * frames produced by the HAL. * - * Queue protocol: + */ + +enum { + CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS = -1 +}; + +/** + * Request input queue protocol: * - * The source holds the queue and its contents. At start, the queue is empty. + * The framework holds the queue and its contents. At start, the queue is empty. * - * 1. When the first metadata buffer is placed into the queue, the source must - * signal the destination by calling notify_queue_not_empty(). + * 1. When the first metadata buffer is placed into the queue, the framework + * signals the device by calling notify_request_queue_not_empty(). * - * 2. After receiving notify_queue_not_empty, the destination must call + * 2. After receiving notify_request_queue_not_empty, the device must call * dequeue() once it's ready to handle the next buffer. * - * 3. Once the destination has processed a buffer, it should try to dequeue - * another buffer. If there are no more buffers available, dequeue() will - * return NULL. In this case, when a buffer becomes available, the source - * must call notify_queue_not_empty() again. If the destination receives a - * NULL return from dequeue, it does not need to query the queue again until - * a notify_queue_not_empty() call is received from the source. + * 3. Once the device has processed a buffer, and is ready for the next buffer, + * it must call dequeue() again instead of waiting for a notification. If + * there are no more buffers available, dequeue() will return NULL. After + * this point, when a buffer becomes available, the framework must call + * notify_request_queue_not_empty() again. If the device receives a NULL + * return from dequeue, it does not need to query the queue again until a + * notify_request_queue_not_empty() call is received from the source. + * + * 4. If the device calls buffer_count() and receives 0, this does not mean that + * the framework will provide a notify_request_queue_not_empty() call. The + * framework will only provide such a notification after the device has + * received a NULL from dequeue, or on initial startup. * - * 4. If the destination calls buffer_count() and receives 0, this does not mean - * that the source will provide a notify_queue_not_empty() call. The source - * must only provide such a call after the destination has received a NULL - * from dequeue, or on initial startup. + * 5. The dequeue() call in response to notify_request_queue_not_empty() may be + * on the same thread as the notify_request_queue_not_empty() call, and may + * be performed from within the notify call. * - * 5. The dequeue() call in response to notify_queue_not_empty() may be on the - * same thread as the notify_queue_not_empty() call. The source must not - * deadlock in that case. + * 6. All dequeued request buffers must be returned to the framework by calling + * free_request, including when errors occur, a device flush is requested, or + * when the device is shutting down. */ - -typedef struct camera2_metadata_queue_src_ops { +typedef struct camera2_request_queue_src_ops { /** - * Get count of buffers in queue + * Get the count of request buffers pending in the queue. May return + * CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS if a repeating request (stream + * request) is currently configured. Calling this method has no effect on + * whether the notify_request_queue_not_empty() method will be called by the + * framework. */ - int (*buffer_count)(camera2_metadata_queue_src_ops *q); + int (*request_count)(struct camera2_request_queue_src_ops *q); /** - * Get a metadata buffer from the source. Returns OK if a request is - * available, placing a pointer to it in next_request. + * Get a metadata buffer from the framework. Returns OK if there is no + * error. If the queue is empty, returns NULL in buffer. In that case, the + * device must wait for a notify_request_queue_not_empty() message before + * attempting to dequeue again. Buffers obtained in this way must be + * returned to the framework with free_request(). */ - int (*dequeue)(camera2_metadata_queue_src_ops *q, + int (*dequeue_request)(struct camera2_request_queue_src_ops *q, camera_metadata_t **buffer); /** - * Return a metadata buffer to the source once it has been used + * Return a metadata buffer to the framework once it has been used, or if + * an error or shutdown occurs. */ - int (*free)(camera2_metadata_queue_src_ops *q, + int (*free_request)(struct camera2_request_queue_src_ops *q, camera_metadata_t *old_buffer); -} camera2_metadata_queue_src_ops_t; +} camera2_request_queue_src_ops_t; -typedef struct camera2_metadata_queue_dst_ops { +/** + * Frame output queue protocol: + * + * The framework holds the queue and its contents. At start, the queue is empty. + * + * 1. When the device is ready to fill an output metadata frame, it must dequeue + * a metadata buffer of the required size. + * + * 2. It should then fill the metadata buffer, and place it on the frame queue + * using enqueue_frame. The framework takes ownership of the frame. + * + * 3. In case of an error, a request to flush the pipeline, or shutdown, the + * device must return any affected dequeued frames to the framework by + * calling cancel_frame. + */ +typedef struct camera2_frame_queue_dst_ops { /** - * Notify destination that the queue is no longer empty + * Get an empty metadata buffer to fill from the framework. The new metadata + * buffer will have room for entries number of metadata entries, plus + * data_bytes worth of extra storage. Frames dequeued here must be returned + * to the framework with either cancel_frame or enqueue_frame. */ - int (*notify_queue_not_empty)(struct camera2_metadata_queue_dst_ops *); + int (*dequeue_frame)(struct camera2_frame_queue_dst_ops *q, + size_t entries, size_t data_bytes, + camera_metadata_t **buffer); -} camera2_metadata_queue_dst_ops_t; + /** + * Return a dequeued metadata buffer to the framework for reuse; do not mark it as + * filled. Use when encountering errors, or flushing the internal request queue. + */ + int (*cancel_frame)(struct camera2_frame_queue_dst_ops *q, + camera_metadata_t *buffer); -/* Defined in camera_metadata.h */ -typedef struct vendor_tag_query_ops vendor_tag_query_ops_t; + /** + * Place a completed metadata frame on the frame output queue. + */ + int (*enqueue_frame)(struct camera2_frame_queue_dst_ops *q, + camera_metadata_t *buffer); + +} camera2_frame_queue_dst_ops_t; + +/********************************************************************** + * + * Notification callback and message definition, and trigger definitions + * + */ /** * Asynchronous notification callback from the HAL, fired for various * reasons. Only for information independent of frame capture, or that require - * specific timing. + * specific timing. The user pointer must be the same one that was passed to the + * device in set_notify_callback(). */ typedef void (*camera2_notify_callback)(int32_t msg_type, int32_t ext1, int32_t ext2, + int32_t ext3, void *user); /** @@ -149,15 +264,39 @@ typedef void (*camera2_notify_callback)(int32_t msg_type, */ enum { /** - * A serious error has occurred. Argument ext1 contains the error code, and - * ext2 and user contain any error-specific information. + * An error has occurred. Argument ext1 contains the error code, and + * ext2 and ext3 contain any error-specific information. */ CAMERA2_MSG_ERROR = 0x0001, /** * The exposure of a given request has begun. Argument ext1 contains the - * request id. + * frame number, and ext2 and ext3 contain the low-order and high-order + * bytes of the timestamp for when exposure began. + * (timestamp = (ext3 << 32 | ext2)) + */ + CAMERA2_MSG_SHUTTER = 0x0010, + /** + * The autofocus routine has changed state. Argument ext1 contains the new + * state; the values are the same as those for the metadata field + * android.control.afState. Ext2 contains the latest value passed to + * trigger_action(CAMERA2_TRIGGER_AUTOFOCUS), or 0 if that method has not + * been called. */ - CAMERA2_MSG_SHUTTER = 0x0002 + CAMERA2_MSG_AUTOFOCUS = 0x0020, + /** + * The autoexposure routine has changed state. Argument ext1 contains the + * new state; the values are the same as those for the metadata field + * android.control.aeState. Ext2 containst the latest value passed to + * trigger_action(CAMERA2_TRIGGER_PRECAPTURE_METERING), or 0 if that method + * has not been called. + */ + CAMERA2_MSG_AUTOEXPOSURE = 0x0021, + /** + * The auto-whitebalance routine has changed state. Argument ext1 contains + * the new state; the values are the same as those for the metadata field + * android.control.awbState. + */ + CAMERA2_MSG_AUTOWB = 0x0022 }; /** @@ -169,58 +308,137 @@ enum { * no further frames or buffer streams will be produced by the * device. Device should be treated as closed. */ - CAMERA2_MSG_ERROR_HARDWARE_FAULT = 0x0001, + CAMERA2_MSG_ERROR_HARDWARE = 0x0001, /** * A serious failure occured. No further frames or buffer streams will be * produced by the device. Device should be treated as closed. The client * must reopen the device to use it again. */ - CAMERA2_MSG_ERROR_DEVICE_FAULT = 0x0002, + CAMERA2_MSG_ERROR_DEVICE, /** - * The camera service has failed. Device should be treated as released. The client - * must reopen the device to use it again. + * An error has occurred in processing a request. No output (metadata or + * buffers) will be produced for this request. ext2 contains the frame + * number of the request. Subsequent requests are unaffected, and the device + * remains operational. */ - CAMERA2_MSG_ERROR_SERVER_FAULT = 0x0003 + CAMERA2_MSG_ERROR_REQUEST, + /** + * An error has occurred in producing an output frame metadata buffer for a + * request, but image buffers for it will still be available. Subsequent + * requests are unaffected, and the device remains operational. ext2 + * contains the frame number of the request. + */ + CAMERA2_MSG_ERROR_FRAME, + /** + * An error has occurred in placing an output buffer into a stream for a + * request. The frame metadata and other buffers may still be + * available. Subsequent requests are unaffected, and the device remains + * operational. ext2 contains the frame number of the request, and ext3 + * contains the stream id. + */ + CAMERA2_MSG_ERROR_STREAM, + /** + * Number of error types + */ + CAMERA2_MSG_NUM_ERRORS }; -typedef struct camera2_device_ops { +/** + * Possible trigger ids for trigger_action() + */ +enum { /** - * Input request queue methods + * Trigger an autofocus cycle. The effect of the trigger depends on the + * autofocus mode in effect when the trigger is received, which is the mode + * listed in the latest capture request to be dequeued. If the mode is off, + * the trigger has no effect. If autofocus is already scanning, the trigger + * has no effect. In AUTO, MACRO, or CONTINUOUS_* modes, the trigger + * otherwise begins an appropriate scan of the scene for focus. The state of + * the autofocus cycle can be tracked in android.control.afMode and the + * corresponding notification. Ext1 is an id that must be returned in + * subsequent auto-focus state change notifications. */ - int (*set_request_queue_src_ops)(struct camera2_device *, - camera2_metadata_queue_src_ops *queue_src_ops); - - int (*get_request_queue_dst_ops)(struct camera2_device *, - camera2_metadata_queue_dst_ops **queue_dst_ops); + CAMERA2_TRIGGER_AUTOFOCUS = 0x0001, + /** + * Trigger a pre-capture metering cycle, which may include firing the flash + * to determine proper capture parameters. Typically, this trigger would be + * fired for a half-depress of a camera shutter key, or before a snapshot + * capture in general. The state of the metering cycle can be tracked in + * android.control.aeMode and the corresponding notification. If the + * auto-exposure mode is OFF, the trigger does nothing. Ext1 is an id that + * must be returned in subsequent auto-exposure state change notifications. + */ + CAMERA2_TRIGGER_PRECAPTURE_METERING +}; +/** + * Possible template types for construct_default_request() + */ +enum { /** - * Input reprocessing queue methods + * Standard camera preview operation with 3A on auto. */ - int (*set_reprocess_queue_ops)(struct camera2_device *, - camera2_metadata_queue_src_ops *queue_src_ops); + CAMERA2_TEMPLATE_PREVIEW = 1, + /** + * Standard camera high-quality still capture with 3A and flash on auto. + */ + CAMERA2_TEMPLATE_STILL_CAPTURE, + /** + * Standard video recording plus preview with 3A on auto, torch off. + */ + CAMERA2_TEMPLATE_VIDEO_RECORD, + /** + * High-quality still capture while recording video. Application will + * include preview, video record, and full-resolution YUV or JPEG streams in + * request. Must not cause stuttering on video stream. 3A on auto. + */ + CAMERA2_TEMPLATE_VIDEO_SNAPSHOT, + /** + * Zero-shutter-lag mode. Application will request preview and + * full-resolution YUV data for each frame, and reprocess it to JPEG when a + * still image is requested by user. Settings should provide highest-quality + * full-resolution images without compromising preview frame rate. 3A on + * auto. + */ + CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG +}; - int (*get_reprocess_queue_dst_ops)(struct camera2_device *, - camera2_metadata_queue_dst_ops **queue_dst_ops); + +/********************************************************************** + * + * Camera device operations + * + */ +typedef struct camera2_device_ops { + + /********************************************************************** + * Request and frame queue setup and management methods + */ /** - * Output frame queue methods + * Pass in input request queue interface methods. */ - int (*set_frame_queue_dst_ops)(struct camera2_device *, - camera2_metadata_queue_dst_ops *queue_dst_ops); + int (*set_request_queue_src_ops)(struct camera2_device *, + camera2_request_queue_src_ops_t *request_src_ops); - int (*get_frame_queue_src_ops)(struct camera2_device *, - camera2_metadata_queue_src_ops **queue_dst_ops); + /** + * Notify device that the request queue is no longer empty. Must only be + * called when the first buffer is added a new queue, or after the source + * has returned NULL in response to a dequeue call. + */ + int (*notify_request_queue_not_empty)(struct camera2_device *); /** - * Pass in notification methods + * Pass in output frame queue interface methods */ - int (*set_notify_callback)(struct camera2_device *, - camera2_notify_callback notify_cb); + int (*set_frame_queue_dst_ops)(struct camera2_device *, + camera2_frame_queue_dst_ops_t *frame_dst_ops); /** - * Number of camera frames being processed by the device - * at the moment (frames that have had their request dequeued, - * but have not yet been enqueued onto output pipeline(s) ) + * Number of camera requests being processed by the device at the moment + * (captures/reprocesses that have had their request dequeued, but have not + * yet been enqueued onto output pipeline(s) ). No streams may be released + * by the framework until the in-progress count is 0. */ int (*get_in_progress_count)(struct camera2_device *); @@ -228,52 +446,195 @@ typedef struct camera2_device_ops { * Flush all in-progress captures. This includes all dequeued requests * (regular or reprocessing) that have not yet placed any outputs into a * stream or the frame queue. Partially completed captures must be completed - * normally. No new requests may be dequeued from the request or - * reprocessing queues until the flush completes. + * normally. No new requests may be dequeued from the request queue until + * the flush completes. */ int (*flush_captures_in_progress)(struct camera2_device *); /** - * Camera stream management + * Create a filled-in default request for standard camera use cases. + * + * The device must return a complete request that is configured to meet the + * requested use case, which must be one of the CAMERA2_TEMPLATE_* + * enums. All request control fields must be included, except for + * android.request.outputStreams and android.request.frameNumber. + * + * The metadata buffer returned must be allocated with + * allocate_camera_metadata. The framework takes ownership of the buffer. */ + int (*construct_default_request)(struct camera2_device *, + int request_template, + camera_metadata_t **request); - /** - * Operations on the input reprocessing stream + /********************************************************************** + * Stream management */ - int (*get_reprocess_stream_ops)(struct camera2_device *, - camera2_stream_ops_t **stream_ops); /** - * Get the number of streams that can be simultaneously allocated. - * A request may include any allocated pipeline for its output, without - * causing a substantial delay in frame production. + * allocate_stream: + * + * Allocate a new output stream for use, defined by the output buffer width, + * height, target, and possibly the pixel format. Returns the new stream's + * ID, gralloc usage flags, minimum queue buffer count, and possibly the + * pixel format, on success. Error conditions: + * + * - Requesting a width/height/format combination not listed as + * supported by the sensor's static characteristics + * + * - Asking for too many streams of a given format type (2 bayer raw + * streams, for example). + * + * Input parameters: + * + * - width, height, format: Specification for the buffers to be sent through + * this stream. Format is a value from the HAL_PIXEL_FORMAT_* list, or + * CAMERA2_HAL_PIXEL_FORMAT_OPAQUE. In the latter case, the camera device + * must select an appropriate (possible platform-specific) HAL pixel + * format to return in format_actual. In the former case, format_actual + * must be set to match format. + * + * - stream_ops: A structure of function pointers for obtaining and queuing + * up buffers for this stream. The underlying stream will be configured + * based on the usage and max_buffers outputs. The methods in this + * structure may not be called until after allocate_stream returns. + * + * Output parameters: + * + * - stream_id: An unsigned integer identifying this stream. This value is + * used in incoming requests to identify the stream, and in releasing the + * stream. + * + * - format_actual: If the input format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, + * then device must select the appropriate (possible platform-specific) + * pixel format and return it in *format_actual. It will be treated as an + * opaque value by the framework, and simply passed to the gralloc module + * when new buffers need to be allocated. If the input format is one of + * the values from HAL_PIXEL_FORMAT_* list, then *format_actual must be + * set equal to format. In the latter case, format_actual may also be + * NULL, in which case it can be ignored as an output. + * + * - usage: The gralloc usage mask needed by the HAL device for producing + * the requested type of data. This is used in allocating new gralloc + * buffers for the stream buffer queue. + * + * - max_buffers: The maximum number of buffers the HAL device may need to + * have dequeued at the same time. The device may not dequeue more buffers + * than this value at the same time. + * */ - int (*get_stream_slot_count)(struct camera2_device *); + int (*allocate_stream)( + struct camera2_device *, + // inputs + uint32_t width, + uint32_t height, + int format, + camera2_stream_ops_t *stream_ops, + // outputs + uint32_t *stream_id, + uint32_t *format_actual, + uint32_t *usage, + uint32_t *max_buffers); /** - * Allocate a new stream for use. Requires specifying which pipeline slot - * to use. Specifies the buffer width, height, and format. - * Error conditions: - * - Allocating an already-allocated slot without first releasing it - * - Requesting a width/height/format combination not listed as supported - * - Requesting a pipeline slot >= pipeline slot count. + * Register buffers for a given stream. This is called after a successful + * allocate_stream call, and before the first request referencing the stream + * is enqueued. This method is intended to allow the HAL device to map or + * otherwise prepare the buffers for later use. num_buffers is guaranteed to + * be at least max_buffers (from allocate_stream), but may be larger. The + * buffers will already be locked for use. At the end of the call, all the + * buffers must be ready to be returned to the queue. */ - int (*allocate_stream)( - struct camera2_device *, - uint32_t stream_slot, - uint32_t width, - uint32_t height, - uint32_t format, - camera2_stream_ops_t *camera2_stream_ops); + int (*register_stream_buffers)( + struct camera2_device *, + uint32_t stream_id, + int num_buffers, + buffer_handle_t *buffers); /** - * Release a stream. Returns an error if called when - * get_in_progress_count is non-zero, or if the pipeline slot is not - * allocated. + * Release a stream. Returns an error if called when get_in_progress_count + * is non-zero, or if the stream id is invalid. */ int (*release_stream)( - struct camera2_device *, - uint32_t stream_slot); + struct camera2_device *, + uint32_t stream_id); + + /** + * allocate_reprocess_stream: + * + * Allocate a new input stream for use, defined by the output buffer width, + * height, and the pixel format. Returns the new stream's ID, gralloc usage + * flags, and required simultaneously acquirable buffer count, on + * success. Error conditions: + * + * - Requesting a width/height/format combination not listed as + * supported by the sensor's static characteristics + * + * - Asking for too many reprocessing streams to be configured at once. + * + * Input parameters: + * + * - width, height, format: Specification for the buffers to be sent through + * this stream. Format must be a value from the HAL_PIXEL_FORMAT_* list. + * + * - reprocess_stream_ops: A structure of function pointers for acquiring + * and releasing buffers for this stream. The underlying stream will be + * configured based on the usage and max_buffers outputs. + * + * Output parameters: + * + * - stream_id: An unsigned integer identifying this stream. This value is + * used in incoming requests to identify the stream, and in releasing the + * stream. These ids are numbered separately from the input stream ids. + * + * - consumer_usage: The gralloc usage mask needed by the HAL device for + * consuming the requested type of data. This is used in allocating new + * gralloc buffers for the stream buffer queue. + * + * - max_buffers: The maximum number of buffers the HAL device may need to + * have acquired at the same time. The device may not have more buffers + * acquired at the same time than this value. + * + */ + int (*allocate_reprocess_stream)(struct camera2_device *, + uint32_t width, + uint32_t height, + uint32_t format, + camera2_stream_in_ops_t *reprocess_stream_ops, + // outputs + uint32_t *stream_id, + uint32_t *consumer_usage, + uint32_t *max_buffers); + + /** + * Release a reprocessing stream. Returns an error if called when + * get_in_progress_count is non-zero, or if the stream id is not + * valid. + */ + int (*release_reprocess_stream)( + struct camera2_device *, + uint32_t stream_id); + + /********************************************************************** + * Miscellaneous methods + */ + + /** + * Trigger asynchronous activity. This is used for triggering special + * behaviors of the camera 3A routines when they are in use. See the + * documentation for CAMERA2_TRIGGER_* above for details of the trigger ids + * and their arguments. + */ + int (*trigger_action)(struct camera2_device *, + uint32_t trigger_id, + int ext1, + int ext2); + + /** + * Notification callback setup + */ + int (*set_notify_callback)(struct camera2_device *, + camera2_notify_callback notify_cb, + void *user); /** * Get methods to query for vendor extension metadata tag infomation. May @@ -283,19 +644,17 @@ typedef struct camera2_device_ops { vendor_tag_query_ops_t **ops); /** - * Release the camera hardware. Requests that are in flight will be - * canceled. No further buffers will be pushed into any allocated pipelines - * once this call returns. - */ - void (*release)(struct camera2_device *); - - /** * Dump state of the camera hardware */ int (*dump)(struct camera2_device *, int fd); } camera2_device_ops_t; +/********************************************************************** + * + * Camera device definition + * + */ typedef struct camera2_device { /** * common.version must equal CAMERA_DEVICE_API_VERSION_2_0 to identify diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk index 340ec30..325e82d 100644 --- a/tests/camera2/Android.mk +++ b/tests/camera2/Android.mk @@ -2,13 +2,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - camera2.cpp + camera2.cpp \ + camera2_utils.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ libstlport \ libhardware \ - libcamera_metadata + libcamera_metadata \ + libgui LOCAL_STATIC_LIBRARIES := \ libgtest \ @@ -21,7 +23,7 @@ LOCAL_C_INCLUDES += \ external/stlport/stlport \ system/media/camera/include \ -LOCAL_MODULE:= camera2_hal_tests +LOCAL_MODULE:= camera2_test LOCAL_MODULE_TAGS := tests include $(BUILD_EXECUTABLE) diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index d13d7cd..50f0b06 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -14,10 +14,21 @@ * limitations under the License. */ -#include -#include +#define LOG_TAG "Camera2_test" +#define LOG_NDEBUG 0 + +#include #include #include +#include + +#include +#include +#include + +#include "camera2_utils.h" + +namespace android { class Camera2Test: public testing::Test { public: @@ -33,12 +44,16 @@ class Camera2Test: public testing::Test { ASSERT_TRUE(NULL != module) << "No camera module was set by hw_get_module"; - std::cout << " Camera module name: " << module->name << std::endl; - std::cout << " Camera module author: " << module->author << std::endl; - std::cout << " Camera module API version: 0x" << std::hex - << module->module_api_version << std::endl; - std::cout << " Camera module HAL API version: 0x" << std::hex - << module->hal_api_version << std::endl; + IF_ALOGV() { + std::cout << " Camera module name: " + << module->name << std::endl; + std::cout << " Camera module author: " + << module->author << std::endl; + std::cout << " Camera module API version: 0x" << std::hex + << module->module_api_version << std::endl; + std::cout << " Camera module HAL API version: 0x" << std::hex + << module->hal_api_version << std::endl; + } int16_t version2_0 = CAMERA_MODULE_API_VERSION_2_0; ASSERT_EQ(version2_0, module->module_api_version) @@ -52,7 +67,10 @@ class Camera2Test: public testing::Test { sNumCameras = sCameraModule->get_number_of_cameras(); ASSERT_LT(0, sNumCameras) << "No camera devices available!"; - std::cout << " Camera device count: " << sNumCameras << std::endl; + IF_ALOGV() { + std::cout << " Camera device count: " << sNumCameras << std::endl; + } + sCameraSupportsHal2 = new bool[sNumCameras]; for (int i = 0; i < sNumCameras; i++) { @@ -60,19 +78,24 @@ class Camera2Test: public testing::Test { res = sCameraModule->get_camera_info(i, &info); ASSERT_EQ(0, res) << "Failure getting camera info for camera " << i; - std::cout << " Camera device: " << std::dec - << i << std::endl;; - std::cout << " Facing: " << std::dec - << info.facing << std::endl; - std::cout << " Orientation: " << std::dec - << info.orientation << std::endl; - std::cout << " Version: 0x" << std::hex << - info.device_version << std::endl; + IF_ALOGV() { + std::cout << " Camera device: " << std::dec + << i << std::endl;; + std::cout << " Facing: " << std::dec + << info.facing << std::endl; + std::cout << " Orientation: " << std::dec + << info.orientation << std::endl; + std::cout << " Version: 0x" << std::hex << + info.device_version << std::endl; + } if (info.device_version >= CAMERA_DEVICE_API_VERSION_2_0) { sCameraSupportsHal2[i] = true; ASSERT_TRUE(NULL != info.static_camera_characteristics); - std::cout << " Static camera metadata:" << std::endl; - dump_camera_metadata(info.static_camera_characteristics, 0, 1); + IF_ALOGV() { + std::cout << " Static camera metadata:" << std::endl; + dump_camera_metadata(info.static_camera_characteristics, + 0, 1); + } } else { sCameraSupportsHal2[i] = false; } @@ -83,13 +106,26 @@ class Camera2Test: public testing::Test { return sCameraModule; } - static const camera2_device_t *openCameraDevice(int id) { + static int getNumCameras() { + return sNumCameras; + } + + static bool isHal2Supported(int id) { + return sCameraSupportsHal2[id]; + } + + static camera2_device_t *openCameraDevice(int id) { + ALOGV("Opening camera %d", id); if (NULL == sCameraSupportsHal2) return NULL; if (id >= sNumCameras) return NULL; if (!sCameraSupportsHal2[id]) return NULL; hw_device_t *device = NULL; const camera_module_t *cam_module = getCameraModule(); + if (cam_module == NULL) { + return NULL; + } + char camId[10]; int res; @@ -98,7 +134,7 @@ class Camera2Test: public testing::Test { (const hw_module_t*)cam_module, camId, &device); - if (res < 0 || cam_module == NULL) { + if (res != NO_ERROR || device == NULL) { return NULL; } camera2_device_t *cam_device = @@ -106,18 +142,439 @@ class Camera2Test: public testing::Test { return cam_device; } - private: + static status_t configureCameraDevice(camera2_device_t *dev, + MetadataQueue &requestQueue, + MetadataQueue &frameQueue, + NotifierListener &listener) { + + status_t err; + + err = dev->ops->set_request_queue_src_ops(dev, + requestQueue.getToConsumerInterface()); + if (err != OK) return err; + + requestQueue.setFromConsumerInterface(dev); + + err = dev->ops->set_frame_queue_dst_ops(dev, + frameQueue.getToProducerInterface()); + if (err != OK) return err; + + err = listener.getNotificationsFrom(dev); + if (err != OK) return err; + + vendor_tag_query_ops_t *vendor_metadata_tag_ops; + err = dev->ops->get_metadata_vendor_tag_ops(dev, &vendor_metadata_tag_ops); + if (err != OK) return err; + + err = set_camera_metadata_vendor_tag_ops(vendor_metadata_tag_ops); + if (err != OK) return err; + + return OK; + } + + static status_t closeCameraDevice(camera2_device_t *cam_dev) { + int res; + ALOGV("Closing camera %p", cam_dev); + + hw_device_t *dev = reinterpret_cast(cam_dev); + res = dev->close(dev); + return res; + } + + void setUpCamera(int id) { + ASSERT_GT(sNumCameras, id); + status_t res; + + if (mDevice != NULL) { + closeCameraDevice(mDevice); + } + mDevice = openCameraDevice(id); + ASSERT_TRUE(NULL != mDevice) << "Failed to open camera device"; + + camera_info info; + res = sCameraModule->get_camera_info(id, &info); + ASSERT_EQ(OK, res); + mStaticInfo = info.static_camera_characteristics; + + res = configureCameraDevice(mDevice, + mRequests, + mFrames, + mNotifications); + ASSERT_EQ(OK, res) << "Failure to configure camera device"; + + } + + void setUpStream(sp consumer, + int width, int height, int format, int *id) { + status_t res; + + StreamAdapter* stream = new StreamAdapter(consumer); + + ALOGV("Creating stream, format 0x%x, %d x %d", format, width, height); + res = stream->connectToDevice(mDevice, width, height, format); + ASSERT_EQ(NO_ERROR, res) << "Failed to connect to stream: " + << strerror(-res); + mStreams.push_back(stream); + + *id = stream->getId(); + } + + void disconnectStream(int id) { + status_t res; + unsigned int i=0; + for (; i < mStreams.size(); i++) { + if (mStreams[i]->getId() == id) { + res = mStreams[i]->disconnect(); + ASSERT_EQ(NO_ERROR, res) << + "Failed to disconnect stream " << id; + break; + } + } + ASSERT_GT(mStreams.size(), i) << "Stream id not found:" << id; + } + + void getResolutionList(uint32_t format, + uint32_t **list, + size_t *count) { + + uint32_t *availableFormats; + size_t availableFormatsCount; + status_t res; + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_FORMATS, + NULL, + (void**)&availableFormats, + &availableFormatsCount); + ASSERT_EQ(OK, res); + + uint32_t formatIdx; + for (formatIdx=0; formatIdx < availableFormatsCount; formatIdx++) { + if (availableFormats[formatIdx] == format) break; + } + ASSERT_NE(availableFormatsCount, formatIdx) + << "No support found for format 0x" << std::hex << format; + + uint32_t *availableSizesPerFormat; + size_t availableSizesPerFormatCount; + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_SIZES_PER_FORMAT, + NULL, + (void**)&availableSizesPerFormat, + &availableSizesPerFormatCount); + ASSERT_EQ(OK, res); + + int size_offset = 0; + for (unsigned int i=0; i < formatIdx; i++) { + size_offset += availableSizesPerFormat[i]; + } + + uint32_t *availableSizes; + size_t availableSizesCount; + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_SIZES, + NULL, + (void**)&availableSizes, + &availableSizesCount); + ASSERT_EQ(OK, res); + + *list = availableSizes + size_offset; + *count = availableSizesPerFormat[formatIdx]; + } + + virtual void SetUp() { + const ::testing::TestInfo* const testInfo = + ::testing::UnitTest::GetInstance()->current_test_info(); + + ALOGV("*** Starting test %s in test case %s", testInfo->name(), testInfo->test_case_name()); + mDevice = NULL; + } + + virtual void TearDown() { + for (unsigned int i = 0; i < mStreams.size(); i++) { + delete mStreams[i]; + } + if (mDevice != NULL) { + closeCameraDevice(mDevice); + } + } + + camera2_device *mDevice; + camera_metadata_t *mStaticInfo; + + MetadataQueue mRequests; + MetadataQueue mFrames; + NotifierListener mNotifications; + + Vector mStreams; + + private: static camera_module_t *sCameraModule; - static int sNumCameras; - static bool *sCameraSupportsHal2; + static int sNumCameras; + static bool *sCameraSupportsHal2; }; camera_module_t *Camera2Test::sCameraModule = NULL; -int Camera2Test::sNumCameras = 0; -bool *Camera2Test::sCameraSupportsHal2 = NULL; +bool *Camera2Test::sCameraSupportsHal2 = NULL; +int Camera2Test::sNumCameras = 0; +static const nsecs_t USEC = 1000; +static const nsecs_t MSEC = 1000*USEC; +static const nsecs_t SEC = 1000*MSEC; -TEST_F(Camera2Test, Basic) { - ASSERT_TRUE(NULL != getCameraModule()); + +TEST_F(Camera2Test, OpenClose) { + status_t res; + + for (int id = 0; id < getNumCameras(); id++) { + if (!isHal2Supported(id)) continue; + + camera2_device_t *d = openCameraDevice(id); + ASSERT_TRUE(NULL != d) << "Failed to open camera device"; + + res = closeCameraDevice(d); + ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device"; + } } + +TEST_F(Camera2Test, Capture1Raw) { + status_t res; + + for (int id = 0; id < getNumCameras(); id++) { + if (!isHal2Supported(id)) continue; + + ASSERT_NO_FATAL_FAILURE(setUpCamera(id)); + + sp rawConsumer = new CpuConsumer(1); + sp rawWaiter = new FrameWaiter(); + rawConsumer->setFrameAvailableListener(rawWaiter); + + uint32_t *rawResolutions; + size_t rawResolutionsCount; + + int format = HAL_PIXEL_FORMAT_RAW_SENSOR; + + getResolutionList(format, + &rawResolutions, &rawResolutionsCount); + ASSERT_LT((uint32_t)0, rawResolutionsCount); + + // Pick first available raw resolution + int width = rawResolutions[0]; + int height = rawResolutions[1]; + + int streamId; + ASSERT_NO_FATAL_FAILURE( + setUpStream(rawConsumer->getProducerInterface(), + width, height, format, &streamId) ); + + camera_metadata_t *request; + request = allocate_camera_metadata(20, 2000); + + uint8_t metadataMode = ANDROID_REQUEST_METADATA_FULL; + add_camera_metadata_entry(request, + ANDROID_REQUEST_METADATA_MODE, + (void**)&metadataMode, 1); + uint32_t outputStreams = streamId; + add_camera_metadata_entry(request, + ANDROID_REQUEST_OUTPUT_STREAMS, + (void**)&outputStreams, 1); + + uint64_t exposureTime = 2*MSEC; + add_camera_metadata_entry(request, + ANDROID_SENSOR_EXPOSURE_TIME, + (void**)&exposureTime, 1); + uint64_t frameDuration = 30*MSEC; + add_camera_metadata_entry(request, + ANDROID_SENSOR_FRAME_DURATION, + (void**)&frameDuration, 1); + uint32_t sensitivity = 100; + add_camera_metadata_entry(request, + ANDROID_SENSOR_SENSITIVITY, + (void**)&sensitivity, 1); + + uint32_t hourOfDay = 12; + add_camera_metadata_entry(request, + 0x80000000, // EMULATOR_HOUROFDAY + &hourOfDay, 1); + + IF_ALOGV() { + std::cout << "Input request: " << std::endl; + dump_camera_metadata(request, 0, 1); + } + + res = mRequests.enqueue(request); + ASSERT_EQ(NO_ERROR, res) << "Can't enqueue request: " << strerror(-res); + + res = mFrames.waitForBuffer(exposureTime + SEC); + ASSERT_EQ(NO_ERROR, res) << "No frame to get: " << strerror(-res); + + camera_metadata_t *frame; + res = mFrames.dequeue(&frame); + ASSERT_EQ(NO_ERROR, res); + ASSERT_TRUE(frame != NULL); + + IF_ALOGV() { + std::cout << "Output frame:" << std::endl; + dump_camera_metadata(frame, 0, 1); + } + + res = rawWaiter->waitForFrame(exposureTime + SEC); + ASSERT_EQ(NO_ERROR, res); + + CpuConsumer::LockedBuffer buffer; + res = rawConsumer->lockNextBuffer(&buffer); + ASSERT_EQ(NO_ERROR, res); + + IF_ALOGV() { + const char *dumpname = + "/data/local/tmp/camera2_test-capture1raw-dump.raw"; + ALOGV("Dumping raw buffer to %s", dumpname); + // Write to file + std::ofstream rawFile(dumpname); + for (unsigned int y = 0; y < buffer.height; y++) { + rawFile.write((const char *)(buffer.data + y * buffer.stride * 2), + buffer.width * 2); + } + rawFile.close(); + } + + res = rawConsumer->unlockBuffer(buffer); + ASSERT_EQ(NO_ERROR, res); + + ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId)); + + res = closeCameraDevice(mDevice); + ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device"; + + } +} + +TEST_F(Camera2Test, CaptureBurstRaw) { + status_t res; + + for (int id = 0; id < getNumCameras(); id++) { + if (!isHal2Supported(id)) continue; + + ASSERT_NO_FATAL_FAILURE(setUpCamera(id)); + + sp rawConsumer = new CpuConsumer(1); + sp rawWaiter = new FrameWaiter(); + rawConsumer->setFrameAvailableListener(rawWaiter); + + uint32_t *rawResolutions; + size_t rawResolutionsCount; + + int format = HAL_PIXEL_FORMAT_RAW_SENSOR; + + getResolutionList(format, + &rawResolutions, &rawResolutionsCount); + ASSERT_LT((uint32_t)0, rawResolutionsCount); + + // Pick first available raw resolution + int width = rawResolutions[0]; + int height = rawResolutions[1]; + + int streamId; + ASSERT_NO_FATAL_FAILURE( + setUpStream(rawConsumer->getProducerInterface(), + width, height, format, &streamId) ); + + camera_metadata_t *request; + request = allocate_camera_metadata(20, 2000); + + uint8_t metadataMode = ANDROID_REQUEST_METADATA_FULL; + add_camera_metadata_entry(request, + ANDROID_REQUEST_METADATA_MODE, + (void**)&metadataMode, 1); + uint32_t outputStreams = streamId; + add_camera_metadata_entry(request, + ANDROID_REQUEST_OUTPUT_STREAMS, + (void**)&outputStreams, 1); + + uint64_t frameDuration = 30*MSEC; + add_camera_metadata_entry(request, + ANDROID_SENSOR_FRAME_DURATION, + (void**)&frameDuration, 1); + uint32_t sensitivity = 100; + add_camera_metadata_entry(request, + ANDROID_SENSOR_SENSITIVITY, + (void**)&sensitivity, 1); + + uint32_t hourOfDay = 12; + add_camera_metadata_entry(request, + 0x80000000, // EMULATOR_HOUROFDAY + &hourOfDay, 1); + + IF_ALOGV() { + std::cout << "Input request template: " << std::endl; + dump_camera_metadata(request, 0, 1); + } + + int numCaptures = 10; + + // Enqueue numCaptures requests with increasing exposure time + + uint64_t exposureTime = 1 * MSEC; + for (int reqCount = 0; reqCount < numCaptures; reqCount++ ) { + camera_metadata_t *req; + req = allocate_camera_metadata(20, 2000); + append_camera_metadata(req, request); + + add_camera_metadata_entry(req, + ANDROID_SENSOR_EXPOSURE_TIME, + (void**)&exposureTime, 1); + exposureTime *= 2; + + res = mRequests.enqueue(req); + ASSERT_EQ(NO_ERROR, res) << "Can't enqueue request: " + << strerror(-res); + } + + // Get frames and image buffers one by one + for (int frameCount = 0; frameCount < 10; frameCount++) { + res = mFrames.waitForBuffer(SEC); + ASSERT_EQ(NO_ERROR, res) << "No frame to get: " << strerror(-res); + + camera_metadata_t *frame; + res = mFrames.dequeue(&frame); + ASSERT_EQ(NO_ERROR, res); + ASSERT_TRUE(frame != NULL); + + uint32_t *frameNumber; + res = find_camera_metadata_entry(frame, + ANDROID_REQUEST_FRAME_COUNT, + NULL, (void**)&frameNumber, NULL); + ASSERT_EQ(NO_ERROR, res); + ASSERT_EQ(frameCount, *frameNumber); + + res = rawWaiter->waitForFrame(SEC); + ASSERT_EQ(NO_ERROR, res) << + "Never got raw data for capture " << frameCount; + + CpuConsumer::LockedBuffer buffer; + res = rawConsumer->lockNextBuffer(&buffer); + ASSERT_EQ(NO_ERROR, res); + + IF_ALOGV() { + char dumpname[60]; + snprintf(dumpname, 60, + "/data/local/tmp/camera2_test-capture1raw-dump_%d.raw", + frameCount); + ALOGV("Dumping raw buffer to %s", dumpname); + // Write to file + std::ofstream rawFile(dumpname); + for (unsigned int y = 0; y < buffer.height; y++) { + rawFile.write( + (const char *)(buffer.data + y * buffer.stride * 2), + buffer.width * 2); + } + rawFile.close(); + } + + res = rawConsumer->unlockBuffer(buffer); + ASSERT_EQ(NO_ERROR, res); + } + } +} + +} // namespace android diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp new file mode 100644 index 0000000..bd56644 --- /dev/null +++ b/tests/camera2/camera2_utils.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +// Utility classes for camera2 HAL testing + +#define LOG_TAG "Camera2_test_utils" +#define LOG_NDEBUG 0 + +#include "utils/Log.h" +#include "camera2_utils.h" + +namespace android { + +/** + * MetadataQueue + */ + +MetadataQueue::MetadataQueue(): + mDevice(NULL), + mFrameCount(0), + mCount(0), + mStreamSlotCount(0), + mSignalConsumer(true) +{ + camera2_request_queue_src_ops::dequeue_request = consumer_dequeue; + camera2_request_queue_src_ops::request_count = consumer_buffer_count; + camera2_request_queue_src_ops::free_request = consumer_free; + + camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue; + camera2_frame_queue_dst_ops::cancel_frame = producer_cancel; + camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue; +} + +MetadataQueue::~MetadataQueue() { + freeBuffers(mEntries.begin(), mEntries.end()); + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); +} + +// Interface to camera2 HAL as consumer (input requests/reprocessing) +camera2_request_queue_src_ops_t* MetadataQueue::getToConsumerInterface() { + return static_cast(this); +} + +void MetadataQueue::setFromConsumerInterface(camera2_device_t *d) { + mDevice = d; +} + +camera2_frame_queue_dst_ops_t* MetadataQueue::getToProducerInterface() { + return static_cast(this); +} + +// Real interfaces +status_t MetadataQueue::enqueue(camera_metadata_t *buf) { + Mutex::Autolock l(mMutex); + + mCount++; + mEntries.push_back(buf); + notEmpty.signal(); + + if (mSignalConsumer && mDevice != NULL) { + mSignalConsumer = false; + + mMutex.unlock(); + ALOGV("%s: Signaling consumer", __FUNCTION__); + mDevice->ops->notify_request_queue_not_empty(mDevice); + mMutex.lock(); + } + return OK; +} + +int MetadataQueue::getBufferCount() { + Mutex::Autolock l(mMutex); + if (mStreamSlotCount > 0) { + return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS; + } + return mCount; +} + +status_t MetadataQueue::dequeue(camera_metadata_t **buf, bool incrementCount) { + Mutex::Autolock l(mMutex); + + if (mCount == 0) { + if (mStreamSlotCount == 0) { + ALOGV("%s: Empty", __FUNCTION__); + *buf = NULL; + mSignalConsumer = true; + return OK; + } + ALOGV("%s: Streaming %d frames to queue", __FUNCTION__, + mStreamSlotCount); + + for (List::iterator slotEntry = mStreamSlot.begin(); + slotEntry != mStreamSlot.end(); + slotEntry++ ) { + size_t entries = get_camera_metadata_entry_count(*slotEntry); + size_t dataBytes = get_camera_metadata_data_count(*slotEntry); + + camera_metadata_t *copy = allocate_camera_metadata(entries, dataBytes); + append_camera_metadata(copy, *slotEntry); + mEntries.push_back(copy); + } + mCount = mStreamSlotCount; + } + ALOGV("MetadataQueue: deque (%d buffers)", mCount); + camera_metadata_t *b = *(mEntries.begin()); + mEntries.erase(mEntries.begin()); + + if (incrementCount) { + add_camera_metadata_entry(b, + ANDROID_REQUEST_FRAME_COUNT, + (void**)&mFrameCount, 1); + mFrameCount++; + } + + *buf = b; + mCount--; + + return OK; +} + +status_t MetadataQueue::waitForBuffer(nsecs_t timeout) { + Mutex::Autolock l(mMutex); + status_t res; + while (mCount == 0) { + res = notEmpty.waitRelative(mMutex,timeout); + if (res != OK) return res; + } + return OK; +} + +status_t MetadataQueue::setStreamSlot(camera_metadata_t *buf) { + if (buf == NULL) { + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); + mStreamSlotCount = 0; + return OK; + } + if (mStreamSlotCount > 1) { + List::iterator deleter = ++mStreamSlot.begin(); + freeBuffers(++mStreamSlot.begin(), mStreamSlot.end()); + mStreamSlotCount = 1; + } + if (mStreamSlotCount == 1) { + free_camera_metadata( *(mStreamSlot.begin()) ); + *(mStreamSlot.begin()) = buf; + } else { + mStreamSlot.push_front(buf); + mStreamSlotCount = 1; + } + return OK; +} + +status_t MetadataQueue::setStreamSlot(const List &bufs) { + if (mStreamSlotCount > 0) { + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); + } + mStreamSlot = bufs; + mStreamSlotCount = mStreamSlot.size(); + + return OK; +} + +status_t MetadataQueue::freeBuffers(List::iterator start, + List::iterator end) { + while (start != end) { + free_camera_metadata(*start); + start = mStreamSlot.erase(start); + } + return OK; +} + +int MetadataQueue::consumer_buffer_count( + camera2_request_queue_src_ops_t *q) { + MetadataQueue *queue = static_cast(q); + return queue->getBufferCount(); +} + +int MetadataQueue::consumer_dequeue(camera2_request_queue_src_ops_t *q, + camera_metadata_t **buffer) { + MetadataQueue *queue = static_cast(q); + return queue->dequeue(buffer, true); +} + +int MetadataQueue::consumer_free(camera2_request_queue_src_ops_t *q, + camera_metadata_t *old_buffer) { + MetadataQueue *queue = static_cast(q); + free_camera_metadata(old_buffer); + return OK; +} + +int MetadataQueue::producer_dequeue(camera2_frame_queue_dst_ops_t *q, + size_t entries, size_t bytes, + camera_metadata_t **buffer) { + camera_metadata_t *new_buffer = + allocate_camera_metadata(entries, bytes); + if (new_buffer == NULL) return NO_MEMORY; + *buffer = new_buffer; + return OK; +} + +int MetadataQueue::producer_cancel(camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *old_buffer) { + free_camera_metadata(old_buffer); + return OK; +} + +int MetadataQueue::producer_enqueue(camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *filled_buffer) { + MetadataQueue *queue = static_cast(q); + return queue->enqueue(filled_buffer); +} + +/** + * NotifierListener + */ + +NotifierListener::NotifierListener() { +} + +status_t NotifierListener::getNotificationsFrom(camera2_device *dev) { + if (!dev) return BAD_VALUE; + status_t err; + err = dev->ops->set_notify_callback(dev, + notify_callback_dispatch, + (void*)this); + return err; +} + +status_t NotifierListener::getNextNotification(int32_t *msg_type, + int32_t *ext1, + int32_t *ext2, + int32_t *ext3) { + Mutex::Autolock l(mMutex); + if (mNotifications.size() == 0) return BAD_VALUE; + return getNextNotificationLocked(msg_type, ext1, ext2, ext3); +} + +status_t NotifierListener::waitForNotification(int32_t *msg_type, + int32_t *ext1, + int32_t *ext2, + int32_t *ext3) { + Mutex::Autolock l(mMutex); + while (mNotifications.size() == 0) { + mNewNotification.wait(mMutex); + } + return getNextNotificationLocked(msg_type, ext1, ext2, ext3); +} + +int NotifierListener::numNotifications() { + Mutex::Autolock l(mMutex); + return mNotifications.size(); +} + +status_t NotifierListener::getNextNotificationLocked(int32_t *msg_type, + int32_t *ext1, + int32_t *ext2, + int32_t *ext3) { + *msg_type = mNotifications.begin()->msg_type; + *ext1 = mNotifications.begin()->ext1; + *ext2 = mNotifications.begin()->ext2; + *ext3 = mNotifications.begin()->ext3; + mNotifications.erase(mNotifications.begin()); + return OK; +} + +void NotifierListener::onNotify(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3) { + Mutex::Autolock l(mMutex); + mNotifications.push_back(Notification(msg_type, ext1, ext2, ext3)); + mNewNotification.signal(); +} + +void NotifierListener::notify_callback_dispatch(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3, + void *user) { + NotifierListener *me = reinterpret_cast(user); + me->onNotify(msg_type, ext1, ext2, ext3); +} + +/** + * StreamAdapter + */ + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char*)(ptr) - offsetof(type, member)) +#endif + +StreamAdapter::StreamAdapter(sp consumer): + mState(UNINITIALIZED), mDevice(NULL), + mId(-1), + mWidth(0), mHeight(0), mFormatRequested(0) +{ + mConsumerInterface = new SurfaceTextureClient(consumer); + camera2_stream_ops::dequeue_buffer = dequeue_buffer; + camera2_stream_ops::enqueue_buffer = enqueue_buffer; + camera2_stream_ops::cancel_buffer = cancel_buffer; + camera2_stream_ops::set_crop = set_crop; +} + +StreamAdapter::~StreamAdapter() { + disconnect(); +} + +status_t StreamAdapter::connectToDevice(camera2_device_t *d, + uint32_t width, uint32_t height, int format) { + if (mState != UNINITIALIZED) return INVALID_OPERATION; + if (d == NULL) { + ALOGE("%s: Null device passed to stream adapter", __FUNCTION__); + return BAD_VALUE; + } + + status_t res; + + mWidth = width; + mHeight = height; + mFormatRequested = format; + + // Allocate device-side stream interface + + uint32_t id; + uint32_t formatActual; + uint32_t usage; + uint32_t maxBuffers = 2; + res = d->ops->allocate_stream(d, + mWidth, mHeight, mFormatRequested, getStreamOps(), + &id, &formatActual, &usage, &maxBuffers); + if (res != OK) { + ALOGE("%s: Device stream allocation failed: %s (%d)", + __FUNCTION__, strerror(-res), res); + mState = UNINITIALIZED; + return res; + } + mDevice = d; + + mId = id; + mFormat = formatActual; + mUsage = usage; + mMaxProducerBuffers = maxBuffers; + + // Configure consumer-side ANativeWindow interface + + res = native_window_api_connect(mConsumerInterface.get(), + NATIVE_WINDOW_API_CAMERA); + if (res != OK) { + ALOGE("%s: Unable to connect to native window for stream %d", + __FUNCTION__, mId); + mState = ALLOCATED; + return res; + } + + res = native_window_set_usage(mConsumerInterface.get(), mUsage); + if (res != OK) { + ALOGE("%s: Unable to configure usage %08x for stream %d", + __FUNCTION__, mUsage, mId); + mState = CONNECTED; + return res; + } + + res = native_window_set_buffers_geometry(mConsumerInterface.get(), + mWidth, mHeight, mFormat); + if (res != OK) { + ALOGE("%s: Unable to configure buffer geometry" + " %d x %d, format 0x%x for stream %d", + __FUNCTION__, mWidth, mHeight, mFormat, mId); + mState = CONNECTED; + return res; + } + + int maxConsumerBuffers; + res = mConsumerInterface->query(mConsumerInterface.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); + if (res != OK) { + ALOGE("%s: Unable to query consumer undequeued" + " buffer count for stream %d", __FUNCTION__, mId); + mState = CONNECTED; + return res; + } + mMaxConsumerBuffers = maxConsumerBuffers; + + ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__, + mMaxProducerBuffers, mMaxConsumerBuffers); + + int totalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers; + + res = native_window_set_buffer_count(mConsumerInterface.get(), + totalBuffers); + if (res != OK) { + ALOGE("%s: Unable to set buffer count for stream %d", + __FUNCTION__, mId); + mState = CONNECTED; + return res; + } + + // Register allocated buffers with HAL device + buffer_handle_t *buffers = new buffer_handle_t[totalBuffers]; + ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[totalBuffers]; + int bufferIdx = 0; + for (; bufferIdx < totalBuffers; bufferIdx++) { + res = mConsumerInterface->dequeueBuffer(mConsumerInterface.get(), + &anwBuffers[bufferIdx]); + if (res != OK) { + ALOGE("%s: Unable to dequeue buffer %d for initial registration for" + "stream %d", __FUNCTION__, bufferIdx, mId); + mState = CONNECTED; + goto cleanUpBuffers; + } + + res = mConsumerInterface->lockBuffer(mConsumerInterface.get(), + anwBuffers[bufferIdx]); + if (res != OK) { + ALOGE("%s: Unable to lock buffer %d for initial registration for" + "stream %d", __FUNCTION__, bufferIdx, mId); + mState = CONNECTED; + bufferIdx++; + goto cleanUpBuffers; + } + + buffers[bufferIdx] = anwBuffers[bufferIdx]->handle; + } + + res = mDevice->ops->register_stream_buffers(mDevice, + mId, + totalBuffers, + buffers); + if (res != OK) { + ALOGE("%s: Unable to register buffers with HAL device for stream %d", + __FUNCTION__, mId); + mState = CONNECTED; + } else { + mState = ACTIVE; + } + +cleanUpBuffers: + for (int i = 0; i < bufferIdx; i++) { + res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(), + anwBuffers[i]); + } + delete anwBuffers; + delete buffers; + + return res; +} + +status_t StreamAdapter::disconnect() { + status_t res; + if (mState >= ALLOCATED) { + res = mDevice->ops->release_stream(mDevice, mId); + if (res != OK) { + ALOGE("%s: Unable to release stream %d", + __FUNCTION__, mId); + return res; + } + } + if (mState >= CONNECTED) { + res = native_window_api_disconnect(mConsumerInterface.get(), + NATIVE_WINDOW_API_CAMERA); + if (res != OK) { + ALOGE("%s: Unable to disconnect stream %d from native window", + __FUNCTION__, mId); + return res; + } + } + mId = -1; + mState = DISCONNECTED; + return OK; +} + +int StreamAdapter::getId() { + return mId; +} + +camera2_stream_ops *StreamAdapter::getStreamOps() { + return static_cast(this); +} + +ANativeWindow* StreamAdapter::toANW(camera2_stream_ops_t *w) { + return static_cast(w)->mConsumerInterface.get(); +} + +int StreamAdapter::dequeue_buffer(camera2_stream_ops_t *w, + buffer_handle_t** buffer) { + int res; + int state = static_cast(w)->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + + ANativeWindow *a = toANW(w); + ANativeWindowBuffer* anb; + res = a->dequeueBuffer(a, &anb); + if (res != OK) return res; + res = a->lockBuffer(a, anb); + if (res != OK) return res; + + *buffer = &(anb->handle); + + return res; +} + +int StreamAdapter::enqueue_buffer(camera2_stream_ops_t* w, + int64_t timestamp, + buffer_handle_t* buffer) { + int state = static_cast(w)->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + ANativeWindow *a = toANW(w); + status_t err; + err = native_window_set_buffers_timestamp(a, timestamp); + if (err != OK) return err; + return a->queueBuffer(a, + container_of(buffer, ANativeWindowBuffer, handle)); +} + +int StreamAdapter::cancel_buffer(camera2_stream_ops_t* w, + buffer_handle_t* buffer) { + int state = static_cast(w)->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + ANativeWindow *a = toANW(w); + return a->cancelBuffer(a, + container_of(buffer, ANativeWindowBuffer, handle)); +} + +int StreamAdapter::set_crop(camera2_stream_ops_t* w, + int left, int top, int right, int bottom) { + int state = static_cast(w)->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + ANativeWindow *a = toANW(w); + android_native_rect_t crop = { left, top, right, bottom }; + return native_window_set_crop(a, &crop); +} + +/** + * FrameWaiter + */ + +FrameWaiter::FrameWaiter(): + mPendingFrames(0) { +} + +status_t FrameWaiter::waitForFrame(nsecs_t timeout) { + status_t res; + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + res = mCondition.waitRelative(mMutex, timeout); + if (res != OK) return res; + } + mPendingFrames--; + return OK; +} + +void FrameWaiter::onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mCondition.signal(); +} + +} // namespace android diff --git a/tests/camera2/camera2_utils.h b/tests/camera2/camera2_utils.h new file mode 100644 index 0000000..4e0b521 --- /dev/null +++ b/tests/camera2/camera2_utils.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +// Utility classes for camera2 HAL testing + +#include +#include + +#include +#include + +#include +#include +#include + +namespace android { + +/** + * Queue class for both sending requests to a camera2 device, and for receiving + * frames from a camera2 device. + */ +class MetadataQueue: public camera2_request_queue_src_ops_t, + public camera2_frame_queue_dst_ops_t { + public: + MetadataQueue(); + ~MetadataQueue(); + + // Interface to camera2 HAL device, either for requests (device is consumer) + // or for frames (device is producer) + camera2_request_queue_src_ops_t* getToConsumerInterface(); + void setFromConsumerInterface(camera2_device_t *d); + + camera2_frame_queue_dst_ops_t* getToProducerInterface(); + + // Real interfaces. On enqueue, queue takes ownership of buffer pointer + // On dequeue, user takes ownership of buffer pointer. + status_t enqueue(camera_metadata_t *buf); + status_t dequeue(camera_metadata_t **buf, bool incrementCount = true); + int getBufferCount(); + status_t waitForBuffer(nsecs_t timeout); + + // Set repeating buffer(s); if the queue is empty on a dequeue call, the + // queue copies the contents of the stream slot into the queue, and then + // dequeues the first new entry. + status_t setStreamSlot(camera_metadata_t *buf); + status_t setStreamSlot(const List &bufs); + + private: + status_t freeBuffers(List::iterator start, + List::iterator end); + + camera2_device_t *mDevice; + + Mutex mMutex; + Condition notEmpty; + + int mFrameCount; + + int mCount; + List mEntries; + int mStreamSlotCount; + List mStreamSlot; + + bool mSignalConsumer; + + static int consumer_buffer_count(camera2_request_queue_src_ops_t *q); + + static int consumer_dequeue(camera2_request_queue_src_ops_t *q, + camera_metadata_t **buffer); + + static int consumer_free(camera2_request_queue_src_ops_t *q, + camera_metadata_t *old_buffer); + + static int producer_dequeue(camera2_frame_queue_dst_ops_t *q, + size_t entries, size_t bytes, + camera_metadata_t **buffer); + + static int producer_cancel(camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *old_buffer); + + static int producer_enqueue(camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *filled_buffer); + +}; + +/** + * Basic class to receive and queue up notifications from the camera device + */ + +class NotifierListener { + public: + + NotifierListener(); + + status_t getNotificationsFrom(camera2_device *dev); + + status_t getNextNotification(int32_t *msg_type, int32_t *ext1, + int32_t *ext2, int32_t *ext3); + + status_t waitForNotification(int32_t *msg_type, int32_t *ext1, + int32_t *ext2, int32_t *ext3); + + int numNotifications(); + + private: + + status_t getNextNotificationLocked(int32_t *msg_type, + int32_t *ext1, int32_t *ext2, int32_t *ext3); + + struct Notification { + Notification(int32_t type, int32_t e1, int32_t e2, int32_t e3): + msg_type(type), + ext1(e1), + ext2(e2), + ext3(e3) + {} + + int32_t msg_type; + int32_t ext1; + int32_t ext2; + int32_t ext3; + }; + + List mNotifications; + + Mutex mMutex; + Condition mNewNotification; + + void onNotify(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3); + + static void notify_callback_dispatch(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3, + void *user); + +}; + +/** + * Adapter from an ISurfaceTexture interface to camera2 device stream ops. + * Also takes care of allocating/deallocating stream in device interface + */ +class StreamAdapter: public camera2_stream_ops { + public: + StreamAdapter(sp consumer); + + ~StreamAdapter(); + + status_t connectToDevice(camera2_device_t *d, + uint32_t width, uint32_t height, int format); + + status_t disconnect(); + + // Get stream ID. Only valid after a successful connectToDevice call. + int getId(); + + private: + enum { + ERROR = -1, + DISCONNECTED = 0, + UNINITIALIZED, + ALLOCATED, + CONNECTED, + ACTIVE + } mState; + + sp mConsumerInterface; + camera2_device_t *mDevice; + + uint32_t mId; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mFormat; + uint32_t mUsage; + uint32_t mMaxProducerBuffers; + uint32_t mMaxConsumerBuffers; + + int mFormatRequested; + + camera2_stream_ops *getStreamOps(); + + static ANativeWindow* toANW(camera2_stream_ops_t *w); + + static int dequeue_buffer(camera2_stream_ops_t *w, + buffer_handle_t** buffer); + + static int enqueue_buffer(camera2_stream_ops_t* w, + int64_t timestamp, + buffer_handle_t* buffer); + + static int cancel_buffer(camera2_stream_ops_t* w, + buffer_handle_t* buffer); + + static int set_crop(camera2_stream_ops_t* w, + int left, int top, int right, int bottom); + +}; + +/** + * Simple class to wait on the CpuConsumer to have a frame available + */ +class FrameWaiter : public CpuConsumer::FrameAvailableListener { + public: + FrameWaiter(); + + /** + * Wait for max timeout nanoseconds for a new frame. Returns + * OK if a frame is available, TIMED_OUT if the timeout was reached. + */ + status_t waitForFrame(nsecs_t timeout); + + virtual void onFrameAvailable(); + + int mPendingFrames; + Mutex mMutex; + Condition mCondition; +}; + +} -- cgit v1.1 From e6a3c3c1135d8c097be5e82103abdd832c02de7c Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 11 May 2012 16:18:42 -0700 Subject: Camera2: Match updated camera_metadata methods. Bug: 6243944 Change-Id: Ib691ef513b4811ca1290f0a9a4e3c1ce1e3f0945 --- tests/camera2/camera2.cpp | 67 ++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 50f0b06..cc2face 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -234,52 +234,43 @@ class Camera2Test: public testing::Test { ASSERT_GT(mStreams.size(), i) << "Stream id not found:" << id; } - void getResolutionList(uint32_t format, - uint32_t **list, + void getResolutionList(int32_t format, + int32_t **list, size_t *count) { - uint32_t *availableFormats; - size_t availableFormatsCount; status_t res; + camera_metadata_entry_t availableFormats; res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_FORMATS, - NULL, - (void**)&availableFormats, - &availableFormatsCount); + &availableFormats); ASSERT_EQ(OK, res); uint32_t formatIdx; - for (formatIdx=0; formatIdx < availableFormatsCount; formatIdx++) { - if (availableFormats[formatIdx] == format) break; + for (formatIdx=0; formatIdx < availableFormats.count; formatIdx++) { + if (availableFormats.data.i32[formatIdx] == format) break; } - ASSERT_NE(availableFormatsCount, formatIdx) + ASSERT_NE(availableFormats.count, formatIdx) << "No support found for format 0x" << std::hex << format; - uint32_t *availableSizesPerFormat; - size_t availableSizesPerFormatCount; + camera_metadata_entry_t availableSizesPerFormat; res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_SIZES_PER_FORMAT, - NULL, - (void**)&availableSizesPerFormat, - &availableSizesPerFormatCount); + &availableSizesPerFormat); ASSERT_EQ(OK, res); int size_offset = 0; for (unsigned int i=0; i < formatIdx; i++) { - size_offset += availableSizesPerFormat[i]; + size_offset += availableSizesPerFormat.data.i32[i]; } - uint32_t *availableSizes; - size_t availableSizesCount; + camera_metadata_entry_t availableSizes; res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_SIZES, - NULL, - (void**)&availableSizes, - &availableSizesCount); + &availableSizes); ASSERT_EQ(OK, res); - *list = availableSizes + size_offset; - *count = availableSizesPerFormat[formatIdx]; + *list = availableSizes.data.i32 + size_offset; + *count = availableSizesPerFormat.data.i32[formatIdx]; } virtual void SetUp() { @@ -349,14 +340,14 @@ TEST_F(Camera2Test, Capture1Raw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - uint32_t *rawResolutions; - size_t rawResolutionsCount; + int32_t *rawResolutions; + size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; getResolutionList(format, &rawResolutions, &rawResolutionsCount); - ASSERT_LT((uint32_t)0, rawResolutionsCount); + ASSERT_LT((size_t)0, rawResolutionsCount); // Pick first available raw resolution int width = rawResolutions[0]; @@ -379,7 +370,7 @@ TEST_F(Camera2Test, Capture1Raw) { ANDROID_REQUEST_OUTPUT_STREAMS, (void**)&outputStreams, 1); - uint64_t exposureTime = 2*MSEC; + uint64_t exposureTime = 10000*MSEC; add_camera_metadata_entry(request, ANDROID_SENSOR_EXPOSURE_TIME, (void**)&exposureTime, 1); @@ -392,7 +383,7 @@ TEST_F(Camera2Test, Capture1Raw) { ANDROID_SENSOR_SENSITIVITY, (void**)&sensitivity, 1); - uint32_t hourOfDay = 12; + uint32_t hourOfDay = 22; add_camera_metadata_entry(request, 0x80000000, // EMULATOR_HOUROFDAY &hourOfDay, 1); @@ -461,7 +452,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - uint32_t *rawResolutions; + int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -514,7 +505,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { // Enqueue numCaptures requests with increasing exposure time - uint64_t exposureTime = 1 * MSEC; + uint64_t exposureTime = 100 * USEC; for (int reqCount = 0; reqCount < numCaptures; reqCount++ ) { camera_metadata_t *req; req = allocate_camera_metadata(20, 2000); @@ -531,8 +522,9 @@ TEST_F(Camera2Test, CaptureBurstRaw) { } // Get frames and image buffers one by one + uint64_t expectedExposureTime = 100 * USEC; for (int frameCount = 0; frameCount < 10; frameCount++) { - res = mFrames.waitForBuffer(SEC); + res = mFrames.waitForBuffer(SEC + expectedExposureTime); ASSERT_EQ(NO_ERROR, res) << "No frame to get: " << strerror(-res); camera_metadata_t *frame; @@ -540,14 +532,14 @@ TEST_F(Camera2Test, CaptureBurstRaw) { ASSERT_EQ(NO_ERROR, res); ASSERT_TRUE(frame != NULL); - uint32_t *frameNumber; + camera_metadata_entry_t frameNumber; res = find_camera_metadata_entry(frame, ANDROID_REQUEST_FRAME_COUNT, - NULL, (void**)&frameNumber, NULL); + &frameNumber); ASSERT_EQ(NO_ERROR, res); - ASSERT_EQ(frameCount, *frameNumber); + ASSERT_EQ(frameCount, *frameNumber.data.i32); - res = rawWaiter->waitForFrame(SEC); + res = rawWaiter->waitForFrame(SEC + expectedExposureTime); ASSERT_EQ(NO_ERROR, res) << "Never got raw data for capture " << frameCount; @@ -558,7 +550,8 @@ TEST_F(Camera2Test, CaptureBurstRaw) { IF_ALOGV() { char dumpname[60]; snprintf(dumpname, 60, - "/data/local/tmp/camera2_test-capture1raw-dump_%d.raw", + "/data/local/tmp/camera2_test-" + "captureBurstRaw-dump_%d.raw", frameCount); ALOGV("Dumping raw buffer to %s", dumpname); // Write to file @@ -573,6 +566,8 @@ TEST_F(Camera2Test, CaptureBurstRaw) { res = rawConsumer->unlockBuffer(buffer); ASSERT_EQ(NO_ERROR, res); + + expectedExposureTime *= 2; } } } -- cgit v1.1 From 6adfd6b8ce32f042d001296f08e5b439af2635c1 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 14 May 2012 15:25:27 -0700 Subject: Camera2: Add test for construct_default_request. Bug: 6243944 Change-Id: I59b03d7ebece2a4b7672b265bd9f960b3faea621 --- include/hardware/camera2.h | 5 ++++- tests/camera2/camera2.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 7f06c52..0764cb1 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -400,7 +400,10 @@ enum { * full-resolution images without compromising preview frame rate. 3A on * auto. */ - CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG + CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG, + + /* Total number of templates */ + CAMERA2_TEMPLATE_COUNT }; diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index cc2face..6c22426 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -572,4 +572,34 @@ TEST_F(Camera2Test, CaptureBurstRaw) { } } +TEST_F(Camera2Test, ConstructDefaultRequests) { + status_t res; + + for (int id = 0; id < getNumCameras(); id++) { + if (!isHal2Supported(id)) continue; + + ASSERT_NO_FATAL_FAILURE(setUpCamera(id)); + + for (int i = CAMERA2_TEMPLATE_PREVIEW; i < CAMERA2_TEMPLATE_COUNT; + i++) { + camera_metadata_t *request = NULL; + res = mDevice->ops->construct_default_request(mDevice, + i, + &request); + EXPECT_EQ(NO_ERROR, res) << + "Unable to construct request from template type %d", i; + EXPECT_TRUE(request != NULL); + EXPECT_LT((size_t)0, get_camera_metadata_entry_count(request)); + EXPECT_LT((size_t)0, get_camera_metadata_data_count(request)); + + IF_ALOGV() { + std::cout << " ** Template type " << i << ":"< Date: Thu, 17 May 2012 17:54:56 -0700 Subject: I am a HAL of constant structure. Bug: 6243944 Change-Id: I126313f75f5f7165d3ca96f52054866c4fb6bee0 --- include/hardware/camera2.h | 62 ++++++++++++++++++++--------------------- tests/camera2/camera2_utils.cpp | 58 +++++++++++++++++++++++--------------- tests/camera2/camera2_utils.h | 31 +++++++++++---------- 3 files changed, 83 insertions(+), 68 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 0764cb1..d445a3b 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -64,7 +64,7 @@ typedef struct camera2_stream_ops { * will have been allocated based on the usage flags provided by * allocate_stream, and will be locked for use. */ - int (*dequeue_buffer)(struct camera2_stream_ops* w, + int (*dequeue_buffer)(const struct camera2_stream_ops* w, buffer_handle_t** buffer); /** @@ -79,19 +79,19 @@ typedef struct camera2_stream_ops { * same timestamp for that buffer, and that timestamp must match the * timestamp in the output frame metadata. */ - int (*enqueue_buffer)(struct camera2_stream_ops* w, + int (*enqueue_buffer)(const struct camera2_stream_ops* w, int64_t timestamp, buffer_handle_t* buffer); /** * Return a buffer to the queue without marking it as filled. */ - int (*cancel_buffer)(struct camera2_stream_ops* w, + int (*cancel_buffer)(const struct camera2_stream_ops* w, buffer_handle_t* buffer); /** * Set the crop window for subsequently enqueued buffers. The parameters are * measured in pixels relative to the buffer width and height. */ - int (*set_crop)(struct camera2_stream_ops *w, + int (*set_crop)(const struct camera2_stream_ops *w, int left, int top, int right, int bottom); } camera2_stream_ops_t; @@ -119,12 +119,12 @@ typedef struct camera2_stream_in_ops { * stride and other details should be queried from the platform gralloc * module as needed. The buffer will already be locked for use. */ - int (*acquire_buffer)(struct camera2_stream_in_ops *w, + int (*acquire_buffer)(const struct camera2_stream_in_ops *w, buffer_handle_t** buffer); /** * Return a used buffer to the buffer queue for reuse. */ - int (*release_buffer)(struct camera2_stream_in_ops *w, + int (*release_buffer)(const struct camera2_stream_in_ops *w, buffer_handle_t* buffer); } camera2_stream_in_ops_t; @@ -180,7 +180,7 @@ typedef struct camera2_request_queue_src_ops { * whether the notify_request_queue_not_empty() method will be called by the * framework. */ - int (*request_count)(struct camera2_request_queue_src_ops *q); + int (*request_count)(const struct camera2_request_queue_src_ops *q); /** * Get a metadata buffer from the framework. Returns OK if there is no @@ -189,13 +189,13 @@ typedef struct camera2_request_queue_src_ops { * attempting to dequeue again. Buffers obtained in this way must be * returned to the framework with free_request(). */ - int (*dequeue_request)(struct camera2_request_queue_src_ops *q, + int (*dequeue_request)(const struct camera2_request_queue_src_ops *q, camera_metadata_t **buffer); /** * Return a metadata buffer to the framework once it has been used, or if * an error or shutdown occurs. */ - int (*free_request)(struct camera2_request_queue_src_ops *q, + int (*free_request)(const struct camera2_request_queue_src_ops *q, camera_metadata_t *old_buffer); } camera2_request_queue_src_ops_t; @@ -222,7 +222,7 @@ typedef struct camera2_frame_queue_dst_ops { * data_bytes worth of extra storage. Frames dequeued here must be returned * to the framework with either cancel_frame or enqueue_frame. */ - int (*dequeue_frame)(struct camera2_frame_queue_dst_ops *q, + int (*dequeue_frame)(const struct camera2_frame_queue_dst_ops *q, size_t entries, size_t data_bytes, camera_metadata_t **buffer); @@ -230,13 +230,13 @@ typedef struct camera2_frame_queue_dst_ops { * Return a dequeued metadata buffer to the framework for reuse; do not mark it as * filled. Use when encountering errors, or flushing the internal request queue. */ - int (*cancel_frame)(struct camera2_frame_queue_dst_ops *q, + int (*cancel_frame)(const struct camera2_frame_queue_dst_ops *q, camera_metadata_t *buffer); /** * Place a completed metadata frame on the frame output queue. */ - int (*enqueue_frame)(struct camera2_frame_queue_dst_ops *q, + int (*enqueue_frame)(const struct camera2_frame_queue_dst_ops *q, camera_metadata_t *buffer); } camera2_frame_queue_dst_ops_t; @@ -421,21 +421,21 @@ typedef struct camera2_device_ops { /** * Pass in input request queue interface methods. */ - int (*set_request_queue_src_ops)(struct camera2_device *, - camera2_request_queue_src_ops_t *request_src_ops); + int (*set_request_queue_src_ops)(const struct camera2_device *, + const camera2_request_queue_src_ops_t *request_src_ops); /** * Notify device that the request queue is no longer empty. Must only be * called when the first buffer is added a new queue, or after the source * has returned NULL in response to a dequeue call. */ - int (*notify_request_queue_not_empty)(struct camera2_device *); + int (*notify_request_queue_not_empty)(const struct camera2_device *); /** * Pass in output frame queue interface methods */ - int (*set_frame_queue_dst_ops)(struct camera2_device *, - camera2_frame_queue_dst_ops_t *frame_dst_ops); + int (*set_frame_queue_dst_ops)(const struct camera2_device *, + const camera2_frame_queue_dst_ops_t *frame_dst_ops); /** * Number of camera requests being processed by the device at the moment @@ -443,7 +443,7 @@ typedef struct camera2_device_ops { * yet been enqueued onto output pipeline(s) ). No streams may be released * by the framework until the in-progress count is 0. */ - int (*get_in_progress_count)(struct camera2_device *); + int (*get_in_progress_count)(const struct camera2_device *); /** * Flush all in-progress captures. This includes all dequeued requests @@ -452,7 +452,7 @@ typedef struct camera2_device_ops { * normally. No new requests may be dequeued from the request queue until * the flush completes. */ - int (*flush_captures_in_progress)(struct camera2_device *); + int (*flush_captures_in_progress)(const struct camera2_device *); /** * Create a filled-in default request for standard camera use cases. @@ -465,7 +465,7 @@ typedef struct camera2_device_ops { * The metadata buffer returned must be allocated with * allocate_camera_metadata. The framework takes ownership of the buffer. */ - int (*construct_default_request)(struct camera2_device *, + int (*construct_default_request)(const struct camera2_device *, int request_template, camera_metadata_t **request); @@ -526,12 +526,12 @@ typedef struct camera2_device_ops { * */ int (*allocate_stream)( - struct camera2_device *, + const struct camera2_device *, // inputs uint32_t width, uint32_t height, int format, - camera2_stream_ops_t *stream_ops, + const camera2_stream_ops_t *stream_ops, // outputs uint32_t *stream_id, uint32_t *format_actual, @@ -548,7 +548,7 @@ typedef struct camera2_device_ops { * buffers must be ready to be returned to the queue. */ int (*register_stream_buffers)( - struct camera2_device *, + const struct camera2_device *, uint32_t stream_id, int num_buffers, buffer_handle_t *buffers); @@ -558,7 +558,7 @@ typedef struct camera2_device_ops { * is non-zero, or if the stream id is invalid. */ int (*release_stream)( - struct camera2_device *, + const struct camera2_device *, uint32_t stream_id); /** @@ -598,11 +598,11 @@ typedef struct camera2_device_ops { * acquired at the same time than this value. * */ - int (*allocate_reprocess_stream)(struct camera2_device *, + int (*allocate_reprocess_stream)(const struct camera2_device *, uint32_t width, uint32_t height, uint32_t format, - camera2_stream_in_ops_t *reprocess_stream_ops, + const camera2_stream_in_ops_t *reprocess_stream_ops, // outputs uint32_t *stream_id, uint32_t *consumer_usage, @@ -614,7 +614,7 @@ typedef struct camera2_device_ops { * valid. */ int (*release_reprocess_stream)( - struct camera2_device *, + const struct camera2_device *, uint32_t stream_id); /********************************************************************** @@ -627,7 +627,7 @@ typedef struct camera2_device_ops { * documentation for CAMERA2_TRIGGER_* above for details of the trigger ids * and their arguments. */ - int (*trigger_action)(struct camera2_device *, + int (*trigger_action)(const struct camera2_device *, uint32_t trigger_id, int ext1, int ext2); @@ -635,7 +635,7 @@ typedef struct camera2_device_ops { /** * Notification callback setup */ - int (*set_notify_callback)(struct camera2_device *, + int (*set_notify_callback)(const struct camera2_device *, camera2_notify_callback notify_cb, void *user); @@ -643,13 +643,13 @@ typedef struct camera2_device_ops { * Get methods to query for vendor extension metadata tag infomation. May * set ops to NULL if no vendor extension tags are defined. */ - int (*get_metadata_vendor_tag_ops)(struct camera2_device*, + int (*get_metadata_vendor_tag_ops)(const struct camera2_device*, vendor_tag_query_ops_t **ops); /** * Dump state of the camera hardware */ - int (*dump)(struct camera2_device *, int fd); + int (*dump)(const struct camera2_device *, int fd); } camera2_device_ops_t; diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp index bd56644..e3ea99f 100644 --- a/tests/camera2/camera2_utils.cpp +++ b/tests/camera2/camera2_utils.cpp @@ -50,7 +50,7 @@ MetadataQueue::~MetadataQueue() { } // Interface to camera2 HAL as consumer (input requests/reprocessing) -camera2_request_queue_src_ops_t* MetadataQueue::getToConsumerInterface() { +const camera2_request_queue_src_ops_t* MetadataQueue::getToConsumerInterface() { return static_cast(this); } @@ -58,7 +58,7 @@ void MetadataQueue::setFromConsumerInterface(camera2_device_t *d) { mDevice = d; } -camera2_frame_queue_dst_ops_t* MetadataQueue::getToProducerInterface() { +const camera2_frame_queue_dst_ops_t* MetadataQueue::getToProducerInterface() { return static_cast(this); } @@ -181,26 +181,38 @@ status_t MetadataQueue::freeBuffers(List::iterator start, return OK; } +MetadataQueue* MetadataQueue::getInstance( + const camera2_request_queue_src_ops_t *q) { + const MetadataQueue* cmq = static_cast(q); + return const_cast(cmq); +} + +MetadataQueue* MetadataQueue::getInstance( + const camera2_frame_queue_dst_ops_t *q) { + const MetadataQueue* cmq = static_cast(q); + return const_cast(cmq); +} + int MetadataQueue::consumer_buffer_count( - camera2_request_queue_src_ops_t *q) { - MetadataQueue *queue = static_cast(q); + const camera2_request_queue_src_ops_t *q) { + MetadataQueue *queue = getInstance(q); return queue->getBufferCount(); } -int MetadataQueue::consumer_dequeue(camera2_request_queue_src_ops_t *q, +int MetadataQueue::consumer_dequeue(const camera2_request_queue_src_ops_t *q, camera_metadata_t **buffer) { - MetadataQueue *queue = static_cast(q); + MetadataQueue *queue = getInstance(q); return queue->dequeue(buffer, true); } -int MetadataQueue::consumer_free(camera2_request_queue_src_ops_t *q, +int MetadataQueue::consumer_free(const camera2_request_queue_src_ops_t *q, camera_metadata_t *old_buffer) { - MetadataQueue *queue = static_cast(q); + MetadataQueue *queue = getInstance(q); free_camera_metadata(old_buffer); return OK; } -int MetadataQueue::producer_dequeue(camera2_frame_queue_dst_ops_t *q, +int MetadataQueue::producer_dequeue(const camera2_frame_queue_dst_ops_t *q, size_t entries, size_t bytes, camera_metadata_t **buffer) { camera_metadata_t *new_buffer = @@ -210,15 +222,15 @@ int MetadataQueue::producer_dequeue(camera2_frame_queue_dst_ops_t *q, return OK; } -int MetadataQueue::producer_cancel(camera2_frame_queue_dst_ops_t *q, +int MetadataQueue::producer_cancel(const camera2_frame_queue_dst_ops_t *q, camera_metadata_t *old_buffer) { free_camera_metadata(old_buffer); return OK; } -int MetadataQueue::producer_enqueue(camera2_frame_queue_dst_ops_t *q, +int MetadataQueue::producer_enqueue(const camera2_frame_queue_dst_ops_t *q, camera_metadata_t *filled_buffer) { - MetadataQueue *queue = static_cast(q); + MetadataQueue *queue = getInstance(q); return queue->enqueue(filled_buffer); } @@ -486,18 +498,18 @@ int StreamAdapter::getId() { return mId; } -camera2_stream_ops *StreamAdapter::getStreamOps() { +const camera2_stream_ops *StreamAdapter::getStreamOps() { return static_cast(this); } -ANativeWindow* StreamAdapter::toANW(camera2_stream_ops_t *w) { - return static_cast(w)->mConsumerInterface.get(); +ANativeWindow* StreamAdapter::toANW(const camera2_stream_ops_t *w) { + return static_cast(w)->mConsumerInterface.get(); } -int StreamAdapter::dequeue_buffer(camera2_stream_ops_t *w, +int StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w, buffer_handle_t** buffer) { int res; - int state = static_cast(w)->mState; + int state = static_cast(w)->mState; if (state != ACTIVE) { ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); return INVALID_OPERATION; @@ -515,10 +527,10 @@ int StreamAdapter::dequeue_buffer(camera2_stream_ops_t *w, return res; } -int StreamAdapter::enqueue_buffer(camera2_stream_ops_t* w, +int StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w, int64_t timestamp, buffer_handle_t* buffer) { - int state = static_cast(w)->mState; + int state = static_cast(w)->mState; if (state != ACTIVE) { ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); return INVALID_OPERATION; @@ -531,9 +543,9 @@ int StreamAdapter::enqueue_buffer(camera2_stream_ops_t* w, container_of(buffer, ANativeWindowBuffer, handle)); } -int StreamAdapter::cancel_buffer(camera2_stream_ops_t* w, +int StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w, buffer_handle_t* buffer) { - int state = static_cast(w)->mState; + int state = static_cast(w)->mState; if (state != ACTIVE) { ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); return INVALID_OPERATION; @@ -543,9 +555,9 @@ int StreamAdapter::cancel_buffer(camera2_stream_ops_t* w, container_of(buffer, ANativeWindowBuffer, handle)); } -int StreamAdapter::set_crop(camera2_stream_ops_t* w, +int StreamAdapter::set_crop(const camera2_stream_ops_t* w, int left, int top, int right, int bottom) { - int state = static_cast(w)->mState; + int state = static_cast(w)->mState; if (state != ACTIVE) { ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); return INVALID_OPERATION; diff --git a/tests/camera2/camera2_utils.h b/tests/camera2/camera2_utils.h index 4e0b521..2c9f801 100644 --- a/tests/camera2/camera2_utils.h +++ b/tests/camera2/camera2_utils.h @@ -40,10 +40,10 @@ class MetadataQueue: public camera2_request_queue_src_ops_t, // Interface to camera2 HAL device, either for requests (device is consumer) // or for frames (device is producer) - camera2_request_queue_src_ops_t* getToConsumerInterface(); + const camera2_request_queue_src_ops_t* getToConsumerInterface(); void setFromConsumerInterface(camera2_device_t *d); - camera2_frame_queue_dst_ops_t* getToProducerInterface(); + const camera2_frame_queue_dst_ops_t* getToProducerInterface(); // Real interfaces. On enqueue, queue takes ownership of buffer pointer // On dequeue, user takes ownership of buffer pointer. @@ -76,22 +76,25 @@ class MetadataQueue: public camera2_request_queue_src_ops_t, bool mSignalConsumer; - static int consumer_buffer_count(camera2_request_queue_src_ops_t *q); + static MetadataQueue* getInstance(const camera2_frame_queue_dst_ops_t *q); + static MetadataQueue* getInstance(const camera2_request_queue_src_ops_t *q); - static int consumer_dequeue(camera2_request_queue_src_ops_t *q, + static int consumer_buffer_count(const camera2_request_queue_src_ops_t *q); + + static int consumer_dequeue(const camera2_request_queue_src_ops_t *q, camera_metadata_t **buffer); - static int consumer_free(camera2_request_queue_src_ops_t *q, + static int consumer_free(const camera2_request_queue_src_ops_t *q, camera_metadata_t *old_buffer); - static int producer_dequeue(camera2_frame_queue_dst_ops_t *q, + static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q, size_t entries, size_t bytes, camera_metadata_t **buffer); - static int producer_cancel(camera2_frame_queue_dst_ops_t *q, + static int producer_cancel(const camera2_frame_queue_dst_ops_t *q, camera_metadata_t *old_buffer); - static int producer_enqueue(camera2_frame_queue_dst_ops_t *q, + static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q, camera_metadata_t *filled_buffer); }; @@ -193,21 +196,21 @@ class StreamAdapter: public camera2_stream_ops { int mFormatRequested; - camera2_stream_ops *getStreamOps(); + const camera2_stream_ops *getStreamOps(); - static ANativeWindow* toANW(camera2_stream_ops_t *w); + static ANativeWindow* toANW(const camera2_stream_ops_t *w); - static int dequeue_buffer(camera2_stream_ops_t *w, + static int dequeue_buffer(const camera2_stream_ops_t *w, buffer_handle_t** buffer); - static int enqueue_buffer(camera2_stream_ops_t* w, + static int enqueue_buffer(const camera2_stream_ops_t* w, int64_t timestamp, buffer_handle_t* buffer); - static int cancel_buffer(camera2_stream_ops_t* w, + static int cancel_buffer(const camera2_stream_ops_t* w, buffer_handle_t* buffer); - static int set_crop(camera2_stream_ops_t* w, + static int set_crop(const camera2_stream_ops_t* w, int left, int top, int right, int bottom); }; -- cgit v1.1 From 895ed341ba7e956eed1d81a75366597fa89d3081 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Sun, 20 May 2012 17:25:53 -0700 Subject: Camera2: Update test code for metadata changes - New resolution handling - Don't do long exposures in tests Bug: 6243944 Change-Id: Ia8362a50c8c4a2230d892e571b31e513c67ab84d --- tests/camera2/camera2.cpp | 56 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 6c22426..d4243ab 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -239,38 +239,36 @@ class Camera2Test: public testing::Test { size_t *count) { status_t res; - camera_metadata_entry_t availableFormats; - res = find_camera_metadata_entry(mStaticInfo, - ANDROID_SCALER_AVAILABLE_FORMATS, - &availableFormats); - ASSERT_EQ(OK, res); - - uint32_t formatIdx; - for (formatIdx=0; formatIdx < availableFormats.count; formatIdx++) { - if (availableFormats.data.i32[formatIdx] == format) break; - } - ASSERT_NE(availableFormats.count, formatIdx) + if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { + camera_metadata_entry_t availableFormats; + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_FORMATS, + &availableFormats); + ASSERT_EQ(OK, res); + + uint32_t formatIdx; + for (formatIdx=0; formatIdx < availableFormats.count; formatIdx++) { + if (availableFormats.data.i32[formatIdx] == format) break; + } + ASSERT_NE(availableFormats.count, formatIdx) << "No support found for format 0x" << std::hex << format; - - camera_metadata_entry_t availableSizesPerFormat; - res = find_camera_metadata_entry(mStaticInfo, - ANDROID_SCALER_AVAILABLE_SIZES_PER_FORMAT, - &availableSizesPerFormat); - ASSERT_EQ(OK, res); - - int size_offset = 0; - for (unsigned int i=0; i < formatIdx; i++) { - size_offset += availableSizesPerFormat.data.i32[i]; } camera_metadata_entry_t availableSizes; - res = find_camera_metadata_entry(mStaticInfo, - ANDROID_SCALER_AVAILABLE_SIZES, - &availableSizes); - ASSERT_EQ(OK, res); + if (format == HAL_PIXEL_FORMAT_RAW_SENSOR) { + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_RAW_SIZES, + &availableSizes); + ASSERT_EQ(OK, res); + } else { + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, + &availableSizes); + ASSERT_EQ(OK, res); + } - *list = availableSizes.data.i32 + size_offset; - *count = availableSizesPerFormat.data.i32[formatIdx]; + *list = availableSizes.data.i32; + *count = availableSizes.count; } virtual void SetUp() { @@ -370,7 +368,7 @@ TEST_F(Camera2Test, Capture1Raw) { ANDROID_REQUEST_OUTPUT_STREAMS, (void**)&outputStreams, 1); - uint64_t exposureTime = 10000*MSEC; + uint64_t exposureTime = 10*MSEC; add_camera_metadata_entry(request, ANDROID_SENSOR_EXPOSURE_TIME, (void**)&exposureTime, 1); @@ -383,7 +381,7 @@ TEST_F(Camera2Test, Capture1Raw) { ANDROID_SENSOR_SENSITIVITY, (void**)&sensitivity, 1); - uint32_t hourOfDay = 22; + uint32_t hourOfDay = 12; add_camera_metadata_entry(request, 0x80000000, // EMULATOR_HOUROFDAY &hourOfDay, 1); -- cgit v1.1 From fa7a91d3d2a7f99612446f61beb29cc9e215d0ba Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 22 May 2012 10:41:20 -0700 Subject: Camera2: Add JPEG capture test. Bug: 6243944 Change-Id: Ifdf16f34b13df1e5bfe501eb7e6083862c71240a --- include/hardware/camera2.h | 6 +-- tests/camera2/Android.mk | 3 +- tests/camera2/camera2.cpp | 131 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index d445a3b..f3e4ba4 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -109,8 +109,8 @@ enum { /** * Input reprocess stream queue management. A set of these methods is provided - * to the HAL device in allocate_reprocess_stream(); they are used to interact with the - * reprocess stream's input gralloc buffer queue. + * to the HAL device in allocate_reprocess_stream(); they are used to interact + * with the reprocess stream's input gralloc buffer queue. */ typedef struct camera2_stream_in_ops { /** @@ -460,7 +460,7 @@ typedef struct camera2_device_ops { * The device must return a complete request that is configured to meet the * requested use case, which must be one of the CAMERA2_TEMPLATE_* * enums. All request control fields must be included, except for - * android.request.outputStreams and android.request.frameNumber. + * android.request.outputStreams. * * The metadata buffer returned must be allocated with * allocate_camera_metadata. The framework takes ownership of the buffer. diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk index 325e82d..38d287e 100644 --- a/tests/camera2/Android.mk +++ b/tests/camera2/Android.mk @@ -10,7 +10,8 @@ LOCAL_SHARED_LIBRARIES := \ libstlport \ libhardware \ libcamera_metadata \ - libgui + libgui \ + libui LOCAL_STATIC_LIBRARIES := \ libgtest \ diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index d4243ab..8a0e842 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "camera2_utils.h" @@ -237,7 +238,7 @@ class Camera2Test: public testing::Test { void getResolutionList(int32_t format, int32_t **list, size_t *count) { - + ALOGV("Getting resolutions for format %x", format); status_t res; if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { camera_metadata_entry_t availableFormats; @@ -259,13 +260,16 @@ class Camera2Test: public testing::Test { res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_RAW_SIZES, &availableSizes); - ASSERT_EQ(OK, res); + } else if (format == HAL_PIXEL_FORMAT_BLOB) { + res = find_camera_metadata_entry(mStaticInfo, + ANDROID_SCALER_AVAILABLE_JPEG_SIZES, + &availableSizes); } else { res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, &availableSizes); - ASSERT_EQ(OK, res); } + ASSERT_EQ(OK, res); *list = availableSizes.data.i32; *count = availableSizes.count; @@ -420,9 +424,11 @@ TEST_F(Camera2Test, Capture1Raw) { ALOGV("Dumping raw buffer to %s", dumpname); // Write to file std::ofstream rawFile(dumpname); + size_t bpp = 2; for (unsigned int y = 0; y < buffer.height; y++) { - rawFile.write((const char *)(buffer.data + y * buffer.stride * 2), - buffer.width * 2); + rawFile.write( + (const char *)(buffer.data + y * buffer.stride * bpp), + buffer.width * bpp); } rawFile.close(); } @@ -600,4 +606,119 @@ TEST_F(Camera2Test, ConstructDefaultRequests) { } } +TEST_F(Camera2Test, Capture1Jpeg) { + status_t res; + + for (int id = 0; id < getNumCameras(); id++) { + if (!isHal2Supported(id)) continue; + + ASSERT_NO_FATAL_FAILURE(setUpCamera(id)); + + sp jpegConsumer = new CpuConsumer(1); + sp jpegWaiter = new FrameWaiter(); + jpegConsumer->setFrameAvailableListener(jpegWaiter); + + int32_t *jpegResolutions; + size_t jpegResolutionsCount; + + int format = HAL_PIXEL_FORMAT_BLOB; + + getResolutionList(format, + &jpegResolutions, &jpegResolutionsCount); + ASSERT_LT((size_t)0, jpegResolutionsCount); + + // Pick first available JPEG resolution + int width = jpegResolutions[0]; + int height = jpegResolutions[1]; + + int streamId; + ASSERT_NO_FATAL_FAILURE( + setUpStream(jpegConsumer->getProducerInterface(), + width, height, format, &streamId) ); + + camera_metadata_t *request; + request = allocate_camera_metadata(20, 2000); + + uint8_t metadataMode = ANDROID_REQUEST_METADATA_FULL; + add_camera_metadata_entry(request, + ANDROID_REQUEST_METADATA_MODE, + (void**)&metadataMode, 1); + uint32_t outputStreams = streamId; + add_camera_metadata_entry(request, + ANDROID_REQUEST_OUTPUT_STREAMS, + (void**)&outputStreams, 1); + + uint64_t exposureTime = 10*MSEC; + add_camera_metadata_entry(request, + ANDROID_SENSOR_EXPOSURE_TIME, + (void**)&exposureTime, 1); + uint64_t frameDuration = 30*MSEC; + add_camera_metadata_entry(request, + ANDROID_SENSOR_FRAME_DURATION, + (void**)&frameDuration, 1); + uint32_t sensitivity = 100; + add_camera_metadata_entry(request, + ANDROID_SENSOR_SENSITIVITY, + (void**)&sensitivity, 1); + + uint32_t hourOfDay = 12; + add_camera_metadata_entry(request, + 0x80000000, // EMULATOR_HOUROFDAY + &hourOfDay, 1); + + IF_ALOGV() { + std::cout << "Input request: " << std::endl; + dump_camera_metadata(request, 0, 1); + } + + res = mRequests.enqueue(request); + ASSERT_EQ(NO_ERROR, res) << "Can't enqueue request: " << strerror(-res); + + res = mFrames.waitForBuffer(exposureTime + SEC); + ASSERT_EQ(NO_ERROR, res) << "No frame to get: " << strerror(-res); + + camera_metadata_t *frame; + res = mFrames.dequeue(&frame); + ASSERT_EQ(NO_ERROR, res); + ASSERT_TRUE(frame != NULL); + + IF_ALOGV() { + std::cout << "Output frame:" << std::endl; + dump_camera_metadata(frame, 0, 1); + } + + res = jpegWaiter->waitForFrame(exposureTime + SEC); + ASSERT_EQ(NO_ERROR, res); + + CpuConsumer::LockedBuffer buffer; + res = jpegConsumer->lockNextBuffer(&buffer); + ASSERT_EQ(NO_ERROR, res); + + IF_ALOGV() { + const char *dumpname = + "/data/local/tmp/camera2_test-capture1jpeg-dump.jpeg"; + ALOGV("Dumping raw buffer to %s", dumpname); + // Write to file + std::ofstream jpegFile(dumpname); + size_t bpp = 1; + for (unsigned int y = 0; y < buffer.height; y++) { + jpegFile.write( + (const char *)(buffer.data + y * buffer.stride * bpp), + buffer.width * bpp); + } + jpegFile.close(); + } + + res = jpegConsumer->unlockBuffer(buffer); + ASSERT_EQ(NO_ERROR, res); + + ASSERT_NO_FATAL_FAILURE(disconnectStream(streamId)); + + res = closeCameraDevice(mDevice); + ASSERT_EQ(NO_ERROR, res) << "Failed to close camera device"; + + } +} + + } // namespace android -- cgit v1.1 From d479ad22a0254fa0b5358fe82fa404e3e96c631a Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 5 Jun 2012 23:41:37 -0700 Subject: Introduce HWC_DEVICE_API_VERSION_1_0 The new version adds an acquire and release fence to each layer, providing explicit producer->hwc and hwc->producer synchronization. Change-Id: Ibd6e3c7b3515c012c767246e6d6514274fdef01d --- include/hardware/hwcomposer.h | 122 +++++++++++------ include/hardware/hwcomposer_defs.h | 2 +- include/hardware/hwcomposer_v0.h | 272 +++++++++++++++++++++++++++++++++++++ modules/hwcomposer/hwcomposer.cpp | 12 +- 4 files changed, 359 insertions(+), 49 deletions(-) create mode 100644 include/hardware/hwcomposer_v0.h diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 98e665c..4af5c69 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -30,11 +30,25 @@ __BEGIN_DECLS /*****************************************************************************/ -// for compatibility +/* for compatibility */ #define HWC_MODULE_API_VERSION HWC_MODULE_API_VERSION_0_1 #define HWC_DEVICE_API_VERSION HWC_DEVICE_API_VERSION_0_1 #define HWC_API_VERSION HWC_DEVICE_API_VERSION +/* Users of this header can define HWC_REMOVE_DEPRECATED_VERSIONS to test that + * they still work with just the current version declared, before the + * deprecated versions are actually removed. + * + * To find code that still depends on the old versions, set the #define to 1 + * here. Code that explicitly sets it to zero (rather than simply not defining + * it) will still see the old versions. + */ +#if !defined(HWC_REMOVE_DEPRECATED_VERSIONS) +#define HWC_REMOVE_DEPRECATED_VERSIONS 0 +#endif + +/*****************************************************************************/ + /** * The id of this module */ @@ -45,21 +59,8 @@ __BEGIN_DECLS */ #define HWC_HARDWARE_COMPOSER "composer" - -struct hwc_composer_device; - -/* - * availability: HWC_DEVICE_API_VERSION_0_3 - * - * struct hwc_methods cannot be embedded in other structures as - * sizeof(struct hwc_methods) cannot be relied upon. - * - */ -typedef struct hwc_methods { - - /************************************************************************* - * HWC_DEVICE_API_VERSION_0_3 - *************************************************************************/ +struct hwc_composer_device_1; +typedef struct hwc_methods_1 { /* * eventControl(..., event, enabled) @@ -76,9 +77,9 @@ typedef struct hwc_methods { */ int (*eventControl)( - struct hwc_composer_device* dev, int event, int enabled); + struct hwc_composer_device_1* dev, int event, int enabled); -} hwc_methods_t; +} hwc_methods_1_t; typedef struct hwc_rect { int left; @@ -99,7 +100,7 @@ typedef struct hwc_color { uint8_t a; } hwc_color_t; -typedef struct hwc_layer { +typedef struct hwc_layer_1 { /* * initially set to HWC_FRAMEBUFFER or HWC_BACKGROUND. * HWC_FRAMEBUFFER @@ -158,10 +159,46 @@ typedef struct hwc_layer { * The visible region INCLUDES areas overlapped by a translucent layer. */ hwc_region_t visibleRegionScreen; + + /* Sync fence object that will be signaled when the buffer's + * contents are available. May be -1 if the contents are already + * available. This field is only valid during set(), and should be + * ignored during prepare(). The set() call must not wait for the + * fence to be signaled before returning, but the HWC must wait for + * all buffers to be signaled before reading from them. + * + * The HWC takes ownership of the acquireFenceFd and is responsible + * for closing it when no longer needed. + */ + int acquireFenceFd; + + /* During set() the HWC must set this field to a file descriptor for + * a sync fence object that will signal after the HWC has finished + * reading from the buffer. The field is ignored by prepare(). Each + * layer should have a unique file descriptor, even if more than one + * refer to the same underlying fence object; this allows each to be + * closed independently. + * + * If buffer reads can complete at significantly different times, + * then using independent fences is preferred. For example, if the + * HWC handles some layers with a blit engine and others with + * overlays, then the blit layers can be reused immediately after + * the blit completes, but the overlay layers can't be reused until + * a subsequent frame has been displayed. + * + * The HWC client taks ownership of the releaseFenceFd and is + * responsible for closing it when no longer needed. + */ + int releaseFenceFd; }; }; -} hwc_layer_t; + /* Allow for expansion w/o breaking binary compatibility. + * Pad layer to 96 bytes, assuming 32-bit pointers. + */ + int32_t reserved[24 - 18]; + +} hwc_layer_1_t; /* * hwc_layer_list_t::flags values @@ -169,7 +206,8 @@ typedef struct hwc_layer { enum { /* * HWC_GEOMETRY_CHANGED is set by SurfaceFlinger to indicate that the list - * passed to (*prepare)() has changed by more than just the buffer handles. + * passed to (*prepare)() has changed by more than just the buffer handles + * and acquire fences. */ HWC_GEOMETRY_CHANGED = 0x00000001, }; @@ -178,11 +216,11 @@ enum { * List of layers. * The handle members of hwLayers elements must be unique. */ -typedef struct hwc_layer_list { +typedef struct hwc_layer_list_1 { uint32_t flags; size_t numHwLayers; - hwc_layer_t hwLayers[0]; -} hwc_layer_list_t; + hwc_layer_1_t hwLayers[0]; +} hwc_layer_list_1_t; /* This represents a display, typically an EGLDisplay object */ typedef void* hwc_display_t; @@ -237,8 +275,7 @@ typedef struct hwc_module { struct hw_module_t common; } hwc_module_t; - -typedef struct hwc_composer_device { +typedef struct hwc_composer_device_1 { struct hw_device_t common; /* @@ -264,8 +301,8 @@ typedef struct hwc_composer_device { * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. */ - int (*prepare)(struct hwc_composer_device *dev, hwc_layer_list_t* list); - + int (*prepare)(struct hwc_composer_device_1 *dev, + hwc_layer_list_1_t* list); /* * (*set)() is used in place of eglSwapBuffers(), and assumes the same @@ -309,16 +346,17 @@ typedef struct hwc_composer_device { * Another code for non EGL errors. * */ - int (*set)(struct hwc_composer_device *dev, + int (*set)(struct hwc_composer_device_1 *dev, hwc_display_t dpy, hwc_surface_t sur, - hwc_layer_list_t* list); + hwc_layer_list_1_t* list); + /* * This field is OPTIONAL and can be NULL. * * If non NULL it will be called by SurfaceFlinger on dumpsys */ - void (*dump)(struct hwc_composer_device* dev, char *buff, int buff_len); + void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len); /* * This field is OPTIONAL and can be NULL. @@ -333,18 +371,17 @@ typedef struct hwc_composer_device { * Any of the callbacks can be NULL, in which case the corresponding * functionality is not supported. */ - void (*registerProcs)(struct hwc_composer_device* dev, + void (*registerProcs)(struct hwc_composer_device_1* dev, hwc_procs_t const* procs); /* * This field is OPTIONAL and can be NULL. - * availability: HWC_DEVICE_API_VERSION_0_2 * * Used to retrieve information about the h/w composer * * Returns 0 on success or -errno on error. */ - int (*query)(struct hwc_composer_device* dev, int what, int* value); + int (*query)(struct hwc_composer_device_1* dev, int what, int* value); /* * Reserved for future use. Must be NULL. @@ -353,28 +390,29 @@ typedef struct hwc_composer_device { /* * This field is OPTIONAL and can be NULL. - * availability: HWC_DEVICE_API_VERSION_0_3 */ - hwc_methods_t const *methods; - -} hwc_composer_device_t; + hwc_methods_1_t const *methods; +} hwc_composer_device_1_t; /** convenience API for opening and closing a device */ -static inline int hwc_open(const struct hw_module_t* module, - hwc_composer_device_t** device) { +static inline int hwc_open_1(const struct hw_module_t* module, + hwc_composer_device_1_t** device) { return module->methods->open(module, HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device); } -static inline int hwc_close(hwc_composer_device_t* device) { +static inline int hwc_close_1(hwc_composer_device_1_t* device) { return device->common.close(&device->common); } - /*****************************************************************************/ +#if !HWC_REMOVE_DEPRECATED_VERSIONS +#include +#endif + __END_DECLS #endif /* ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H */ diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index 99465d3..02b8e50 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -33,7 +33,7 @@ __BEGIN_DECLS #define HWC_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION(0, 1) #define HWC_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION(0, 2) #define HWC_DEVICE_API_VERSION_0_3 HARDWARE_DEVICE_API_VERSION(0, 3) - +#define HWC_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0) enum { /* hwc_composer_device_t::set failed in EGL */ diff --git a/include/hardware/hwcomposer_v0.h b/include/hardware/hwcomposer_v0.h new file mode 100644 index 0000000..473819b --- /dev/null +++ b/include/hardware/hwcomposer_v0.h @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + +/* This header contains deprecated HWCv0 interface declarations. Don't include + * this header directly; it will be included by unless + * HWC_REMOVE_DEPRECATED_VERSIONS is defined to non-zero. + */ +#ifndef ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H +#error "This header should only be included by hardware/hwcomposer.h" +#endif + +#ifndef ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_V0_H +#define ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_V0_H + +struct hwc_composer_device; + +/* + * availability: HWC_DEVICE_API_VERSION_0_3 + * + * struct hwc_methods cannot be embedded in other structures as + * sizeof(struct hwc_methods) cannot be relied upon. + * + */ +typedef struct hwc_methods { + + /************************************************************************* + * HWC_DEVICE_API_VERSION_0_3 + *************************************************************************/ + + /* + * eventControl(..., event, enabled) + * Enables or disables h/w composer events. + * + * eventControl can be called from any thread and takes effect + * immediately. + * + * Supported events are: + * HWC_EVENT_VSYNC + * + * returns -EINVAL if the "event" parameter is not one of the value above + * or if the "enabled" parameter is not 0 or 1. + */ + + int (*eventControl)( + struct hwc_composer_device* dev, int event, int enabled); + +} hwc_methods_t; + +typedef struct hwc_layer { + /* + * initially set to HWC_FRAMEBUFFER or HWC_BACKGROUND. + * HWC_FRAMEBUFFER + * indicates the layer will be drawn into the framebuffer + * using OpenGL ES. + * The HWC can toggle this value to HWC_OVERLAY, to indicate + * it will handle the layer. + * + * HWC_BACKGROUND + * indicates this is a special "background" layer. The only valid + * field is backgroundColor. HWC_BACKGROUND can only be used with + * HWC_API_VERSION >= 0.2 + * The HWC can toggle this value to HWC_FRAMEBUFFER, to indicate + * it CANNOT handle the background color + * + */ + int32_t compositionType; + + /* see hwc_layer_t::hints above */ + uint32_t hints; + + /* see hwc_layer_t::flags above */ + uint32_t flags; + + union { + /* color of the background. hwc_color_t.a is ignored */ + hwc_color_t backgroundColor; + + struct { + /* handle of buffer to compose. This handle is guaranteed to have been + * allocated from gralloc using the GRALLOC_USAGE_HW_COMPOSER usage flag. If + * the layer's handle is unchanged across two consecutive prepare calls and + * the HWC_GEOMETRY_CHANGED flag is not set for the second call then the + * HWComposer implementation may assume that the contents of the buffer have + * not changed. */ + buffer_handle_t handle; + + /* transformation to apply to the buffer during composition */ + uint32_t transform; + + /* blending to apply during composition */ + int32_t blending; + + /* area of the source to consider, the origin is the top-left corner of + * the buffer */ + hwc_rect_t sourceCrop; + + /* where to composite the sourceCrop onto the display. The sourceCrop + * is scaled using linear filtering to the displayFrame. The origin is the + * top-left corner of the screen. + */ + hwc_rect_t displayFrame; + + /* visible region in screen space. The origin is the + * top-left corner of the screen. + * The visible region INCLUDES areas overlapped by a translucent layer. + */ + hwc_region_t visibleRegionScreen; + }; + }; +} hwc_layer_t; + +/* + * List of layers. + * The handle members of hwLayers elements must be unique. + */ +typedef struct hwc_layer_list { + uint32_t flags; + size_t numHwLayers; + hwc_layer_t hwLayers[0]; +} hwc_layer_list_t; + +/*****************************************************************************/ + +typedef struct hwc_composer_device { + struct hw_device_t common; + + /* + * (*prepare)() is called for each frame before composition and is used by + * SurfaceFlinger to determine what composition steps the HWC can handle. + * + * (*prepare)() can be called more than once, the last call prevails. + * + * The HWC responds by setting the compositionType field to either + * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for + * this layer is handled by SurfaceFlinger with OpenGL ES, in the later + * case, the HWC will have to handle this layer's composition. + * + * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the + * list's geometry has changed, that is, when more than just the buffer's + * handles have been updated. Typically this happens (but is not limited to) + * when a window is added, removed, resized or moved. + * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition will be handled by SurfaceFlinger with OpenGL ES. + * + * returns: 0 on success. An negative error code on error. If an error is + * returned, SurfaceFlinger will assume that none of the layer will be + * handled by the HWC. + */ + int (*prepare)(struct hwc_composer_device *dev, hwc_layer_list_t* list); + + /* + * (*set)() is used in place of eglSwapBuffers(), and assumes the same + * functionality, except it also commits the work list atomically with + * the actual eglSwapBuffers(). + * + * The list parameter is guaranteed to be the same as the one returned + * from the last call to (*prepare)(). + * + * When this call returns the caller assumes that: + * + * - the display will be updated in the near future with the content + * of the work list, without artifacts during the transition from the + * previous frame. + * + * - all objects are available for immediate access or destruction, in + * particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer. + * Note that this means that immediately accessing (potentially from a + * different process) a buffer used in this call will not result in + * screen corruption, the driver must apply proper synchronization or + * scheduling (eg: block the caller, such as gralloc_module_t::lock(), + * OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work + * after the buffer is freed from the actual composition). + * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition has been handled by SurfaceFlinger with OpenGL ES. + * In this case, (*set)() behaves just like eglSwapBuffers(). + * + * dpy, sur, and list are set to NULL to indicate that the screen is + * turning off. This happens WITHOUT prepare() being called first. + * This is a good time to free h/w resources and/or power + * the relevant h/w blocks down. + * + * IMPORTANT NOTE: there is an implicit layer containing opaque black + * pixels behind all the layers in the list. + * It is the responsibility of the hwcomposer module to make + * sure black pixels are output (or blended from). + * + * returns: 0 on success. An negative error code on error: + * HWC_EGL_ERROR: eglGetError() will provide the proper error code + * Another code for non EGL errors. + * + */ + int (*set)(struct hwc_composer_device *dev, + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_t* list); + + /* + * This field is OPTIONAL and can be NULL. + * + * If non NULL it will be called by SurfaceFlinger on dumpsys + */ + void (*dump)(struct hwc_composer_device* dev, char *buff, int buff_len); + + /* + * This field is OPTIONAL and can be NULL. + * + * (*registerProcs)() registers a set of callbacks the h/w composer HAL + * can later use. It is FORBIDDEN to call any of the callbacks from + * within registerProcs(). registerProcs() must save the hwc_procs_t pointer + * which is needed when calling a registered callback. + * Each call to registerProcs replaces the previous set of callbacks. + * registerProcs is called with NULL to unregister all callbacks. + * + * Any of the callbacks can be NULL, in which case the corresponding + * functionality is not supported. + */ + void (*registerProcs)(struct hwc_composer_device* dev, + hwc_procs_t const* procs); + + /* + * This field is OPTIONAL and can be NULL. + * availability: HWC_DEVICE_API_VERSION_0_2 + * + * Used to retrieve information about the h/w composer + * + * Returns 0 on success or -errno on error. + */ + int (*query)(struct hwc_composer_device* dev, int what, int* value); + + /* + * Reserved for future use. Must be NULL. + */ + void* reserved_proc[4]; + + /* + * This field is OPTIONAL and can be NULL. + * availability: HWC_DEVICE_API_VERSION_0_3 + */ + hwc_methods_t const *methods; + +} hwc_composer_device_t; + +/** convenience API for opening and closing a device */ + +static inline int hwc_open(const struct hw_module_t* module, + hwc_composer_device_t** device) { + return module->methods->open(module, + HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device); +} + +static inline int hwc_close(hwc_composer_device_t* device) { + return device->common.close(&device->common); +} + +/*****************************************************************************/ + +#endif /* ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_V0_H */ diff --git a/modules/hwcomposer/hwcomposer.cpp b/modules/hwcomposer/hwcomposer.cpp index 0e04cac..0e49e4c 100644 --- a/modules/hwcomposer/hwcomposer.cpp +++ b/modules/hwcomposer/hwcomposer.cpp @@ -29,7 +29,7 @@ /*****************************************************************************/ struct hwc_context_t { - hwc_composer_device_t device; + hwc_composer_device_1_t device; /* our private state goes below here */ }; @@ -54,7 +54,7 @@ hwc_module_t HAL_MODULE_INFO_SYM = { /*****************************************************************************/ -static void dump_layer(hwc_layer_t const* l) { +static void dump_layer(hwc_layer_1_t const* l) { ALOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", l->compositionType, l->flags, l->handle, l->transform, l->blending, l->sourceCrop.left, @@ -67,7 +67,7 @@ static void dump_layer(hwc_layer_t const* l) { l->displayFrame.bottom); } -static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { +static int hwc_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) { if (list && (list->flags & HWC_GEOMETRY_CHANGED)) { for (size_t i=0 ; inumHwLayers ; i++) { //dump_layer(&list->hwLayers[i]); @@ -77,10 +77,10 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { return 0; } -static int hwc_set(hwc_composer_device_t *dev, +static int hwc_set(hwc_composer_device_1_t *dev, hwc_display_t dpy, hwc_surface_t sur, - hwc_layer_list_t* list) + hwc_layer_list_1_t* list) { //for (size_t i=0 ; inumHwLayers ; i++) { // dump_layer(&list->hwLayers[i]); @@ -117,7 +117,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, /* initialize the procs */ dev->device.common.tag = HARDWARE_DEVICE_TAG; - dev->device.common.version = 0; + dev->device.common.version = HWC_DEVICE_API_VERSION_1_0; dev->device.common.module = const_cast(module); dev->device.common.close = hwc_device_close; -- cgit v1.1 From bd85f47ae7b6b2af30cf9d51d7039fbba5a271ed Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Wed, 13 Jun 2012 16:36:01 -0700 Subject: Update ANativeWindow clients for sync This change updates uses of ANativeWindow to use the new ANW functions that accept and return Sync HAL fence file descriptors. Change-Id: I8ea699ba0a9b5c4b4316f9428cbd565976899991 --- tests/camera2/Android.mk | 1 + tests/camera2/camera2_utils.cpp | 23 +++++------------------ 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk index 38d287e..c378e12 100644 --- a/tests/camera2/Android.mk +++ b/tests/camera2/Android.mk @@ -11,6 +11,7 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libcamera_metadata \ libgui \ + libsync \ libui LOCAL_STATIC_LIBRARIES := \ diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp index e3ea99f..ba938d9 100644 --- a/tests/camera2/camera2_utils.cpp +++ b/tests/camera2/camera2_utils.cpp @@ -425,7 +425,7 @@ status_t StreamAdapter::connectToDevice(camera2_device_t *d, ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[totalBuffers]; int bufferIdx = 0; for (; bufferIdx < totalBuffers; bufferIdx++) { - res = mConsumerInterface->dequeueBuffer(mConsumerInterface.get(), + res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(), &anwBuffers[bufferIdx]); if (res != OK) { ALOGE("%s: Unable to dequeue buffer %d for initial registration for" @@ -433,17 +433,6 @@ status_t StreamAdapter::connectToDevice(camera2_device_t *d, mState = CONNECTED; goto cleanUpBuffers; } - - res = mConsumerInterface->lockBuffer(mConsumerInterface.get(), - anwBuffers[bufferIdx]); - if (res != OK) { - ALOGE("%s: Unable to lock buffer %d for initial registration for" - "stream %d", __FUNCTION__, bufferIdx, mId); - mState = CONNECTED; - bufferIdx++; - goto cleanUpBuffers; - } - buffers[bufferIdx] = anwBuffers[bufferIdx]->handle; } @@ -462,7 +451,7 @@ status_t StreamAdapter::connectToDevice(camera2_device_t *d, cleanUpBuffers: for (int i = 0; i < bufferIdx; i++) { res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(), - anwBuffers[i]); + anwBuffers[i], -1); } delete anwBuffers; delete buffers; @@ -517,9 +506,7 @@ int StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w, ANativeWindow *a = toANW(w); ANativeWindowBuffer* anb; - res = a->dequeueBuffer(a, &anb); - if (res != OK) return res; - res = a->lockBuffer(a, anb); + res = native_window_dequeue_buffer_and_wait(a, &anb); if (res != OK) return res; *buffer = &(anb->handle); @@ -540,7 +527,7 @@ int StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w, err = native_window_set_buffers_timestamp(a, timestamp); if (err != OK) return err; return a->queueBuffer(a, - container_of(buffer, ANativeWindowBuffer, handle)); + container_of(buffer, ANativeWindowBuffer, handle), -1); } int StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w, @@ -552,7 +539,7 @@ int StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w, } ANativeWindow *a = toANW(w); return a->cancelBuffer(a, - container_of(buffer, ANativeWindowBuffer, handle)); + container_of(buffer, ANativeWindowBuffer, handle), -1); } int StreamAdapter::set_crop(const camera2_stream_ops_t* w, -- cgit v1.1 From a635449697a2df5de98e72cfc24e926b641d5544 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 19 Jun 2012 12:16:04 -0700 Subject: Use audio_channel_mask_t consistently Change-Id: Ib832c0b707b1e0b82adf4ab3d4d18a2dc459d240 --- include/hardware/audio_effect.h | 4 ++-- include/hardware/audio_policy.h | 4 ++-- modules/audio/audio_hw.c | 4 ++-- modules/audio/audio_policy.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/hardware/audio_effect.h b/include/hardware/audio_effect.h index 65eba36..4037bbb 100644 --- a/include/hardware/audio_effect.h +++ b/include/hardware/audio_effect.h @@ -784,8 +784,8 @@ enum effect_feature_e { // EFFECT_FEATURE_AUX_CHANNELS feature configuration descriptor. Describe a combination // of main and auxiliary channels supported typedef struct channel_config_s { - uint32_t main_channels; // channel mask for main channels - uint32_t aux_channels; // channel mask for auxiliary channels + audio_channel_mask_t main_channels; // channel mask for main channels + audio_channel_mask_t aux_channels; // channel mask for auxiliary channels } channel_config_t; diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h index 78a1a62..8924dd1 100644 --- a/include/hardware/audio_policy.h +++ b/include/hardware/audio_policy.h @@ -132,7 +132,7 @@ struct audio_policy { audio_stream_type_t stream, uint32_t samplingRate, audio_format_t format, - uint32_t channels, + audio_channel_mask_t channelMask, audio_output_flags_t flags); /* indicates to the audio policy manager that the output starts being used @@ -157,7 +157,7 @@ struct audio_policy { audio_io_handle_t (*get_input)(struct audio_policy *pol, audio_source_t inputSource, uint32_t samplingRate, audio_format_t format, - uint32_t channels, + audio_channel_mask_t channelMask, audio_in_acoustics_t acoustics); /* indicates to the audio policy manager that the input starts being used */ diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c index d860437..15e9920 100644 --- a/modules/audio/audio_hw.c +++ b/modules/audio/audio_hw.c @@ -55,7 +55,7 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) return 4096; } -static uint32_t out_get_channels(const struct audio_stream *stream) +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) { return AUDIO_CHANNEL_OUT_STEREO; } @@ -148,7 +148,7 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) return 320; } -static uint32_t in_get_channels(const struct audio_stream *stream) +static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) { return AUDIO_CHANNEL_IN_MONO; } diff --git a/modules/audio/audio_policy.c b/modules/audio/audio_policy.c index ee95e92..a44ea77 100644 --- a/modules/audio/audio_policy.c +++ b/modules/audio/audio_policy.c @@ -98,7 +98,7 @@ static audio_io_handle_t ap_get_output(struct audio_policy *pol, audio_stream_type_t stream, uint32_t sampling_rate, audio_format_t format, - uint32_t channels, + audio_channel_mask_t channelMask, audio_output_flags_t flags) { return 0; @@ -124,7 +124,7 @@ static void ap_release_output(struct audio_policy *pol, static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource, uint32_t sampling_rate, audio_format_t format, - uint32_t channels, + audio_channel_mask_t channelMask, audio_in_acoustics_t acoustics) { return 0; -- cgit v1.1 From 88ef190fcf4a02839eb13ab7ca8d91d3dd145731 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Tue, 3 Jul 2012 21:17:23 -0700 Subject: hardware: Add field for number of framebuffers supported Change-Id: Iec29018a956d2c048ce077c48fd3995a4ca6f72a --- include/hardware/fb.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/hardware/fb.h b/include/hardware/fb.h index ba2f286..135e4aa 100644 --- a/include/hardware/fb.h +++ b/include/hardware/fb.h @@ -64,7 +64,10 @@ typedef struct framebuffer_device_t { /* max swap interval supported by this framebuffer */ const int maxSwapInterval; - int reserved[8]; + /* Number of framebuffers supported*/ + const int numFramebuffers; + + int reserved[7]; /* * requests a specific swap-interval (same definition than EGL) -- cgit v1.1 From 38fccf483b19a0dd2431cb8515e7a2cc5546b373 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 12 Jul 2012 17:54:59 -0700 Subject: hwcomposer: add a new blank operation Add a new blank operation to be called by surfaceflinger when the screen turns on or off. Also rev the API version to 1.1 for the new field. Change-Id: I266fb33f66184538e34cfc319f63cf809dcb2f18 --- include/hardware/hwcomposer.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 4af5c69..a036da3 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -79,6 +79,21 @@ typedef struct hwc_methods_1 { int (*eventControl)( struct hwc_composer_device_1* dev, int event, int enabled); + /* + * This field is OPTIONAL and can be NULL. + * + * blank(..., blank) + * Blanks or unblanks the screen. + * + * Turns the screen off when blank is nonzero, on when blank is zero. + * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple + * sequential calls with the same blank value must be supported. + * + * returns 0 on success, negative on error. + */ + + int (*blank)(struct hwc_composer_device_1* dev, int blank); + } hwc_methods_1_t; typedef struct hwc_rect { -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 -- cgit v1.1 From 7797d75b12a90cd03a47642c59dbb677aa4daa88 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 16 Jul 2012 14:50:50 -0700 Subject: Add camera gralloc usage flags. GRALLOC_USAGE_HW_CAMERA_WRITE is for camera outputs in the new camera HAL. GRALLOC_USAGE_HW_CAMERA_READ is for sending previously captured camera data back into the camera pipeline for further processing. For example, for converting a raw sensor image into YUV or JPEG data. Bug: 6243944 Change-Id: If9011ec320a1a804f3337704243ed7fc410fec91 --- include/hardware/gralloc.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h index 2dbd1fa..86ed95c 100644 --- a/include/hardware/gralloc.h +++ b/include/hardware/gralloc.h @@ -76,8 +76,12 @@ enum { GRALLOC_USAGE_HW_FB = 0x00001000, /* buffer will be used with the HW video encoder */ GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000, + /* buffer will be written by the HW camera pipeline */ + GRALLOC_USAGE_HW_CAMERA_WRITE = 0x00020000, + /* buffer will be read by the HW camera pipeline */ + GRALLOC_USAGE_HW_CAMERA_READ = 0x00040000, /* mask for the software usage bit-mask */ - GRALLOC_USAGE_HW_MASK = 0x00011F00, + GRALLOC_USAGE_HW_MASK = 0x00071F00, /* buffer should be displayed full-screen on an external display when * possible -- cgit v1.1 From afc55fd404d7d86f0affc9080ccb42aad8745d3a Mon Sep 17 00:00:00 2001 From: John Grossman Date: Tue, 17 Jul 2012 11:54:04 -0700 Subject: Extend the audio HAL interface to support get/set master mute: DO NOT MERGE Extend the audio HAL interface to allow HALs to optionally support HW level master mute. This follows the same pattern as master volume and is part of the fix for bug 6828363. Because of the divergences between ICS and master, this change will need to be merged by hand. Signed-off-by: John Grossman Change-Id: Ica6f5e37e13d13dde60463966f41f271ffa104fd --- include/hardware/audio.h | 17 ++++++++++++++++- modules/audio/audio_hw.c | 15 +++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/hardware/audio.h b/include/hardware/audio.h index ac014a1..6770ce0 100644 --- a/include/hardware/audio.h +++ b/include/hardware/audio.h @@ -284,11 +284,26 @@ struct audio_hw_device { * master volume control. AudioFlinger will query this value from the * primary audio HAL when the service starts and use the value for setting * the initial master volume across all HALs. HALs which do not support - * this method should may leave it set to NULL. + * this method may leave it set to NULL. */ int (*get_master_volume)(struct audio_hw_device *dev, float *volume); /** + * set the audio mute status for all audio activities. If any value other + * than 0 is returned, the software mixer will emulate this capability. + */ + int (*set_master_mute)(struct audio_hw_device *dev, bool mute); + + /** + * Get the current master mute status for the HAL, if the HAL supports + * master mute control. AudioFlinger will query this value from the primary + * audio HAL when the service starts and use the value for setting the + * initial master mute across all HALs. HALs which do not support this + * method may leave it set to NULL. + */ + int (*get_master_mute)(struct audio_hw_device *dev, bool *mute); + + /** * setMode is called when the audio mode changes. AUDIO_MODE_NORMAL mode * is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is * playing, and AUDIO_MODE_IN_CALL when a call is in progress. diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c index f25a053..47b3bb4 100644 --- a/modules/audio/audio_hw.c +++ b/modules/audio/audio_hw.c @@ -285,8 +285,17 @@ static int adev_set_master_volume(struct audio_hw_device *dev, float volume) return -ENOSYS; } -static int adev_get_master_volume(struct audio_hw_device *dev, - float *volume) +static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) +{ + return -ENOSYS; +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +{ + return -ENOSYS; +} + +static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) { return -ENOSYS; } @@ -415,6 +424,8 @@ static int adev_open(const hw_module_t* module, const char* name, adev->device.set_voice_volume = adev_set_voice_volume; adev->device.set_master_volume = adev_set_master_volume; adev->device.get_master_volume = adev_get_master_volume; + adev->device.set_master_mute = adev_set_master_mute; + adev->device.get_master_mute = adev_get_master_mute; adev->device.set_mode = adev_set_mode; adev->device.set_mic_mute = adev_set_mic_mute; adev->device.get_mic_mute = adev_get_mic_mute; -- cgit v1.1 From 48915acb392773c1fcb86e2711eab468410a0baa Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 20 Feb 2012 12:08:57 -0800 Subject: struct effect_descriptor_s const correctness Also struct audio_stream in audio_stream_frame_size Change-Id: Ie0de708e38a1850c186a8b4eb5f491adc44b3275 --- include/hardware/audio.h | 2 +- include/hardware/audio_policy.h | 4 ++-- modules/audio/audio_policy.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/hardware/audio.h b/include/hardware/audio.h index 01d79b2..0a917e2 100644 --- a/include/hardware/audio.h +++ b/include/hardware/audio.h @@ -291,7 +291,7 @@ typedef struct audio_stream_in audio_stream_in_t; /** * return the frame size (number of bytes per sample). */ -static inline size_t audio_stream_frame_size(struct audio_stream *s) +static inline size_t audio_stream_frame_size(const struct audio_stream *s) { size_t chan_samp_sz; diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h index 8924dd1..53c8ae3 100644 --- a/include/hardware/audio_policy.h +++ b/include/hardware/audio_policy.h @@ -215,10 +215,10 @@ struct audio_policy { /* Audio effect management */ audio_io_handle_t (*get_output_for_effect)(struct audio_policy *pol, - struct effect_descriptor_s *desc); + const struct effect_descriptor_s *desc); int (*register_effect)(struct audio_policy *pol, - struct effect_descriptor_s *desc, + const struct effect_descriptor_s *desc, audio_io_handle_t output, uint32_t strategy, int session, diff --git a/modules/audio/audio_policy.c b/modules/audio/audio_policy.c index a44ea77..2dd3dbe 100644 --- a/modules/audio/audio_policy.c +++ b/modules/audio/audio_policy.c @@ -193,13 +193,13 @@ static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol, } static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol, - struct effect_descriptor_s *desc) + const struct effect_descriptor_s *desc) { return 0; } static int ap_register_effect(struct audio_policy *pol, - struct effect_descriptor_s *desc, + const struct effect_descriptor_s *desc, audio_io_handle_t output, uint32_t strategy, int session, -- cgit v1.1 From e57a2d2ec601c54852a1cf55c11186bbf5c6c8f5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 22 Jun 2012 13:35:54 -0700 Subject: Add comment Change-Id: Idc2890ebc10c0e6a116bc7c8872cd379e1cf3e25 --- include/hardware/audio_policy.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h index 8924dd1..4662f0f 100644 --- a/include/hardware/audio_policy.h +++ b/include/hardware/audio_policy.h @@ -291,7 +291,10 @@ struct audio_policy_service_ops { /* Audio input Control functions */ /* */ - /* opens an audio input */ + /* opens an audio input + * deprecated - new implementations should use open_input_on_module, + * and the acoustics parameter is ignored + */ audio_io_handle_t (*open_input)(void *service, audio_devices_t *pDevices, uint32_t *pSamplingRate, -- cgit v1.1 From 65bed1f947ad9eb992c02a3563bd64ef05c4e268 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Wed, 25 Jul 2012 15:11:41 -0700 Subject: Add multi-display and flip fence to HWC Change-Id: I31b4fc293220bc51169971df93347dd35fdc30ef --- include/hardware/hwcomposer.h | 117 ++++++++++++++++++++------------------ modules/hwcomposer/hwcomposer.cpp | 16 +++--- 2 files changed, 69 insertions(+), 64 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index a036da3..11176ec 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -64,7 +64,7 @@ typedef struct hwc_methods_1 { /* * eventControl(..., event, enabled) - * Enables or disables h/w composer events. + * Enables or disables h/w composer events for a display. * * eventControl can be called from any thread and takes effect * immediately. @@ -77,13 +77,14 @@ typedef struct hwc_methods_1 { */ int (*eventControl)( - struct hwc_composer_device_1* dev, int event, int enabled); + struct hwc_composer_device_1* dev, int dpy, + int event, int enabled); /* * This field is OPTIONAL and can be NULL. * * blank(..., blank) - * Blanks or unblanks the screen. + * Blanks or unblanks a display's screen. * * Turns the screen off when blank is nonzero, on when blank is zero. * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple @@ -92,7 +93,7 @@ typedef struct hwc_methods_1 { * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int blank); + int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); } hwc_methods_1_t; @@ -215,8 +216,14 @@ typedef struct hwc_layer_1 { } hwc_layer_1_t; +/* This represents a display, typically an EGLDisplay object */ +typedef void* hwc_display_t; + +/* This represents a surface, typically an EGLSurface object */ +typedef void* hwc_surface_t; + /* - * hwc_layer_list_t::flags values + * hwc_display_contents_1_t::flags values */ enum { /* @@ -228,21 +235,36 @@ enum { }; /* - * List of layers. - * The handle members of hwLayers elements must be unique. + * Description of the contents to output on a display. + * + * This is the top-level structure passed to the prepare and set calls to + * negotiate and commit the composition of a display image. */ -typedef struct hwc_layer_list_1 { +typedef struct hwc_display_contents_1 { + /* File descriptor referring to a Sync HAL fence object which will signal + * when this display image is no longer visible, i.e. when the following + * set() takes effect. The fence object is created and returned by the set + * call; this field will be -1 on entry to prepare and set. SurfaceFlinger + * will close the returned file descriptor. + */ + int flipFenceFd; + + /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition. + * They aren't relevant to prepare. The set call should commit this surface + * atomically to the display along with any overlay layers. + */ + hwc_display_t dpy; + hwc_surface_t sur; + + /* List of layers that will be composed on the display. The buffer handles + * in the list will be unique. If numHwLayers is 0 and/or hwLayers is NULL, + * all composition will be performed by SurfaceFlinger. + */ uint32_t flags; size_t numHwLayers; hwc_layer_1_t hwLayers[0]; -} hwc_layer_list_1_t; - -/* This represents a display, typically an EGLDisplay object */ -typedef void* hwc_display_t; - -/* This represents a surface, typically an EGLSurface object */ -typedef void* hwc_surface_t; +} hwc_display_contents_1_t; /* see hwc_composer_device::registerProcs() * Any of the callbacks can be NULL, in which case the corresponding @@ -262,9 +284,10 @@ typedef struct hwc_procs { /* * (*vsync)() is called by the h/w composer HAL when a vsync event is - * received and HWC_EVENT_VSYNC is enabled (see: hwc_event_control). + * received and HWC_EVENT_VSYNC is enabled on a display + * (see: hwc_event_control). * - * the "zero" parameter must always be 0. + * the "dpy" parameter indicates which display the vsync event is for. * the "timestamp" parameter is the system monotonic clock timestamp in * nanosecond of when the vsync event happened. * @@ -278,9 +301,8 @@ typedef struct hwc_procs { * hwc_composer_device.set(..., 0, 0, 0) (screen off). The implementation * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. - * */ - void (*vsync)(struct hwc_procs* procs, int zero, int64_t timestamp); + void (*vsync)(struct hwc_procs* procs, int dpy, int64_t timestamp); } hwc_procs_t; @@ -299,72 +321,55 @@ typedef struct hwc_composer_device_1 { * * (*prepare)() can be called more than once, the last call prevails. * - * The HWC responds by setting the compositionType field to either - * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for - * this layer is handled by SurfaceFlinger with OpenGL ES, in the later - * case, the HWC will have to handle this layer's composition. + * The HWC responds by setting the compositionType field in each layer to + * either HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the + * composition for the layer is handled by SurfaceFlinger with OpenGL ES, + * in the later case, the HWC will have to handle the layer's composition. * * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the * list's geometry has changed, that is, when more than just the buffer's * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * - * a NULL list parameter or a numHwLayers of zero indicates that the - * entire composition will be handled by SurfaceFlinger with OpenGL ES. - * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. */ int (*prepare)(struct hwc_composer_device_1 *dev, - hwc_layer_list_1_t* list); + size_t numDisplays, hwc_display_contents_1_t** displays); /* * (*set)() is used in place of eglSwapBuffers(), and assumes the same * functionality, except it also commits the work list atomically with * the actual eglSwapBuffers(). * - * The list parameter is guaranteed to be the same as the one returned - * from the last call to (*prepare)(). - * - * When this call returns the caller assumes that: + * The layer lists are guaranteed to be the same as the ones returned from + * the last call to (*prepare)(). * - * - the display will be updated in the near future with the content - * of the work list, without artifacts during the transition from the - * previous frame. + * When this call returns the caller assumes that the displays will be + * updated in the near future with the content of their work lists, without + * artifacts during the transition from the previous frame. * - * - all objects are available for immediate access or destruction, in - * particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer. - * Note that this means that immediately accessing (potentially from a - * different process) a buffer used in this call will not result in - * screen corruption, the driver must apply proper synchronization or - * scheduling (eg: block the caller, such as gralloc_module_t::lock(), - * OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work - * after the buffer is freed from the actual composition). - * - * a NULL list parameter or a numHwLayers of zero indicates that the - * entire composition has been handled by SurfaceFlinger with OpenGL ES. + * A display with a NULL layer list or a numHwLayers of zero indicates that + * the entire composition has been handled by SurfaceFlinger with OpenGL ES. * In this case, (*set)() behaves just like eglSwapBuffers(). * - * dpy, sur, and list are set to NULL to indicate that the screen is - * turning off. This happens WITHOUT prepare() being called first. - * This is a good time to free h/w resources and/or power - * the relevant h/w blocks down. + * The dpy, surf, and layers fields are set to NULL to indicate that the + * screen is turning off. This happens WITHOUT prepare() being called first. + * This is a good time to free h/w resources and/or power down the relevant + * h/w blocks. * * IMPORTANT NOTE: there is an implicit layer containing opaque black - * pixels behind all the layers in the list. - * It is the responsibility of the hwcomposer module to make - * sure black pixels are output (or blended from). + * pixels behind all the layers in the list. It is the responsibility of + * the hwcomposer module to make sure black pixels are output (or blended + * from). * * returns: 0 on success. An negative error code on error: * HWC_EGL_ERROR: eglGetError() will provide the proper error code * Another code for non EGL errors. - * */ int (*set)(struct hwc_composer_device_1 *dev, - hwc_display_t dpy, - hwc_surface_t sur, - hwc_layer_list_1_t* list); + size_t numDisplays, hwc_display_contents_1_t** displays); /* * This field is OPTIONAL and can be NULL. diff --git a/modules/hwcomposer/hwcomposer.cpp b/modules/hwcomposer/hwcomposer.cpp index 0e49e4c..f0a5512 100644 --- a/modules/hwcomposer/hwcomposer.cpp +++ b/modules/hwcomposer/hwcomposer.cpp @@ -67,26 +67,26 @@ static void dump_layer(hwc_layer_1_t const* l) { l->displayFrame.bottom); } -static int hwc_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) { - if (list && (list->flags & HWC_GEOMETRY_CHANGED)) { - for (size_t i=0 ; inumHwLayers ; i++) { +static int hwc_prepare(hwc_composer_device_1_t *dev, + size_t numDisplays, hwc_display_contents_1_t** displays) { + if (displays && (displays[0]->flags & HWC_GEOMETRY_CHANGED)) { + for (size_t i=0 ; inumHwLayers ; i++) { //dump_layer(&list->hwLayers[i]); - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; } } return 0; } static int hwc_set(hwc_composer_device_1_t *dev, - hwc_display_t dpy, - hwc_surface_t sur, - hwc_layer_list_1_t* list) + size_t numDisplays, hwc_display_contents_1_t** displays) { //for (size_t i=0 ; inumHwLayers ; i++) { // dump_layer(&list->hwLayers[i]); //} - EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)displays[0]->dpy, + (EGLSurface)displays[0]->sur); if (!sucess) { return HWC_EGL_ERROR; } -- cgit v1.1 From 85ab59a147eb67cd17a9348949d5a365bf702a5f Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 31 Jul 2012 12:16:24 -0700 Subject: Revert "Add multi-display and flip fence to HWC" This reverts commit 1d51b2b9fc713da6de18117bc19508ecdfde4f23 Change-Id: I1ae46d8cae1cb3064800cd24df56347b05eb6059 --- include/hardware/hwcomposer.h | 117 ++++++++++++++++++-------------------- modules/hwcomposer/hwcomposer.cpp | 16 +++--- 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 11176ec..a036da3 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -64,7 +64,7 @@ typedef struct hwc_methods_1 { /* * eventControl(..., event, enabled) - * Enables or disables h/w composer events for a display. + * Enables or disables h/w composer events. * * eventControl can be called from any thread and takes effect * immediately. @@ -77,14 +77,13 @@ typedef struct hwc_methods_1 { */ int (*eventControl)( - struct hwc_composer_device_1* dev, int dpy, - int event, int enabled); + struct hwc_composer_device_1* dev, int event, int enabled); /* * This field is OPTIONAL and can be NULL. * * blank(..., blank) - * Blanks or unblanks a display's screen. + * Blanks or unblanks the screen. * * Turns the screen off when blank is nonzero, on when blank is zero. * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple @@ -93,7 +92,7 @@ typedef struct hwc_methods_1 { * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); + int (*blank)(struct hwc_composer_device_1* dev, int blank); } hwc_methods_1_t; @@ -216,14 +215,8 @@ typedef struct hwc_layer_1 { } hwc_layer_1_t; -/* This represents a display, typically an EGLDisplay object */ -typedef void* hwc_display_t; - -/* This represents a surface, typically an EGLSurface object */ -typedef void* hwc_surface_t; - /* - * hwc_display_contents_1_t::flags values + * hwc_layer_list_t::flags values */ enum { /* @@ -235,36 +228,21 @@ enum { }; /* - * Description of the contents to output on a display. - * - * This is the top-level structure passed to the prepare and set calls to - * negotiate and commit the composition of a display image. + * List of layers. + * The handle members of hwLayers elements must be unique. */ -typedef struct hwc_display_contents_1 { - /* File descriptor referring to a Sync HAL fence object which will signal - * when this display image is no longer visible, i.e. when the following - * set() takes effect. The fence object is created and returned by the set - * call; this field will be -1 on entry to prepare and set. SurfaceFlinger - * will close the returned file descriptor. - */ - int flipFenceFd; - - /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition. - * They aren't relevant to prepare. The set call should commit this surface - * atomically to the display along with any overlay layers. - */ - hwc_display_t dpy; - hwc_surface_t sur; - - /* List of layers that will be composed on the display. The buffer handles - * in the list will be unique. If numHwLayers is 0 and/or hwLayers is NULL, - * all composition will be performed by SurfaceFlinger. - */ +typedef struct hwc_layer_list_1 { uint32_t flags; size_t numHwLayers; hwc_layer_1_t hwLayers[0]; +} hwc_layer_list_1_t; + +/* This represents a display, typically an EGLDisplay object */ +typedef void* hwc_display_t; + +/* This represents a surface, typically an EGLSurface object */ +typedef void* hwc_surface_t; -} hwc_display_contents_1_t; /* see hwc_composer_device::registerProcs() * Any of the callbacks can be NULL, in which case the corresponding @@ -284,10 +262,9 @@ typedef struct hwc_procs { /* * (*vsync)() is called by the h/w composer HAL when a vsync event is - * received and HWC_EVENT_VSYNC is enabled on a display - * (see: hwc_event_control). + * received and HWC_EVENT_VSYNC is enabled (see: hwc_event_control). * - * the "dpy" parameter indicates which display the vsync event is for. + * the "zero" parameter must always be 0. * the "timestamp" parameter is the system monotonic clock timestamp in * nanosecond of when the vsync event happened. * @@ -301,8 +278,9 @@ typedef struct hwc_procs { * hwc_composer_device.set(..., 0, 0, 0) (screen off). The implementation * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. + * */ - void (*vsync)(struct hwc_procs* procs, int dpy, int64_t timestamp); + void (*vsync)(struct hwc_procs* procs, int zero, int64_t timestamp); } hwc_procs_t; @@ -321,55 +299,72 @@ typedef struct hwc_composer_device_1 { * * (*prepare)() can be called more than once, the last call prevails. * - * The HWC responds by setting the compositionType field in each layer to - * either HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the - * composition for the layer is handled by SurfaceFlinger with OpenGL ES, - * in the later case, the HWC will have to handle the layer's composition. + * The HWC responds by setting the compositionType field to either + * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for + * this layer is handled by SurfaceFlinger with OpenGL ES, in the later + * case, the HWC will have to handle this layer's composition. * * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the * list's geometry has changed, that is, when more than just the buffer's * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition will be handled by SurfaceFlinger with OpenGL ES. + * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. */ int (*prepare)(struct hwc_composer_device_1 *dev, - size_t numDisplays, hwc_display_contents_1_t** displays); + hwc_layer_list_1_t* list); /* * (*set)() is used in place of eglSwapBuffers(), and assumes the same * functionality, except it also commits the work list atomically with * the actual eglSwapBuffers(). * - * The layer lists are guaranteed to be the same as the ones returned from - * the last call to (*prepare)(). + * The list parameter is guaranteed to be the same as the one returned + * from the last call to (*prepare)(). + * + * When this call returns the caller assumes that: * - * When this call returns the caller assumes that the displays will be - * updated in the near future with the content of their work lists, without - * artifacts during the transition from the previous frame. + * - the display will be updated in the near future with the content + * of the work list, without artifacts during the transition from the + * previous frame. * - * A display with a NULL layer list or a numHwLayers of zero indicates that - * the entire composition has been handled by SurfaceFlinger with OpenGL ES. + * - all objects are available for immediate access or destruction, in + * particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer. + * Note that this means that immediately accessing (potentially from a + * different process) a buffer used in this call will not result in + * screen corruption, the driver must apply proper synchronization or + * scheduling (eg: block the caller, such as gralloc_module_t::lock(), + * OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work + * after the buffer is freed from the actual composition). + * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition has been handled by SurfaceFlinger with OpenGL ES. * In this case, (*set)() behaves just like eglSwapBuffers(). * - * The dpy, surf, and layers fields are set to NULL to indicate that the - * screen is turning off. This happens WITHOUT prepare() being called first. - * This is a good time to free h/w resources and/or power down the relevant - * h/w blocks. + * dpy, sur, and list are set to NULL to indicate that the screen is + * turning off. This happens WITHOUT prepare() being called first. + * This is a good time to free h/w resources and/or power + * the relevant h/w blocks down. * * IMPORTANT NOTE: there is an implicit layer containing opaque black - * pixels behind all the layers in the list. It is the responsibility of - * the hwcomposer module to make sure black pixels are output (or blended - * from). + * pixels behind all the layers in the list. + * It is the responsibility of the hwcomposer module to make + * sure black pixels are output (or blended from). * * returns: 0 on success. An negative error code on error: * HWC_EGL_ERROR: eglGetError() will provide the proper error code * Another code for non EGL errors. + * */ int (*set)(struct hwc_composer_device_1 *dev, - size_t numDisplays, hwc_display_contents_1_t** displays); + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_1_t* list); /* * This field is OPTIONAL and can be NULL. diff --git a/modules/hwcomposer/hwcomposer.cpp b/modules/hwcomposer/hwcomposer.cpp index f0a5512..0e49e4c 100644 --- a/modules/hwcomposer/hwcomposer.cpp +++ b/modules/hwcomposer/hwcomposer.cpp @@ -67,26 +67,26 @@ static void dump_layer(hwc_layer_1_t const* l) { l->displayFrame.bottom); } -static int hwc_prepare(hwc_composer_device_1_t *dev, - size_t numDisplays, hwc_display_contents_1_t** displays) { - if (displays && (displays[0]->flags & HWC_GEOMETRY_CHANGED)) { - for (size_t i=0 ; inumHwLayers ; i++) { +static int hwc_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) { + if (list && (list->flags & HWC_GEOMETRY_CHANGED)) { + for (size_t i=0 ; inumHwLayers ; i++) { //dump_layer(&list->hwLayers[i]); - displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; } } return 0; } static int hwc_set(hwc_composer_device_1_t *dev, - size_t numDisplays, hwc_display_contents_1_t** displays) + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_1_t* list) { //for (size_t i=0 ; inumHwLayers ; i++) { // dump_layer(&list->hwLayers[i]); //} - EGLBoolean sucess = eglSwapBuffers((EGLDisplay)displays[0]->dpy, - (EGLSurface)displays[0]->sur); + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); if (!sucess) { return HWC_EGL_ERROR; } -- cgit v1.1 From d8cb4d8a79805c72953b6e4333dc36d5e0a597b6 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 31 Jul 2012 12:16:24 -0700 Subject: Revert "Add multi-display and flip fence to HWC" This reverts commit 1d51b2b9fc713da6de18117bc19508ecdfde4f23 Change-Id: I1ae46d8cae1cb3064800cd24df56347b05eb6059 --- include/hardware/hwcomposer.h | 117 ++++++++++++++++++-------------------- modules/hwcomposer/hwcomposer.cpp | 16 +++--- 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 11176ec..a036da3 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -64,7 +64,7 @@ typedef struct hwc_methods_1 { /* * eventControl(..., event, enabled) - * Enables or disables h/w composer events for a display. + * Enables or disables h/w composer events. * * eventControl can be called from any thread and takes effect * immediately. @@ -77,14 +77,13 @@ typedef struct hwc_methods_1 { */ int (*eventControl)( - struct hwc_composer_device_1* dev, int dpy, - int event, int enabled); + struct hwc_composer_device_1* dev, int event, int enabled); /* * This field is OPTIONAL and can be NULL. * * blank(..., blank) - * Blanks or unblanks a display's screen. + * Blanks or unblanks the screen. * * Turns the screen off when blank is nonzero, on when blank is zero. * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple @@ -93,7 +92,7 @@ typedef struct hwc_methods_1 { * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); + int (*blank)(struct hwc_composer_device_1* dev, int blank); } hwc_methods_1_t; @@ -216,14 +215,8 @@ typedef struct hwc_layer_1 { } hwc_layer_1_t; -/* This represents a display, typically an EGLDisplay object */ -typedef void* hwc_display_t; - -/* This represents a surface, typically an EGLSurface object */ -typedef void* hwc_surface_t; - /* - * hwc_display_contents_1_t::flags values + * hwc_layer_list_t::flags values */ enum { /* @@ -235,36 +228,21 @@ enum { }; /* - * Description of the contents to output on a display. - * - * This is the top-level structure passed to the prepare and set calls to - * negotiate and commit the composition of a display image. + * List of layers. + * The handle members of hwLayers elements must be unique. */ -typedef struct hwc_display_contents_1 { - /* File descriptor referring to a Sync HAL fence object which will signal - * when this display image is no longer visible, i.e. when the following - * set() takes effect. The fence object is created and returned by the set - * call; this field will be -1 on entry to prepare and set. SurfaceFlinger - * will close the returned file descriptor. - */ - int flipFenceFd; - - /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition. - * They aren't relevant to prepare. The set call should commit this surface - * atomically to the display along with any overlay layers. - */ - hwc_display_t dpy; - hwc_surface_t sur; - - /* List of layers that will be composed on the display. The buffer handles - * in the list will be unique. If numHwLayers is 0 and/or hwLayers is NULL, - * all composition will be performed by SurfaceFlinger. - */ +typedef struct hwc_layer_list_1 { uint32_t flags; size_t numHwLayers; hwc_layer_1_t hwLayers[0]; +} hwc_layer_list_1_t; + +/* This represents a display, typically an EGLDisplay object */ +typedef void* hwc_display_t; + +/* This represents a surface, typically an EGLSurface object */ +typedef void* hwc_surface_t; -} hwc_display_contents_1_t; /* see hwc_composer_device::registerProcs() * Any of the callbacks can be NULL, in which case the corresponding @@ -284,10 +262,9 @@ typedef struct hwc_procs { /* * (*vsync)() is called by the h/w composer HAL when a vsync event is - * received and HWC_EVENT_VSYNC is enabled on a display - * (see: hwc_event_control). + * received and HWC_EVENT_VSYNC is enabled (see: hwc_event_control). * - * the "dpy" parameter indicates which display the vsync event is for. + * the "zero" parameter must always be 0. * the "timestamp" parameter is the system monotonic clock timestamp in * nanosecond of when the vsync event happened. * @@ -301,8 +278,9 @@ typedef struct hwc_procs { * hwc_composer_device.set(..., 0, 0, 0) (screen off). The implementation * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. + * */ - void (*vsync)(struct hwc_procs* procs, int dpy, int64_t timestamp); + void (*vsync)(struct hwc_procs* procs, int zero, int64_t timestamp); } hwc_procs_t; @@ -321,55 +299,72 @@ typedef struct hwc_composer_device_1 { * * (*prepare)() can be called more than once, the last call prevails. * - * The HWC responds by setting the compositionType field in each layer to - * either HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the - * composition for the layer is handled by SurfaceFlinger with OpenGL ES, - * in the later case, the HWC will have to handle the layer's composition. + * The HWC responds by setting the compositionType field to either + * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for + * this layer is handled by SurfaceFlinger with OpenGL ES, in the later + * case, the HWC will have to handle this layer's composition. * * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the * list's geometry has changed, that is, when more than just the buffer's * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition will be handled by SurfaceFlinger with OpenGL ES. + * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. */ int (*prepare)(struct hwc_composer_device_1 *dev, - size_t numDisplays, hwc_display_contents_1_t** displays); + hwc_layer_list_1_t* list); /* * (*set)() is used in place of eglSwapBuffers(), and assumes the same * functionality, except it also commits the work list atomically with * the actual eglSwapBuffers(). * - * The layer lists are guaranteed to be the same as the ones returned from - * the last call to (*prepare)(). + * The list parameter is guaranteed to be the same as the one returned + * from the last call to (*prepare)(). + * + * When this call returns the caller assumes that: * - * When this call returns the caller assumes that the displays will be - * updated in the near future with the content of their work lists, without - * artifacts during the transition from the previous frame. + * - the display will be updated in the near future with the content + * of the work list, without artifacts during the transition from the + * previous frame. * - * A display with a NULL layer list or a numHwLayers of zero indicates that - * the entire composition has been handled by SurfaceFlinger with OpenGL ES. + * - all objects are available for immediate access or destruction, in + * particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer. + * Note that this means that immediately accessing (potentially from a + * different process) a buffer used in this call will not result in + * screen corruption, the driver must apply proper synchronization or + * scheduling (eg: block the caller, such as gralloc_module_t::lock(), + * OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work + * after the buffer is freed from the actual composition). + * + * a NULL list parameter or a numHwLayers of zero indicates that the + * entire composition has been handled by SurfaceFlinger with OpenGL ES. * In this case, (*set)() behaves just like eglSwapBuffers(). * - * The dpy, surf, and layers fields are set to NULL to indicate that the - * screen is turning off. This happens WITHOUT prepare() being called first. - * This is a good time to free h/w resources and/or power down the relevant - * h/w blocks. + * dpy, sur, and list are set to NULL to indicate that the screen is + * turning off. This happens WITHOUT prepare() being called first. + * This is a good time to free h/w resources and/or power + * the relevant h/w blocks down. * * IMPORTANT NOTE: there is an implicit layer containing opaque black - * pixels behind all the layers in the list. It is the responsibility of - * the hwcomposer module to make sure black pixels are output (or blended - * from). + * pixels behind all the layers in the list. + * It is the responsibility of the hwcomposer module to make + * sure black pixels are output (or blended from). * * returns: 0 on success. An negative error code on error: * HWC_EGL_ERROR: eglGetError() will provide the proper error code * Another code for non EGL errors. + * */ int (*set)(struct hwc_composer_device_1 *dev, - size_t numDisplays, hwc_display_contents_1_t** displays); + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_1_t* list); /* * This field is OPTIONAL and can be NULL. diff --git a/modules/hwcomposer/hwcomposer.cpp b/modules/hwcomposer/hwcomposer.cpp index f0a5512..0e49e4c 100644 --- a/modules/hwcomposer/hwcomposer.cpp +++ b/modules/hwcomposer/hwcomposer.cpp @@ -67,26 +67,26 @@ static void dump_layer(hwc_layer_1_t const* l) { l->displayFrame.bottom); } -static int hwc_prepare(hwc_composer_device_1_t *dev, - size_t numDisplays, hwc_display_contents_1_t** displays) { - if (displays && (displays[0]->flags & HWC_GEOMETRY_CHANGED)) { - for (size_t i=0 ; inumHwLayers ; i++) { +static int hwc_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) { + if (list && (list->flags & HWC_GEOMETRY_CHANGED)) { + for (size_t i=0 ; inumHwLayers ; i++) { //dump_layer(&list->hwLayers[i]); - displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; } } return 0; } static int hwc_set(hwc_composer_device_1_t *dev, - size_t numDisplays, hwc_display_contents_1_t** displays) + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_1_t* list) { //for (size_t i=0 ; inumHwLayers ; i++) { // dump_layer(&list->hwLayers[i]); //} - EGLBoolean sucess = eglSwapBuffers((EGLDisplay)displays[0]->dpy, - (EGLSurface)displays[0]->sur); + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); if (!sucess) { return HWC_EGL_ERROR; } -- cgit v1.1 From 5d64b230dc7c262575dd790299cfb667af66e014 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Mon, 30 Jul 2012 10:12:40 -0700 Subject: Camera2: Test logging changes Change-Id: Idcde83d46da438726c5186cbcf8109a22aef997f --- tests/camera2/camera2.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 8a0e842..05f61ef 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -94,8 +94,8 @@ class Camera2Test: public testing::Test { ASSERT_TRUE(NULL != info.static_camera_characteristics); IF_ALOGV() { std::cout << " Static camera metadata:" << std::endl; - dump_camera_metadata(info.static_camera_characteristics, - 0, 1); + dump_indented_camera_metadata(info.static_camera_characteristics, + 0, 1, 6); } } else { sCameraSupportsHal2[i] = false; @@ -392,7 +392,7 @@ TEST_F(Camera2Test, Capture1Raw) { IF_ALOGV() { std::cout << "Input request: " << std::endl; - dump_camera_metadata(request, 0, 1); + dump_indented_camera_metadata(request, 0, 1, 2); } res = mRequests.enqueue(request); @@ -408,7 +408,7 @@ TEST_F(Camera2Test, Capture1Raw) { IF_ALOGV() { std::cout << "Output frame:" << std::endl; - dump_camera_metadata(frame, 0, 1); + dump_indented_camera_metadata(frame, 0, 1, 2); } res = rawWaiter->waitForFrame(exposureTime + SEC); @@ -502,7 +502,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { IF_ALOGV() { std::cout << "Input request template: " << std::endl; - dump_camera_metadata(request, 0, 1); + dump_indented_camera_metadata(request, 0, 1, 2); } int numCaptures = 10; @@ -598,7 +598,7 @@ TEST_F(Camera2Test, ConstructDefaultRequests) { IF_ALOGV() { std::cout << " ** Template type " << i << ":"<waitForFrame(exposureTime + SEC); -- cgit v1.1 From f9d6cd7dee62789b220033c926c87deab8991bde Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 31 Jul 2012 14:29:00 -0700 Subject: Add multi-display and flip fence to HWC Change-Id: I3b0446050648e2b386ffb32976c9943b6fd9793d --- include/hardware/hwcomposer.h | 117 ++++++++++++++++++++------------------ modules/hwcomposer/hwcomposer.cpp | 16 +++--- 2 files changed, 69 insertions(+), 64 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index a036da3..11176ec 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -64,7 +64,7 @@ typedef struct hwc_methods_1 { /* * eventControl(..., event, enabled) - * Enables or disables h/w composer events. + * Enables or disables h/w composer events for a display. * * eventControl can be called from any thread and takes effect * immediately. @@ -77,13 +77,14 @@ typedef struct hwc_methods_1 { */ int (*eventControl)( - struct hwc_composer_device_1* dev, int event, int enabled); + struct hwc_composer_device_1* dev, int dpy, + int event, int enabled); /* * This field is OPTIONAL and can be NULL. * * blank(..., blank) - * Blanks or unblanks the screen. + * Blanks or unblanks a display's screen. * * Turns the screen off when blank is nonzero, on when blank is zero. * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple @@ -92,7 +93,7 @@ typedef struct hwc_methods_1 { * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int blank); + int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); } hwc_methods_1_t; @@ -215,8 +216,14 @@ typedef struct hwc_layer_1 { } hwc_layer_1_t; +/* This represents a display, typically an EGLDisplay object */ +typedef void* hwc_display_t; + +/* This represents a surface, typically an EGLSurface object */ +typedef void* hwc_surface_t; + /* - * hwc_layer_list_t::flags values + * hwc_display_contents_1_t::flags values */ enum { /* @@ -228,21 +235,36 @@ enum { }; /* - * List of layers. - * The handle members of hwLayers elements must be unique. + * Description of the contents to output on a display. + * + * This is the top-level structure passed to the prepare and set calls to + * negotiate and commit the composition of a display image. */ -typedef struct hwc_layer_list_1 { +typedef struct hwc_display_contents_1 { + /* File descriptor referring to a Sync HAL fence object which will signal + * when this display image is no longer visible, i.e. when the following + * set() takes effect. The fence object is created and returned by the set + * call; this field will be -1 on entry to prepare and set. SurfaceFlinger + * will close the returned file descriptor. + */ + int flipFenceFd; + + /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition. + * They aren't relevant to prepare. The set call should commit this surface + * atomically to the display along with any overlay layers. + */ + hwc_display_t dpy; + hwc_surface_t sur; + + /* List of layers that will be composed on the display. The buffer handles + * in the list will be unique. If numHwLayers is 0 and/or hwLayers is NULL, + * all composition will be performed by SurfaceFlinger. + */ uint32_t flags; size_t numHwLayers; hwc_layer_1_t hwLayers[0]; -} hwc_layer_list_1_t; - -/* This represents a display, typically an EGLDisplay object */ -typedef void* hwc_display_t; - -/* This represents a surface, typically an EGLSurface object */ -typedef void* hwc_surface_t; +} hwc_display_contents_1_t; /* see hwc_composer_device::registerProcs() * Any of the callbacks can be NULL, in which case the corresponding @@ -262,9 +284,10 @@ typedef struct hwc_procs { /* * (*vsync)() is called by the h/w composer HAL when a vsync event is - * received and HWC_EVENT_VSYNC is enabled (see: hwc_event_control). + * received and HWC_EVENT_VSYNC is enabled on a display + * (see: hwc_event_control). * - * the "zero" parameter must always be 0. + * the "dpy" parameter indicates which display the vsync event is for. * the "timestamp" parameter is the system monotonic clock timestamp in * nanosecond of when the vsync event happened. * @@ -278,9 +301,8 @@ typedef struct hwc_procs { * hwc_composer_device.set(..., 0, 0, 0) (screen off). The implementation * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. - * */ - void (*vsync)(struct hwc_procs* procs, int zero, int64_t timestamp); + void (*vsync)(struct hwc_procs* procs, int dpy, int64_t timestamp); } hwc_procs_t; @@ -299,72 +321,55 @@ typedef struct hwc_composer_device_1 { * * (*prepare)() can be called more than once, the last call prevails. * - * The HWC responds by setting the compositionType field to either - * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for - * this layer is handled by SurfaceFlinger with OpenGL ES, in the later - * case, the HWC will have to handle this layer's composition. + * The HWC responds by setting the compositionType field in each layer to + * either HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the + * composition for the layer is handled by SurfaceFlinger with OpenGL ES, + * in the later case, the HWC will have to handle the layer's composition. * * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the * list's geometry has changed, that is, when more than just the buffer's * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * - * a NULL list parameter or a numHwLayers of zero indicates that the - * entire composition will be handled by SurfaceFlinger with OpenGL ES. - * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. */ int (*prepare)(struct hwc_composer_device_1 *dev, - hwc_layer_list_1_t* list); + size_t numDisplays, hwc_display_contents_1_t** displays); /* * (*set)() is used in place of eglSwapBuffers(), and assumes the same * functionality, except it also commits the work list atomically with * the actual eglSwapBuffers(). * - * The list parameter is guaranteed to be the same as the one returned - * from the last call to (*prepare)(). - * - * When this call returns the caller assumes that: + * The layer lists are guaranteed to be the same as the ones returned from + * the last call to (*prepare)(). * - * - the display will be updated in the near future with the content - * of the work list, without artifacts during the transition from the - * previous frame. + * When this call returns the caller assumes that the displays will be + * updated in the near future with the content of their work lists, without + * artifacts during the transition from the previous frame. * - * - all objects are available for immediate access or destruction, in - * particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer. - * Note that this means that immediately accessing (potentially from a - * different process) a buffer used in this call will not result in - * screen corruption, the driver must apply proper synchronization or - * scheduling (eg: block the caller, such as gralloc_module_t::lock(), - * OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work - * after the buffer is freed from the actual composition). - * - * a NULL list parameter or a numHwLayers of zero indicates that the - * entire composition has been handled by SurfaceFlinger with OpenGL ES. + * A display with a NULL layer list or a numHwLayers of zero indicates that + * the entire composition has been handled by SurfaceFlinger with OpenGL ES. * In this case, (*set)() behaves just like eglSwapBuffers(). * - * dpy, sur, and list are set to NULL to indicate that the screen is - * turning off. This happens WITHOUT prepare() being called first. - * This is a good time to free h/w resources and/or power - * the relevant h/w blocks down. + * The dpy, surf, and layers fields are set to NULL to indicate that the + * screen is turning off. This happens WITHOUT prepare() being called first. + * This is a good time to free h/w resources and/or power down the relevant + * h/w blocks. * * IMPORTANT NOTE: there is an implicit layer containing opaque black - * pixels behind all the layers in the list. - * It is the responsibility of the hwcomposer module to make - * sure black pixels are output (or blended from). + * pixels behind all the layers in the list. It is the responsibility of + * the hwcomposer module to make sure black pixels are output (or blended + * from). * * returns: 0 on success. An negative error code on error: * HWC_EGL_ERROR: eglGetError() will provide the proper error code * Another code for non EGL errors. - * */ int (*set)(struct hwc_composer_device_1 *dev, - hwc_display_t dpy, - hwc_surface_t sur, - hwc_layer_list_1_t* list); + size_t numDisplays, hwc_display_contents_1_t** displays); /* * This field is OPTIONAL and can be NULL. diff --git a/modules/hwcomposer/hwcomposer.cpp b/modules/hwcomposer/hwcomposer.cpp index 0e49e4c..f0a5512 100644 --- a/modules/hwcomposer/hwcomposer.cpp +++ b/modules/hwcomposer/hwcomposer.cpp @@ -67,26 +67,26 @@ static void dump_layer(hwc_layer_1_t const* l) { l->displayFrame.bottom); } -static int hwc_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) { - if (list && (list->flags & HWC_GEOMETRY_CHANGED)) { - for (size_t i=0 ; inumHwLayers ; i++) { +static int hwc_prepare(hwc_composer_device_1_t *dev, + size_t numDisplays, hwc_display_contents_1_t** displays) { + if (displays && (displays[0]->flags & HWC_GEOMETRY_CHANGED)) { + for (size_t i=0 ; inumHwLayers ; i++) { //dump_layer(&list->hwLayers[i]); - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; } } return 0; } static int hwc_set(hwc_composer_device_1_t *dev, - hwc_display_t dpy, - hwc_surface_t sur, - hwc_layer_list_1_t* list) + size_t numDisplays, hwc_display_contents_1_t** displays) { //for (size_t i=0 ; inumHwLayers ; i++) { // dump_layer(&list->hwLayers[i]); //} - EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)displays[0]->dpy, + (EGLSurface)displays[0]->sur); if (!sucess) { return HWC_EGL_ERROR; } -- cgit v1.1 From 47bf3d7ea5f6c98e615e0a1f93497d241c79cc05 Mon Sep 17 00:00:00 2001 From: John Grossman Date: Tue, 17 Jul 2012 11:54:04 -0700 Subject: Extend the audio HAL interface to support get/set master mute (cherry picked from commit d245968b7ef0be5c776c9aefff3eca9e293d1b35) > Extend the audio HAL interface to support get/set master mute > > Hand merge from ics-aah > > > Extend the audio HAL interface to support get/set master mute: DO NOT MERGE > > > > Extend the audio HAL interface to allow HALs to optionally support HW > > level master mute. This follows the same pattern as master volume and > > is part of the fix for bug 6828363. Because of the divergences > > between ICS and master, this change will need to be merged by hand. > > > > Signed-off-by: John Grossman > > Change-Id: Ica6f5e37e13d13dde60463966f41f271ffa104fd > > Change-Id: I5e7aea6d7da0012dcc077281f9077fc04cfb9889 > Signed-off-by: John Grossman Change-Id: I2011cc5bc41ca7081ce255a4bfba65f36f899bc4 Signed-off-by: John Grossman --- include/hardware/audio.h | 17 ++++++++++++++++- modules/audio/audio_hw.c | 15 +++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/hardware/audio.h b/include/hardware/audio.h index 0a917e2..26e9ea9 100644 --- a/include/hardware/audio.h +++ b/include/hardware/audio.h @@ -352,7 +352,7 @@ struct audio_hw_device { * master volume control. AudioFlinger will query this value from the * primary audio HAL when the service starts and use the value for setting * the initial master volume across all HALs. HALs which do not support - * this method should may leave it set to NULL. + * this method may leave it set to NULL. */ int (*get_master_volume)(struct audio_hw_device *dev, float *volume); @@ -407,6 +407,21 @@ struct audio_hw_device { /** This method dumps the state of the audio hardware */ int (*dump)(const struct audio_hw_device *dev, int fd); + + /** + * set the audio mute status for all audio activities. If any value other + * than 0 is returned, the software mixer will emulate this capability. + */ + int (*set_master_mute)(struct audio_hw_device *dev, bool mute); + + /** + * Get the current master mute status for the HAL, if the HAL supports + * master mute control. AudioFlinger will query this value from the primary + * audio HAL when the service starts and use the value for setting the + * initial master mute across all HALs. HALs which do not support this + * method may leave it set to NULL. + */ + int (*get_master_mute)(struct audio_hw_device *dev, bool *mute); }; typedef struct audio_hw_device audio_hw_device_t; diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c index 15e9920..e4fb711 100644 --- a/modules/audio/audio_hw.c +++ b/modules/audio/audio_hw.c @@ -287,8 +287,17 @@ static int adev_set_master_volume(struct audio_hw_device *dev, float volume) return -ENOSYS; } -static int adev_get_master_volume(struct audio_hw_device *dev, - float *volume) +static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) +{ + return -ENOSYS; +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +{ + return -ENOSYS; +} + +static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) { return -ENOSYS; } @@ -416,6 +425,8 @@ static int adev_open(const hw_module_t* module, const char* name, adev->device.set_voice_volume = adev_set_voice_volume; adev->device.set_master_volume = adev_set_master_volume; adev->device.get_master_volume = adev_get_master_volume; + adev->device.set_master_mute = adev_set_master_mute; + adev->device.get_master_mute = adev_get_master_mute; adev->device.set_mode = adev_set_mode; adev->device.set_mic_mute = adev_set_mic_mute; adev->device.get_mic_mute = adev_get_mic_mute; -- cgit v1.1 From ac3f7e195cadcf1f826340976a228fd5bbcdb807 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 31 Jul 2012 15:18:32 -0700 Subject: Simplify prepare and set semantics (comments only) Documentation updated for semantic changes vs. HWC 0.x: * Prepare won't be called with NULL pointers. This used to be used to disable hardware composition, though that wasn't documented. Now we'll call prepare with non-NULL pointers but the layer list will have zero layers. * Set won't be called with NULL pointers. This used to cause the display to turn off; that is now done by calling the blank() method, which is no longer optional. Change-Id: I9c69dc34f64e499a5ba5f8729836e7c216f8c733 --- include/hardware/hwcomposer.h | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 11176ec..895c695 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -75,24 +75,19 @@ typedef struct hwc_methods_1 { * returns -EINVAL if the "event" parameter is not one of the value above * or if the "enabled" parameter is not 0 or 1. */ - int (*eventControl)( struct hwc_composer_device_1* dev, int dpy, int event, int enabled); /* - * This field is OPTIONAL and can be NULL. - * * blank(..., blank) * Blanks or unblanks a display's screen. * * Turns the screen off when blank is nonzero, on when blank is zero. - * Blanking may also be triggered by a call to set..., 0, 0, 0). Multiple - * sequential calls with the same blank value must be supported. + * Multiple sequential calls with the same blank value must be supported. * * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); } hwc_methods_1_t; @@ -257,8 +252,8 @@ typedef struct hwc_display_contents_1 { hwc_surface_t sur; /* List of layers that will be composed on the display. The buffer handles - * in the list will be unique. If numHwLayers is 0 and/or hwLayers is NULL, - * all composition will be performed by SurfaceFlinger. + * in the list will be unique. If numHwLayers is 0, all composition will be + * performed by SurfaceFlinger. */ uint32_t flags; size_t numHwLayers; @@ -331,6 +326,9 @@ typedef struct hwc_composer_device_1 { * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * + * The numDisplays parameter will always be greater than zero, displays + * will be non-NULL, and the array entries will be non-NULL. + * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be * handled by the HWC. @@ -350,14 +348,12 @@ typedef struct hwc_composer_device_1 { * updated in the near future with the content of their work lists, without * artifacts during the transition from the previous frame. * - * A display with a NULL layer list or a numHwLayers of zero indicates that - * the entire composition has been handled by SurfaceFlinger with OpenGL ES. - * In this case, (*set)() behaves just like eglSwapBuffers(). + * A display with zero layers indicates that the entire composition has + * been handled by SurfaceFlinger with OpenGL ES. In this case, (*set)() + * behaves just like eglSwapBuffers(). * - * The dpy, surf, and layers fields are set to NULL to indicate that the - * screen is turning off. This happens WITHOUT prepare() being called first. - * This is a good time to free h/w resources and/or power down the relevant - * h/w blocks. + * The numDisplays parameter will always be greater than zero, displays + * will be non-NULL, and the array entries will be non-NULL. * * IMPORTANT NOTE: there is an implicit layer containing opaque black * pixels behind all the layers in the list. It is the responsibility of @@ -409,7 +405,7 @@ typedef struct hwc_composer_device_1 { void* reserved_proc[4]; /* - * This field is OPTIONAL and can be NULL. + * This field is REQUIRED and must not be NULL. */ hwc_methods_1_t const *methods; -- cgit v1.1 From 8467a6d2918274295212d07fc6e3894f6bc5d623 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Wed, 8 Aug 2012 17:04:40 -0700 Subject: Enhance keymaster tests Check the key values of successful attempts. For imported keys, the key values should match the input values when they're returned. For generated keys, the modulus size should be correct and the public exponent should be correct. Bug: 6736252 Bug: http://code.google.com/p/android/issues/detail?id=34212 Change-Id: I37ed97d36ebfbe4301b43426129928bcb53c39f8 --- tests/keymaster/Android.mk | 2 + tests/keymaster/keymaster_test.cpp | 132 ++++++++++++++++++++++++++----------- 2 files changed, 97 insertions(+), 37 deletions(-) diff --git a/tests/keymaster/Android.mk b/tests/keymaster/Android.mk index 2661211..e53e67f 100644 --- a/tests/keymaster/Android.mk +++ b/tests/keymaster/Android.mk @@ -10,11 +10,13 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES := \ bionic \ external/gtest/include \ + external/openssl/include \ external/stlport/stlport LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ + libcrypto \ libstlport \ libhardware diff --git a/tests/keymaster/keymaster_test.cpp b/tests/keymaster/keymaster_test.cpp index f4cfcd2..dd24fcb 100644 --- a/tests/keymaster/keymaster_test.cpp +++ b/tests/keymaster/keymaster_test.cpp @@ -22,6 +22,10 @@ #include +#include +#include +#include + #include #include @@ -93,6 +97,34 @@ private: keymaster_device_t** mDevice; }; +struct BIGNUM_Delete { + void operator()(BIGNUM* p) const { + BN_free(p); + } +}; +typedef UniquePtr Unique_BIGNUM; + +struct EVP_PKEY_Delete { + void operator()(EVP_PKEY* p) const { + EVP_PKEY_free(p); + } +}; +typedef UniquePtr Unique_EVP_PKEY; + +struct PKCS8_PRIV_KEY_INFO_Delete { + void operator()(PKCS8_PRIV_KEY_INFO* p) const { + PKCS8_PRIV_KEY_INFO_free(p); + } +}; +typedef UniquePtr Unique_PKCS8_PRIV_KEY_INFO; + +struct RSA_Delete { + void operator()(RSA* p) const { + RSA_free(p); + } +}; +typedef UniquePtr Unique_RSA; + /* * DER-encoded PKCS#8 format RSA key. Generated using: * @@ -209,8 +241,8 @@ static uint8_t TEST_KEY_1[] = { static unsigned char BOGUS_KEY_1[] = { 0xFF, 0xFF, 0xFF, 0xFF }; -class KeymasterTest : public testing::Test { -protected: +class KeymasterBaseTest : public ::testing::Test { +public: static void SetUpTestCase() { const hw_module_t* mod; ASSERT_EQ(0, hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod)) @@ -241,22 +273,24 @@ protected: ASSERT_EQ(0, keymaster_close(sDevice)); } - virtual void SetUp() { - } +protected: + static keymaster_device_t* sDevice; +}; - virtual void TearDown() { - } +keymaster_device_t* KeymasterBaseTest::sDevice = NULL; - static keymaster_device_t* sDevice; +class KeymasterTest : public KeymasterBaseTest { }; -keymaster_device_t* KeymasterTest::sDevice = NULL; +class KeymasterGenerateTest : public KeymasterBaseTest, + public ::testing::WithParamInterface { +}; -TEST_F(KeymasterTest, GenerateKeyPair_RSA_512_Success) { +TEST_P(KeymasterGenerateTest, GenerateKeyPair_RSA_Success) { keymaster_keypair_t key_type = TYPE_RSA; keymaster_rsa_keygen_params_t params = { - modulus_size: 512, - public_exponent: 0x10001L, + modulus_size: GetParam(), + public_exponent: RSA_F4, }; uint8_t* key_blob; @@ -266,40 +300,39 @@ TEST_F(KeymasterTest, GenerateKeyPair_RSA_512_Success) { sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) << "Should generate an RSA key with 512 bit modulus size"; UniqueKey key(&sDevice, key_blob, key_blob_length); -} -TEST_F(KeymasterTest, GenerateKeyPair_RSA_1024_Success) { - keymaster_keypair_t key_type = TYPE_RSA; - keymaster_rsa_keygen_params_t params = { - modulus_size: 1024, - public_exponent: 0x3L, - }; + uint8_t* x509_data = NULL; + size_t x509_data_length; + EXPECT_EQ(0, + sDevice->get_keypair_public(sDevice, key_blob, key_blob_length, + &x509_data, &x509_data_length)) + << "Should be able to retrieve RSA public key successfully"; + UniqueBlob x509_blob(x509_data, x509_data_length); + ASSERT_FALSE(x509_blob.get() == NULL) + << "X509 data should be allocated"; - uint8_t* key_blob; - size_t key_blob_length; + const unsigned char *tmp = static_cast(x509_blob.get()); + Unique_EVP_PKEY actual(d2i_PUBKEY((EVP_PKEY**) NULL, &tmp, + static_cast(x509_blob.length()))); - EXPECT_EQ(0, - sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) - << "Should generate an RSA key with 2048 bit modulus size"; - UniqueKey key(&sDevice, key_blob, key_blob_length); -} + ASSERT_EQ(EVP_PKEY_RSA, EVP_PKEY_type(actual.get()->type)) + << "Generated key type should be of type RSA"; -TEST_F(KeymasterTest, GenerateKeyPair_RSA_2048_Success) { - keymaster_keypair_t key_type = TYPE_RSA; - keymaster_rsa_keygen_params_t params = { - modulus_size: 2048, - public_exponent: 0x3L, - }; + Unique_RSA rsa(EVP_PKEY_get1_RSA(actual.get())); + ASSERT_FALSE(rsa.get() == NULL) + << "Should be able to extract RSA key from EVP_PKEY"; - uint8_t* key_blob; - size_t key_blob_length; + EXPECT_EQ(static_cast(RSA_F4), BN_get_word(rsa.get()->e)) + << "Exponent should be RSA_F4"; - EXPECT_EQ(0, - sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) - << "Should generate an RSA key with 2048 bit modulus size"; - UniqueKey key(&sDevice, key_blob, key_blob_length); + EXPECT_EQ(GetParam() / 8, static_cast(RSA_size(rsa.get()))) + << "Modulus size should be the specified parameter"; } +INSTANTIATE_TEST_CASE_P(RSA, + KeymasterGenerateTest, + ::testing::Values(512, 1024, 2048)); + TEST_F(KeymasterTest, GenerateKeyPair_RSA_NullParams_Failure) { keymaster_keypair_t key_type = TYPE_RSA; @@ -331,6 +364,31 @@ TEST_F(KeymasterTest, ImportKeyPair_RSA_Success) { &key_blob, &key_blob_length)) << "Should successfully import an RSA key"; UniqueKey key(&sDevice, key_blob, key_blob_length); + + uint8_t* x509_data; + size_t x509_data_length; + EXPECT_EQ(0, + sDevice->get_keypair_public(sDevice, key_blob, key_blob_length, + &x509_data, &x509_data_length)) + << "Should be able to retrieve RSA public key successfully"; + UniqueBlob x509_blob(x509_data, x509_data_length); + + const unsigned char *tmp = static_cast(x509_blob.get()); + Unique_EVP_PKEY actual(d2i_PUBKEY((EVP_PKEY**) NULL, &tmp, + static_cast(x509_blob.length()))); + + EXPECT_EQ(EVP_PKEY_type(actual.get()->type), EVP_PKEY_RSA) + << "Generated key type should be of type RSA"; + + const unsigned char *expectedTmp = static_cast(TEST_KEY_1); + Unique_PKCS8_PRIV_KEY_INFO expectedPkcs8( + d2i_PKCS8_PRIV_KEY_INFO((PKCS8_PRIV_KEY_INFO**) NULL, &expectedTmp, + sizeof(TEST_KEY_1))); + + Unique_EVP_PKEY expected(EVP_PKCS82PKEY(expectedPkcs8.get())); + + EXPECT_EQ(1, EVP_PKEY_cmp(expected.get(), actual.get())) + << "Expected and actual keys should match"; } TEST_F(KeymasterTest, ImportKeyPair_BogusKey_Failure) { -- cgit v1.1 From f7a60c464a03f251deb87489d48d2249e6d31ff2 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 3 Aug 2012 10:56:57 -0700 Subject: Camera2: Add ZSL pixel format, AF CANCEL trigger, lots of docs - Add CAMERA2_HAL_PIXEL_FORMAT_ZSL - Add CAMERA2_TRIGGER_CANCEL_AUTOFOCUS - Add documentation to describe how AUTOFOCUS and CANCEL_AUTOFOCUS triggers interact with AF state, mode, and notifications. - Other minor edits Bug: 6243944 Change-Id: I679c40cfe08e62d3a5851839f748fe2292bbfae7 --- include/hardware/camera2.h | 122 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index f3e4ba4..518130b 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -96,15 +96,22 @@ typedef struct camera2_stream_ops { } camera2_stream_ops_t; -/** - * Special pixel format value used to indicate that the framework does not care - * what exact pixel format is to be used for an output stream. The device HAL is - * free to select any pixel format, platform-specific and otherwise, and this - * opaque value will be passed on to the platform gralloc module when buffers - * need to be allocated for the stream. - */ enum { - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = -1 + /** + * Special pixel format value used to indicate that the framework does not care + * what exact pixel format is to be used for an output stream. The device HAL is + * free to select any pixel format, platform-specific and otherwise, and this + * opaque value will be passed on to the platform gralloc module when buffers + * need to be allocated for the stream. + */ + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = -1, + /** + * Special pixel format value used to indicate that the framework will use + * the output buffers for zero-shutter-lag mode; these buffers should be + * efficient to produce at full sensor resolution, and efficient to send + * into a reprocess stream for final output processing. + */ + CAMERA2_HAL_PIXEL_FORMAT_ZSL = -2 }; /** @@ -278,15 +285,16 @@ enum { /** * The autofocus routine has changed state. Argument ext1 contains the new * state; the values are the same as those for the metadata field - * android.control.afState. Ext2 contains the latest value passed to - * trigger_action(CAMERA2_TRIGGER_AUTOFOCUS), or 0 if that method has not - * been called. + * android.control.afState. Ext2 contains the latest trigger ID passed to + * trigger_action(CAMERA2_TRIGGER_AUTOFOCUS) or + * trigger_action(CAMERA2_TRIGGER_CANCEL_AUTOFOCUS), or 0 if trigger has not + * been called with either of those actions. */ CAMERA2_MSG_AUTOFOCUS = 0x0020, /** * The autoexposure routine has changed state. Argument ext1 contains the * new state; the values are the same as those for the metadata field - * android.control.aeState. Ext2 containst the latest value passed to + * android.control.aeState. Ext2 contains the latest trigger ID value passed to * trigger_action(CAMERA2_TRIGGER_PRECAPTURE_METERING), or 0 if that method * has not been called. */ @@ -294,7 +302,9 @@ enum { /** * The auto-whitebalance routine has changed state. Argument ext1 contains * the new state; the values are the same as those for the metadata field - * android.control.awbState. + * android.control.awbState. Ext2 contains the latest trigger ID passed to + * trigger_action(CAMERA2_TRIGGER_PRECAPTURE_METERING), or 0 if that method + * has not been called. */ CAMERA2_MSG_AUTOWB = 0x0022 }; @@ -350,23 +360,87 @@ enum { /** * Trigger an autofocus cycle. The effect of the trigger depends on the * autofocus mode in effect when the trigger is received, which is the mode - * listed in the latest capture request to be dequeued. If the mode is off, - * the trigger has no effect. If autofocus is already scanning, the trigger - * has no effect. In AUTO, MACRO, or CONTINUOUS_* modes, the trigger - * otherwise begins an appropriate scan of the scene for focus. The state of + * listed in the latest capture request to be dequeued by the HAL. If the + * mode is OFF, EDOF, or FIXED, the trigger has no effect. In AUTO, MACRO, + * or CONTINUOUS_* modes, see below for the expected behavior. The state of * the autofocus cycle can be tracked in android.control.afMode and the - * corresponding notification. Ext1 is an id that must be returned in - * subsequent auto-focus state change notifications. + * corresponding notifications. + * + ** + * In AUTO or MACRO mode, the AF state transitions (and notifications) + * when calling with trigger ID = N with the previous ID being K are: + * + * Initial state Transitions + * INACTIVE (K) -> ACTIVE_SCAN (N) -> AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * AF_FOCUSED (K) -> ACTIVE_SCAN (N) -> AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * AF_NOT_FOCUSED (K) -> ACTIVE_SCAN (N) -> AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * ACTIVE_SCAN (K) -> AF_FOCUSED(N) or AF_NOT_FOCUSED(N) + * PASSIVE_SCAN (K) Not used in AUTO/MACRO mode + * PASSIVE_FOCUSED (K) Not used in AUTO/MACRO mode + * + ** + * In CONTINUOUS_PICTURE mode, triggering AF must lock the AF to the current + * lens position and transition the AF state to either AF_FOCUSED or + * NOT_FOCUSED. If a passive scan is underway, that scan must complete and + * then lock the lens position and change AF state. TRIGGER_CANCEL_AUTOFOCUS + * will allow the AF to restart its operation. + * + * Initial state Transitions + * INACTIVE (K) -> immediate AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * PASSIVE_FOCUSED (K) -> immediate AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * PASSIVE_SCAN (K) -> AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * AF_FOCUSED (K) no effect except to change next notification ID to N + * AF_NOT_FOCUSED (K) no effect except to change next notification ID to N + * + ** + * In CONTINUOUS_VIDEO mode, triggering AF must lock the AF to the current + * lens position and transition the AF state to either AF_FOCUSED or + * NOT_FOCUSED. If a passive scan is underway, it must immediately halt, in + * contrast with CONTINUOUS_PICTURE mode. TRIGGER_CANCEL_AUTOFOCUS will + * allow the AF to restart its operation. + * + * Initial state Transitions + * INACTIVE (K) -> immediate AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * PASSIVE_FOCUSED (K) -> immediate AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * PASSIVE_SCAN (K) -> immediate AF_FOCUSED (N) or AF_NOT_FOCUSED (N) + * AF_FOCUSED (K) no effect except to change next notification ID to N + * AF_NOT_FOCUSED (K) no effect except to change next notification ID to N + * + * Ext1 is an ID that must be returned in subsequent auto-focus state change + * notifications through camera2_notify_callback() and stored in + * android.control.afTriggerId. */ CAMERA2_TRIGGER_AUTOFOCUS = 0x0001, /** + * Send a cancel message to the autofocus algorithm. The effect of the + * cancellation depends on the autofocus mode in effect when the trigger is + * received, which is the mode listed in the latest capture request to be + * dequeued by the HAL. If the AF mode is OFF or EDOF, the cancel has no + * effect. For other modes, the lens should return to its default position, + * any current autofocus scan must be canceled, and the AF state should be + * set to INACTIVE. + * + * The state of the autofocus cycle can be tracked in android.control.afMode + * and the corresponding notification. Continuous autofocus modes may resume + * focusing operations thereafter exactly as if the camera had just been set + * to a continuous AF mode. + * + * Ext1 is an ID that must be returned in subsequent auto-focus state change + * notifications through camera2_notify_callback() and stored in + * android.control.afTriggerId. + */ + CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, + /** * Trigger a pre-capture metering cycle, which may include firing the flash * to determine proper capture parameters. Typically, this trigger would be * fired for a half-depress of a camera shutter key, or before a snapshot * capture in general. The state of the metering cycle can be tracked in * android.control.aeMode and the corresponding notification. If the - * auto-exposure mode is OFF, the trigger does nothing. Ext1 is an id that - * must be returned in subsequent auto-exposure state change notifications. + * auto-exposure mode is OFF, the trigger does nothing. + * + * Ext1 is an ID that must be returned in subsequent + * auto-exposure/auto-white balance state change notifications through + * camera2_notify_callback() and stored in android.control.aePrecaptureId. */ CAMERA2_TRIGGER_PRECAPTURE_METERING }; @@ -395,7 +469,7 @@ enum { CAMERA2_TEMPLATE_VIDEO_SNAPSHOT, /** * Zero-shutter-lag mode. Application will request preview and - * full-resolution YUV data for each frame, and reprocess it to JPEG when a + * full-resolution data for each frame, and reprocess it to JPEG when a * still image is requested by user. Settings should provide highest-quality * full-resolution images without compromising preview frame rate. 3A on * auto. @@ -629,8 +703,8 @@ typedef struct camera2_device_ops { */ int (*trigger_action)(const struct camera2_device *, uint32_t trigger_id, - int ext1, - int ext2); + int32_t ext1, + int32_t ext2); /** * Notification callback setup -- cgit v1.1 -- cgit v1.1 From 53c71df3bc6982393296ad2614095039c61e6a42 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Wed, 8 Aug 2012 17:04:40 -0700 Subject: Enhance keymaster tests Check the key values of successful attempts. For imported keys, the key values should match the input values when they're returned. For generated keys, the modulus size should be correct and the public exponent should be correct. (cherry-pick of 280dbc7e691304cccb2a32683d1a5a13cc188e41) Bug: 6736252 Bug: http://code.google.com/p/android/issues/detail?id=34212 Change-Id: Ieaf922ec83e0b81feb08f6ac3977e4aabd09ce14 --- tests/keymaster/Android.mk | 2 + tests/keymaster/keymaster_test.cpp | 132 ++++++++++++++++++++++++++----------- 2 files changed, 97 insertions(+), 37 deletions(-) diff --git a/tests/keymaster/Android.mk b/tests/keymaster/Android.mk index 2661211..e53e67f 100644 --- a/tests/keymaster/Android.mk +++ b/tests/keymaster/Android.mk @@ -10,11 +10,13 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES := \ bionic \ external/gtest/include \ + external/openssl/include \ external/stlport/stlport LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ + libcrypto \ libstlport \ libhardware diff --git a/tests/keymaster/keymaster_test.cpp b/tests/keymaster/keymaster_test.cpp index f4cfcd2..dd24fcb 100644 --- a/tests/keymaster/keymaster_test.cpp +++ b/tests/keymaster/keymaster_test.cpp @@ -22,6 +22,10 @@ #include +#include +#include +#include + #include #include @@ -93,6 +97,34 @@ private: keymaster_device_t** mDevice; }; +struct BIGNUM_Delete { + void operator()(BIGNUM* p) const { + BN_free(p); + } +}; +typedef UniquePtr Unique_BIGNUM; + +struct EVP_PKEY_Delete { + void operator()(EVP_PKEY* p) const { + EVP_PKEY_free(p); + } +}; +typedef UniquePtr Unique_EVP_PKEY; + +struct PKCS8_PRIV_KEY_INFO_Delete { + void operator()(PKCS8_PRIV_KEY_INFO* p) const { + PKCS8_PRIV_KEY_INFO_free(p); + } +}; +typedef UniquePtr Unique_PKCS8_PRIV_KEY_INFO; + +struct RSA_Delete { + void operator()(RSA* p) const { + RSA_free(p); + } +}; +typedef UniquePtr Unique_RSA; + /* * DER-encoded PKCS#8 format RSA key. Generated using: * @@ -209,8 +241,8 @@ static uint8_t TEST_KEY_1[] = { static unsigned char BOGUS_KEY_1[] = { 0xFF, 0xFF, 0xFF, 0xFF }; -class KeymasterTest : public testing::Test { -protected: +class KeymasterBaseTest : public ::testing::Test { +public: static void SetUpTestCase() { const hw_module_t* mod; ASSERT_EQ(0, hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod)) @@ -241,22 +273,24 @@ protected: ASSERT_EQ(0, keymaster_close(sDevice)); } - virtual void SetUp() { - } +protected: + static keymaster_device_t* sDevice; +}; - virtual void TearDown() { - } +keymaster_device_t* KeymasterBaseTest::sDevice = NULL; - static keymaster_device_t* sDevice; +class KeymasterTest : public KeymasterBaseTest { }; -keymaster_device_t* KeymasterTest::sDevice = NULL; +class KeymasterGenerateTest : public KeymasterBaseTest, + public ::testing::WithParamInterface { +}; -TEST_F(KeymasterTest, GenerateKeyPair_RSA_512_Success) { +TEST_P(KeymasterGenerateTest, GenerateKeyPair_RSA_Success) { keymaster_keypair_t key_type = TYPE_RSA; keymaster_rsa_keygen_params_t params = { - modulus_size: 512, - public_exponent: 0x10001L, + modulus_size: GetParam(), + public_exponent: RSA_F4, }; uint8_t* key_blob; @@ -266,40 +300,39 @@ TEST_F(KeymasterTest, GenerateKeyPair_RSA_512_Success) { sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) << "Should generate an RSA key with 512 bit modulus size"; UniqueKey key(&sDevice, key_blob, key_blob_length); -} -TEST_F(KeymasterTest, GenerateKeyPair_RSA_1024_Success) { - keymaster_keypair_t key_type = TYPE_RSA; - keymaster_rsa_keygen_params_t params = { - modulus_size: 1024, - public_exponent: 0x3L, - }; + uint8_t* x509_data = NULL; + size_t x509_data_length; + EXPECT_EQ(0, + sDevice->get_keypair_public(sDevice, key_blob, key_blob_length, + &x509_data, &x509_data_length)) + << "Should be able to retrieve RSA public key successfully"; + UniqueBlob x509_blob(x509_data, x509_data_length); + ASSERT_FALSE(x509_blob.get() == NULL) + << "X509 data should be allocated"; - uint8_t* key_blob; - size_t key_blob_length; + const unsigned char *tmp = static_cast(x509_blob.get()); + Unique_EVP_PKEY actual(d2i_PUBKEY((EVP_PKEY**) NULL, &tmp, + static_cast(x509_blob.length()))); - EXPECT_EQ(0, - sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) - << "Should generate an RSA key with 2048 bit modulus size"; - UniqueKey key(&sDevice, key_blob, key_blob_length); -} + ASSERT_EQ(EVP_PKEY_RSA, EVP_PKEY_type(actual.get()->type)) + << "Generated key type should be of type RSA"; -TEST_F(KeymasterTest, GenerateKeyPair_RSA_2048_Success) { - keymaster_keypair_t key_type = TYPE_RSA; - keymaster_rsa_keygen_params_t params = { - modulus_size: 2048, - public_exponent: 0x3L, - }; + Unique_RSA rsa(EVP_PKEY_get1_RSA(actual.get())); + ASSERT_FALSE(rsa.get() == NULL) + << "Should be able to extract RSA key from EVP_PKEY"; - uint8_t* key_blob; - size_t key_blob_length; + EXPECT_EQ(static_cast(RSA_F4), BN_get_word(rsa.get()->e)) + << "Exponent should be RSA_F4"; - EXPECT_EQ(0, - sDevice->generate_keypair(sDevice, key_type, ¶ms, &key_blob, &key_blob_length)) - << "Should generate an RSA key with 2048 bit modulus size"; - UniqueKey key(&sDevice, key_blob, key_blob_length); + EXPECT_EQ(GetParam() / 8, static_cast(RSA_size(rsa.get()))) + << "Modulus size should be the specified parameter"; } +INSTANTIATE_TEST_CASE_P(RSA, + KeymasterGenerateTest, + ::testing::Values(512, 1024, 2048)); + TEST_F(KeymasterTest, GenerateKeyPair_RSA_NullParams_Failure) { keymaster_keypair_t key_type = TYPE_RSA; @@ -331,6 +364,31 @@ TEST_F(KeymasterTest, ImportKeyPair_RSA_Success) { &key_blob, &key_blob_length)) << "Should successfully import an RSA key"; UniqueKey key(&sDevice, key_blob, key_blob_length); + + uint8_t* x509_data; + size_t x509_data_length; + EXPECT_EQ(0, + sDevice->get_keypair_public(sDevice, key_blob, key_blob_length, + &x509_data, &x509_data_length)) + << "Should be able to retrieve RSA public key successfully"; + UniqueBlob x509_blob(x509_data, x509_data_length); + + const unsigned char *tmp = static_cast(x509_blob.get()); + Unique_EVP_PKEY actual(d2i_PUBKEY((EVP_PKEY**) NULL, &tmp, + static_cast(x509_blob.length()))); + + EXPECT_EQ(EVP_PKEY_type(actual.get()->type), EVP_PKEY_RSA) + << "Generated key type should be of type RSA"; + + const unsigned char *expectedTmp = static_cast(TEST_KEY_1); + Unique_PKCS8_PRIV_KEY_INFO expectedPkcs8( + d2i_PKCS8_PRIV_KEY_INFO((PKCS8_PRIV_KEY_INFO**) NULL, &expectedTmp, + sizeof(TEST_KEY_1))); + + Unique_EVP_PKEY expected(EVP_PKCS82PKEY(expectedPkcs8.get())); + + EXPECT_EQ(1, EVP_PKEY_cmp(expected.get(), actual.get())) + << "Expected and actual keys should match"; } TEST_F(KeymasterTest, ImportKeyPair_BogusKey_Failure) { -- cgit v1.1 From 705d2912b70ae0dc8d035d475cf75f64c1a4c4b6 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 16 Aug 2012 14:45:06 -0700 Subject: hwc: update blank documentation to specify that blank is synchronous Change the documentation of the blank function in the hw composer to specify that the screen state transition must be complete when the function returns. Change-Id: Ibd0a9cdef13991c36cabada5fc0e4f7bb8fa7af9 --- include/hardware/hwcomposer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 895c695..91ee504 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -85,6 +85,8 @@ typedef struct hwc_methods_1 { * * Turns the screen off when blank is nonzero, on when blank is zero. * Multiple sequential calls with the same blank value must be supported. + * The screen state transition must be be complete when the function + * returns. * * returns 0 on success, negative on error. */ -- cgit v1.1 From d18c83fc044a5f1d74ebe59bea7763b75c4d00d7 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Thu, 16 Aug 2012 16:21:13 -0700 Subject: HWC 1.1: add FRAMEBUFFER_TARGET layer type Change-Id: I61965c343dceb4137bc439b49ea90ec13183b719 --- include/hardware/hwcomposer.h | 40 +++++++++++++++++++++++++------------- include/hardware/hwcomposer_defs.h | 4 ++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 895c695..d928054 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -113,20 +113,30 @@ typedef struct hwc_color { typedef struct hwc_layer_1 { /* - * initially set to HWC_FRAMEBUFFER or HWC_BACKGROUND. + * Initially set to HWC_FRAMEBUFFER, HWC_BACKGROUND, or + * HWC_FRAMEBUFFER_TARGET. + * * HWC_FRAMEBUFFER - * indicates the layer will be drawn into the framebuffer - * using OpenGL ES. - * The HWC can toggle this value to HWC_OVERLAY, to indicate - * it will handle the layer. + * Indicates the layer will be drawn into the framebuffer + * using OpenGL ES. The HWC can toggle this value to HWC_OVERLAY to + * indicate it will handle the layer. * * HWC_BACKGROUND - * indicates this is a special "background" layer. The only valid - * field is backgroundColor. HWC_BACKGROUND can only be used with - * HWC_API_VERSION >= 0.2 - * The HWC can toggle this value to HWC_FRAMEBUFFER, to indicate - * it CANNOT handle the background color + * Indicates this is a special "background" layer. The only valid field + * is backgroundColor. The HWC can toggle this value to HWC_FRAMEBUFFER + * to indicate it CANNOT handle the background color. + * + * HWC_FRAMEBUFFER_TARGET + * Indicates this layer is the framebuffer surface used as the target of + * OpenGL ES composition. If the HWC sets all other layers to HWC_OVERLAY + * or HWC_BACKGROUND, then no OpenGL ES composition will be done, and + * this layer should be ignored during set(); the HWC_SKIP_LAYER flag + * will indicate this case. * + * This flag (and the framebuffer surface layer) will only be used if the + * HWC version is HWC_DEVICE_API_VERSION_1_1 or higher. In older versions, + * the OpenGL ES target surface is communicated by the (dpy, sur) fields + * in hwc_compositor_device_1_t. */ int32_t compositionType; @@ -244,9 +254,13 @@ typedef struct hwc_display_contents_1 { */ int flipFenceFd; - /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition. - * They aren't relevant to prepare. The set call should commit this surface - * atomically to the display along with any overlay layers. + /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition for + * HWC versions before HWC_DEVICE_VERSION_1_1. They aren't relevant to + * prepare. The set call should commit this surface atomically to the + * display along with any overlay layers. + * + * For HWC_DEVICE_VERSION_1_1 and later, these will always be set to + * EGL_NO_DISPLAY and EGL_NO_SURFACE. */ hwc_display_t dpy; hwc_surface_t sur; diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index 02b8e50..28605d4 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -89,6 +89,10 @@ enum { /* this is the background layer. it's used to set the background color. * there is only a single background layer */ HWC_BACKGROUND = 2, + + /* this layer holds the result of compositing the HWC_FRAMEBUFFER layers. + * Added in HWC_DEVICE_API_VERSION_1_1. */ + HWC_FRAMEBUFFER_TARGET = 3, }; /* -- cgit v1.1 From f4e4624ef78fa72dd976b201c08ceb394564279c Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 21 Aug 2012 15:24:55 -0700 Subject: Define HWC_DEVICE_API_VERSION_1_1 Change-Id: I925e010fb6367979de9b7657607ea5b444820a7e --- include/hardware/hwcomposer_defs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index 28605d4..a5df8f0 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -34,6 +34,7 @@ __BEGIN_DECLS #define HWC_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION(0, 2) #define HWC_DEVICE_API_VERSION_0_3 HARDWARE_DEVICE_API_VERSION(0, 3) #define HWC_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0) +#define HWC_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION(1, 1) enum { /* hwc_composer_device_t::set failed in EGL */ -- cgit v1.1 From 43b51d9fdd7a447c9de7bf30960a1963c93ff5c3 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Wed, 22 Aug 2012 11:42:57 -0700 Subject: Add NUM_DISPLAY_TYPES query and refine display list semantics Change-Id: I740859bfa2b126edcdf06f7b2c8208770bc864f9 --- include/hardware/hwcomposer.h | 24 ++++++++++++++++++++---- include/hardware/hwcomposer_defs.h | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 27b9197..a6358e4 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -342,8 +342,16 @@ typedef struct hwc_composer_device_1 { * handles have been updated. Typically this happens (but is not limited to) * when a window is added, removed, resized or moved. * - * The numDisplays parameter will always be greater than zero, displays - * will be non-NULL, and the array entries will be non-NULL. + * For HWC 1.0, numDisplays will always be one, and displays[0] will be + * non-NULL. + * + * For HWC 1.1, numDisplays will always be HWC_NUM_DISPLAY_TYPES. Entries + * for unsupported or disabled/disconnected display types will be NULL. + * + * For HWC 1.2 and later, numDisplays will be HWC_NUM_DISPLAY_TYPES or more. + * The extra entries correspond to enabled virtual displays, and will be + * non-NULL. In HWC 1.2, support for one virtual display is required, and + * no more than one will be used. Future HWC versions might require more. * * returns: 0 on success. An negative error code on error. If an error is * returned, SurfaceFlinger will assume that none of the layer will be @@ -368,8 +376,16 @@ typedef struct hwc_composer_device_1 { * been handled by SurfaceFlinger with OpenGL ES. In this case, (*set)() * behaves just like eglSwapBuffers(). * - * The numDisplays parameter will always be greater than zero, displays - * will be non-NULL, and the array entries will be non-NULL. + * For HWC 1.0, numDisplays will always be one, and displays[0] will be + * non-NULL. + * + * For HWC 1.1, numDisplays will always be HWC_NUM_DISPLAY_TYPES. Entries + * for unsupported or disabled/disconnected display types will be NULL. + * + * For HWC 1.2 and later, numDisplays will be HWC_NUM_DISPLAY_TYPES or more. + * The extra entries correspond to enabled virtual displays, and will be + * non-NULL. In HWC 1.2, support for one virtual display is required, and + * no more than one will be used. Future HWC versions might require more. * * IMPORTANT NOTE: there is an implicit layer containing opaque black * pixels behind all the layers in the list. It is the responsibility of diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index a5df8f0..f0f97fc 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -139,6 +139,12 @@ enum { * returns the vsync period in nanosecond */ HWC_VSYNC_PERIOD = 1, + + /* + * availability: HWC_DEVICE_API_VERSION_1_1 + * returns a mask of supported display types + */ + HWC_DISPLAY_TYPES_SUPPORTED = 2, }; /* Allowed events for hwc_methods::eventControl() */ @@ -146,6 +152,18 @@ enum { HWC_EVENT_VSYNC = 0 }; +/* Display types and associated mask bits. */ +enum { + HWC_DISPLAY_PRIMARY = 0, + HWC_DISPLAY_EXTERNAL = 1, // HDMI, DP, etc. + HWC_NUM_DISPLAY_TYPES +}; + +enum { + HWC_DISPLAY_PRIMARY_BIT = 1 << HWC_DISPLAY_PRIMARY, + HWC_DISPLAY_EXTERNAL_BIT = 1 << HWC_DISPLAY_EXTERNAL, +}; + /*****************************************************************************/ __END_DECLS -- cgit v1.1 From 0a0a41653d82552e601980c8793fcb07e3863044 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 21 Aug 2012 12:06:28 -0700 Subject: Simplify and clean up legacy decisions During the HWC 0.x evolution, some fields were left optional or organized strangely to avoid breaking backwards compatibility. Since we're breaking it in the transition to HWC 1.0 anyway, we can clean these up a little. * The current callbacks are now registered immediately after the device is opened and guaranteed to be present, so the implementation can rely on them being present. * The hwc_methods_t structure is gone, with its two methods folded into the main hwc_composer_device_1_t. * All methods and callbacks are now required except dump(). New methods and callbacks we add in the future will still be optional for backwards compatibility. Change-Id: I5d58774a5144016993c12df3dd6ad2a5d746bee9 --- include/hardware/hwcomposer.h | 106 +++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index a6358e4..29ea54c 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -59,41 +59,6 @@ __BEGIN_DECLS */ #define HWC_HARDWARE_COMPOSER "composer" -struct hwc_composer_device_1; -typedef struct hwc_methods_1 { - - /* - * eventControl(..., event, enabled) - * Enables or disables h/w composer events for a display. - * - * eventControl can be called from any thread and takes effect - * immediately. - * - * Supported events are: - * HWC_EVENT_VSYNC - * - * returns -EINVAL if the "event" parameter is not one of the value above - * or if the "enabled" parameter is not 0 or 1. - */ - int (*eventControl)( - struct hwc_composer_device_1* dev, int dpy, - int event, int enabled); - - /* - * blank(..., blank) - * Blanks or unblanks a display's screen. - * - * Turns the screen off when blank is nonzero, on when blank is zero. - * Multiple sequential calls with the same blank value must be supported. - * The screen state transition must be be complete when the function - * returns. - * - * returns 0 on success, negative on error. - */ - int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); - -} hwc_methods_1_t; - typedef struct hwc_rect { int left; int top; @@ -190,6 +155,10 @@ typedef struct hwc_layer_1 { * fence to be signaled before returning, but the HWC must wait for * all buffers to be signaled before reading from them. * + * HWC_FRAMEBUFFER layers will never have an acquire fence, since + * reads from them are complete before the framebuffer is ready for + * display. + * * The HWC takes ownership of the acquireFenceFd and is responsible * for closing it when no longer needed. */ @@ -209,6 +178,10 @@ typedef struct hwc_layer_1 { * the blit completes, but the overlay layers can't be reused until * a subsequent frame has been displayed. * + * Since HWC doesn't read from HWC_FRAMEBUFFER layers, it shouldn't + * produce a release fence for them. The releaseFenceFd will be -1 + * for these layers when set() is called. + * * The HWC client taks ownership of the releaseFenceFd and is * responsible for closing it when no longer needed. */ @@ -278,8 +251,7 @@ typedef struct hwc_display_contents_1 { } hwc_display_contents_1_t; /* see hwc_composer_device::registerProcs() - * Any of the callbacks can be NULL, in which case the corresponding - * functionality is not supported. + * All of the callbacks are required and non-NULL unless otherwise noted. */ typedef struct hwc_procs { /* @@ -291,7 +263,7 @@ typedef struct hwc_procs { * it is safe to call invalidate() from any of hwc_composer_device * hooks, unless noted otherwise. */ - void (*invalidate)(struct hwc_procs* procs); + void (*invalidate)(const struct hwc_procs* procs); /* * (*vsync)() is called by the h/w composer HAL when a vsync event is @@ -313,7 +285,7 @@ typedef struct hwc_procs { * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. */ - void (*vsync)(struct hwc_procs* procs, int dpy, int64_t timestamp); + void (*vsync)(const struct hwc_procs* procs, int dpy, int64_t timestamp); } hwc_procs_t; @@ -400,31 +372,35 @@ typedef struct hwc_composer_device_1 { size_t numDisplays, hwc_display_contents_1_t** displays); /* - * This field is OPTIONAL and can be NULL. + * eventControl(..., event, enabled) + * Enables or disables h/w composer events for a display. * - * If non NULL it will be called by SurfaceFlinger on dumpsys + * eventControl can be called from any thread and takes effect + * immediately. + * + * Supported events are: + * HWC_EVENT_VSYNC + * + * returns -EINVAL if the "event" parameter is not one of the value above + * or if the "enabled" parameter is not 0 or 1. */ - void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len); + int (*eventControl)(struct hwc_composer_device_1* dev, int dpy, + int event, int enabled); /* - * This field is OPTIONAL and can be NULL. + * blank(..., blank) + * Blanks or unblanks a display's screen. * - * (*registerProcs)() registers a set of callbacks the h/w composer HAL - * can later use. It is FORBIDDEN to call any of the callbacks from - * within registerProcs(). registerProcs() must save the hwc_procs_t pointer - * which is needed when calling a registered callback. - * Each call to registerProcs replaces the previous set of callbacks. - * registerProcs is called with NULL to unregister all callbacks. + * Turns the screen off when blank is nonzero, on when blank is zero. + * Multiple sequential calls with the same blank value must be supported. + * The screen state transition must be be complete when the function + * returns. * - * Any of the callbacks can be NULL, in which case the corresponding - * functionality is not supported. + * returns 0 on success, negative on error. */ - void (*registerProcs)(struct hwc_composer_device_1* dev, - hwc_procs_t const* procs); + int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); /* - * This field is OPTIONAL and can be NULL. - * * Used to retrieve information about the h/w composer * * Returns 0 on success or -errno on error. @@ -432,14 +408,26 @@ typedef struct hwc_composer_device_1 { int (*query)(struct hwc_composer_device_1* dev, int what, int* value); /* - * Reserved for future use. Must be NULL. + * (*registerProcs)() registers callbacks that the h/w composer HAL can + * later use. It will be called immediately after the composer device is + * opened with non-NULL procs. It is FORBIDDEN to call any of the callbacks + * from within registerProcs(). registerProcs() must save the hwc_procs_t + * pointer which is needed when calling a registered callback. */ - void* reserved_proc[4]; + void (*registerProcs)(struct hwc_composer_device_1* dev, + hwc_procs_t const* procs); /* - * This field is REQUIRED and must not be NULL. + * This field is OPTIONAL and can be NULL. + * + * If non NULL it will be called by SurfaceFlinger on dumpsys */ - hwc_methods_1_t const *methods; + void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len); + + /* + * Reserved for future use. Must be NULL. + */ + void* reserved_proc[4]; } hwc_composer_device_1_t; -- cgit v1.1 From d959ec5297c19b9b8f1760c9237030bf931b5803 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 24 Aug 2012 12:32:17 -0700 Subject: Camera2: Make static_camera_characteristics const. Disallow modification to static characteristics structure, and clarify ownership and lifetime of the structure. Also update test code accordingly. Bug: 6243944 Change-Id: Ib8de5e9d6580187b21a5ae9a28a3d24f1d083f7b --- include/hardware/camera_common.h | 6 ++++-- tests/camera2/camera2.cpp | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h index 5459b6c..5697bda 100644 --- a/include/hardware/camera_common.h +++ b/include/hardware/camera_common.h @@ -135,7 +135,9 @@ struct camera_info { /** * The camera's fixed characteristics, which include all camera metadata in - * the android.*.info.* sections. + * the android.*.info.* sections. This should be a sorted metadata buffer, + * and may not be modified or freed by the caller. The pointer should remain + * valid for the lifetime of the camera module. * * Version information (based on camera_module_t.common.module_api_version): * @@ -150,7 +152,7 @@ struct camera_info { * otherwise. * */ - camera_metadata_t *static_camera_characteristics; + const camera_metadata_t *static_camera_characteristics; }; typedef struct camera_module { diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 05f61ef..29eef68 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -236,13 +236,13 @@ class Camera2Test: public testing::Test { } void getResolutionList(int32_t format, - int32_t **list, + const int32_t **list, size_t *count) { ALOGV("Getting resolutions for format %x", format); status_t res; if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { - camera_metadata_entry_t availableFormats; - res = find_camera_metadata_entry(mStaticInfo, + camera_metadata_ro_entry_t availableFormats; + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_FORMATS, &availableFormats); ASSERT_EQ(OK, res); @@ -255,17 +255,17 @@ class Camera2Test: public testing::Test { << "No support found for format 0x" << std::hex << format; } - camera_metadata_entry_t availableSizes; + camera_metadata_ro_entry_t availableSizes; if (format == HAL_PIXEL_FORMAT_RAW_SENSOR) { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_RAW_SIZES, &availableSizes); } else if (format == HAL_PIXEL_FORMAT_BLOB) { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_JPEG_SIZES, &availableSizes); } else { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, &availableSizes); } @@ -293,7 +293,7 @@ class Camera2Test: public testing::Test { } camera2_device *mDevice; - camera_metadata_t *mStaticInfo; + const camera_metadata_t *mStaticInfo; MetadataQueue mRequests; MetadataQueue mFrames; @@ -342,7 +342,7 @@ TEST_F(Camera2Test, Capture1Raw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - int32_t *rawResolutions; + const int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -456,7 +456,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - int32_t *rawResolutions; + const int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -618,7 +618,7 @@ TEST_F(Camera2Test, Capture1Jpeg) { sp jpegWaiter = new FrameWaiter(); jpegConsumer->setFrameAvailableListener(jpegWaiter); - int32_t *jpegResolutions; + const int32_t *jpegResolutions; size_t jpegResolutionsCount; int format = HAL_PIXEL_FORMAT_BLOB; -- cgit v1.1 From dde2a9d4b5129fa836d211a75f0040bf552c94c9 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Sun, 26 Aug 2012 14:44:38 -0700 Subject: Revert "Camera2: Make static_camera_characteristics const." Needs a third change that's not yet done with review. This reverts commit c9ec8a656b59912f496880d3a63c0decd490f09d Change-Id: Ic3e465e1308cbf107a250ec17b73a59a35e52f9f --- include/hardware/camera_common.h | 6 ++---- tests/camera2/camera2.cpp | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h index 5697bda..5459b6c 100644 --- a/include/hardware/camera_common.h +++ b/include/hardware/camera_common.h @@ -135,9 +135,7 @@ struct camera_info { /** * The camera's fixed characteristics, which include all camera metadata in - * the android.*.info.* sections. This should be a sorted metadata buffer, - * and may not be modified or freed by the caller. The pointer should remain - * valid for the lifetime of the camera module. + * the android.*.info.* sections. * * Version information (based on camera_module_t.common.module_api_version): * @@ -152,7 +150,7 @@ struct camera_info { * otherwise. * */ - const camera_metadata_t *static_camera_characteristics; + camera_metadata_t *static_camera_characteristics; }; typedef struct camera_module { diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 29eef68..05f61ef 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -236,13 +236,13 @@ class Camera2Test: public testing::Test { } void getResolutionList(int32_t format, - const int32_t **list, + int32_t **list, size_t *count) { ALOGV("Getting resolutions for format %x", format); status_t res; if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { - camera_metadata_ro_entry_t availableFormats; - res = find_camera_metadata_ro_entry(mStaticInfo, + camera_metadata_entry_t availableFormats; + res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_FORMATS, &availableFormats); ASSERT_EQ(OK, res); @@ -255,17 +255,17 @@ class Camera2Test: public testing::Test { << "No support found for format 0x" << std::hex << format; } - camera_metadata_ro_entry_t availableSizes; + camera_metadata_entry_t availableSizes; if (format == HAL_PIXEL_FORMAT_RAW_SENSOR) { - res = find_camera_metadata_ro_entry(mStaticInfo, + res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_RAW_SIZES, &availableSizes); } else if (format == HAL_PIXEL_FORMAT_BLOB) { - res = find_camera_metadata_ro_entry(mStaticInfo, + res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_JPEG_SIZES, &availableSizes); } else { - res = find_camera_metadata_ro_entry(mStaticInfo, + res = find_camera_metadata_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, &availableSizes); } @@ -293,7 +293,7 @@ class Camera2Test: public testing::Test { } camera2_device *mDevice; - const camera_metadata_t *mStaticInfo; + camera_metadata_t *mStaticInfo; MetadataQueue mRequests; MetadataQueue mFrames; @@ -342,7 +342,7 @@ TEST_F(Camera2Test, Capture1Raw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - const int32_t *rawResolutions; + int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -456,7 +456,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - const int32_t *rawResolutions; + int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -618,7 +618,7 @@ TEST_F(Camera2Test, Capture1Jpeg) { sp jpegWaiter = new FrameWaiter(); jpegConsumer->setFrameAvailableListener(jpegWaiter); - const int32_t *jpegResolutions; + int32_t *jpegResolutions; size_t jpegResolutionsCount; int format = HAL_PIXEL_FORMAT_BLOB; -- cgit v1.1 From b8b6439598ecc5faecfce8d43f3418b057714b4c Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 24 Aug 2012 12:32:17 -0700 Subject: Camera2: Make static_camera_characteristics const. Disallow modification to static characteristics structure, and clarify ownership and lifetime of the structure. Also update test code accordingly. Bug: 6243944 Change-Id: I6921d6889937212867efb99aa3881ab3ffc4f6f9 --- include/hardware/camera_common.h | 6 ++++-- tests/camera2/camera2.cpp | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/hardware/camera_common.h b/include/hardware/camera_common.h index 5459b6c..5697bda 100644 --- a/include/hardware/camera_common.h +++ b/include/hardware/camera_common.h @@ -135,7 +135,9 @@ struct camera_info { /** * The camera's fixed characteristics, which include all camera metadata in - * the android.*.info.* sections. + * the android.*.info.* sections. This should be a sorted metadata buffer, + * and may not be modified or freed by the caller. The pointer should remain + * valid for the lifetime of the camera module. * * Version information (based on camera_module_t.common.module_api_version): * @@ -150,7 +152,7 @@ struct camera_info { * otherwise. * */ - camera_metadata_t *static_camera_characteristics; + const camera_metadata_t *static_camera_characteristics; }; typedef struct camera_module { diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 05f61ef..29eef68 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -236,13 +236,13 @@ class Camera2Test: public testing::Test { } void getResolutionList(int32_t format, - int32_t **list, + const int32_t **list, size_t *count) { ALOGV("Getting resolutions for format %x", format); status_t res; if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { - camera_metadata_entry_t availableFormats; - res = find_camera_metadata_entry(mStaticInfo, + camera_metadata_ro_entry_t availableFormats; + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_FORMATS, &availableFormats); ASSERT_EQ(OK, res); @@ -255,17 +255,17 @@ class Camera2Test: public testing::Test { << "No support found for format 0x" << std::hex << format; } - camera_metadata_entry_t availableSizes; + camera_metadata_ro_entry_t availableSizes; if (format == HAL_PIXEL_FORMAT_RAW_SENSOR) { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_RAW_SIZES, &availableSizes); } else if (format == HAL_PIXEL_FORMAT_BLOB) { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_JPEG_SIZES, &availableSizes); } else { - res = find_camera_metadata_entry(mStaticInfo, + res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, &availableSizes); } @@ -293,7 +293,7 @@ class Camera2Test: public testing::Test { } camera2_device *mDevice; - camera_metadata_t *mStaticInfo; + const camera_metadata_t *mStaticInfo; MetadataQueue mRequests; MetadataQueue mFrames; @@ -342,7 +342,7 @@ TEST_F(Camera2Test, Capture1Raw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - int32_t *rawResolutions; + const int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -456,7 +456,7 @@ TEST_F(Camera2Test, CaptureBurstRaw) { sp rawWaiter = new FrameWaiter(); rawConsumer->setFrameAvailableListener(rawWaiter); - int32_t *rawResolutions; + const int32_t *rawResolutions; size_t rawResolutionsCount; int format = HAL_PIXEL_FORMAT_RAW_SENSOR; @@ -618,7 +618,7 @@ TEST_F(Camera2Test, Capture1Jpeg) { sp jpegWaiter = new FrameWaiter(); jpegConsumer->setFrameAvailableListener(jpegWaiter); - int32_t *jpegResolutions; + const int32_t *jpegResolutions; size_t jpegResolutionsCount; int format = HAL_PIXEL_FORMAT_BLOB; -- cgit v1.1 From 2388a2dc91979364d96e49456b189f904f0267f3 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 28 Aug 2012 14:01:26 -0700 Subject: Camera2: Use HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED Align camera2's management of platform-opaque formats with rest of framework. Instead of using CAMERA2_PIXEL_FORMAT_OPAQUE, use HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as the format for both the camera HAL and for gralloc, and depend on the gralloc usage flags to let the gralloc module select the appropriate real format for specific stream endpoints. Add a new gralloc usage for ZSL mode, where the camera service will hold a streaming circular buffer of opaque full-resolution images during camera preview. Since this is an opaque format that needs to be optimized for 30fps operation, need gralloc to be aware of this use case. Bug: 6243944 Change-Id: If7f2516649381ce9bcffe4e319b63cbc068f643f --- include/hardware/camera2.h | 46 ++++++++++++++--------------------------- include/hardware/gralloc.h | 2 ++ tests/camera2/camera2.cpp | 2 +- tests/camera2/camera2_utils.cpp | 9 ++++---- tests/camera2/camera2_utils.h | 2 -- 5 files changed, 22 insertions(+), 39 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 518130b..8209985 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -96,22 +96,11 @@ typedef struct camera2_stream_ops { } camera2_stream_ops_t; +/** + * Temporary definition during transition. TODO: Remove once HALs no longer + * reference this */ enum { - /** - * Special pixel format value used to indicate that the framework does not care - * what exact pixel format is to be used for an output stream. The device HAL is - * free to select any pixel format, platform-specific and otherwise, and this - * opaque value will be passed on to the platform gralloc module when buffers - * need to be allocated for the stream. - */ - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = -1, - /** - * Special pixel format value used to indicate that the framework will use - * the output buffers for zero-shutter-lag mode; these buffers should be - * efficient to produce at full sensor resolution, and efficient to send - * into a reprocess stream for final output processing. - */ - CAMERA2_HAL_PIXEL_FORMAT_ZSL = -2 + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED }; /** @@ -564,11 +553,12 @@ typedef struct camera2_device_ops { * Input parameters: * * - width, height, format: Specification for the buffers to be sent through - * this stream. Format is a value from the HAL_PIXEL_FORMAT_* list, or - * CAMERA2_HAL_PIXEL_FORMAT_OPAQUE. In the latter case, the camera device - * must select an appropriate (possible platform-specific) HAL pixel - * format to return in format_actual. In the former case, format_actual - * must be set to match format. + * this stream. Format is a value from the HAL_PIXEL_FORMAT_* list. If + * HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED is used, then the platform + * gralloc module will select a format based on the usage flags provided + * by the camera HAL and the consumer of the stream. The camera HAL should + * inspect the buffers handed to it in the register_stream_buffers call to + * obtain the implementation-specific format if necessary. * * - stream_ops: A structure of function pointers for obtaining and queuing * up buffers for this stream. The underlying stream will be configured @@ -581,15 +571,6 @@ typedef struct camera2_device_ops { * used in incoming requests to identify the stream, and in releasing the * stream. * - * - format_actual: If the input format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, - * then device must select the appropriate (possible platform-specific) - * pixel format and return it in *format_actual. It will be treated as an - * opaque value by the framework, and simply passed to the gralloc module - * when new buffers need to be allocated. If the input format is one of - * the values from HAL_PIXEL_FORMAT_* list, then *format_actual must be - * set equal to format. In the latter case, format_actual may also be - * NULL, in which case it can be ignored as an output. - * * - usage: The gralloc usage mask needed by the HAL device for producing * the requested type of data. This is used in allocating new gralloc * buffers for the stream buffer queue. @@ -608,7 +589,7 @@ typedef struct camera2_device_ops { const camera2_stream_ops_t *stream_ops, // outputs uint32_t *stream_id, - uint32_t *format_actual, + uint32_t *format_actual, // IGNORED, will be removed uint32_t *usage, uint32_t *max_buffers); @@ -619,7 +600,10 @@ typedef struct camera2_device_ops { * otherwise prepare the buffers for later use. num_buffers is guaranteed to * be at least max_buffers (from allocate_stream), but may be larger. The * buffers will already be locked for use. At the end of the call, all the - * buffers must be ready to be returned to the queue. + * buffers must be ready to be returned to the queue. If the stream format + * was set to HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, the camera HAL should + * inspect the passed-in buffers here to determine any platform-private + * pixel format information. */ int (*register_stream_buffers)( const struct camera2_device *, diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h index 86ed95c..4fdd2e6 100644 --- a/include/hardware/gralloc.h +++ b/include/hardware/gralloc.h @@ -80,6 +80,8 @@ enum { GRALLOC_USAGE_HW_CAMERA_WRITE = 0x00020000, /* buffer will be read by the HW camera pipeline */ GRALLOC_USAGE_HW_CAMERA_READ = 0x00040000, + /* buffer will be used as part of zero-shutter-lag queue */ + GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00080000, /* mask for the software usage bit-mask */ GRALLOC_USAGE_HW_MASK = 0x00071F00, diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp index 29eef68..f43513e 100644 --- a/tests/camera2/camera2.cpp +++ b/tests/camera2/camera2.cpp @@ -240,7 +240,7 @@ class Camera2Test: public testing::Test { size_t *count) { ALOGV("Getting resolutions for format %x", format); status_t res; - if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) { + if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { camera_metadata_ro_entry_t availableFormats; res = find_camera_metadata_ro_entry(mStaticInfo, ANDROID_SCALER_AVAILABLE_FORMATS, diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp index ba938d9..cefe29a 100644 --- a/tests/camera2/camera2_utils.cpp +++ b/tests/camera2/camera2_utils.cpp @@ -317,7 +317,7 @@ void NotifierListener::notify_callback_dispatch(int32_t msg_type, StreamAdapter::StreamAdapter(sp consumer): mState(UNINITIALIZED), mDevice(NULL), mId(-1), - mWidth(0), mHeight(0), mFormatRequested(0) + mWidth(0), mHeight(0), mFormat(0) { mConsumerInterface = new SurfaceTextureClient(consumer); camera2_stream_ops::dequeue_buffer = dequeue_buffer; @@ -342,16 +342,16 @@ status_t StreamAdapter::connectToDevice(camera2_device_t *d, mWidth = width; mHeight = height; - mFormatRequested = format; + mFormat = format; // Allocate device-side stream interface uint32_t id; - uint32_t formatActual; + uint32_t formatActual; // ignored uint32_t usage; uint32_t maxBuffers = 2; res = d->ops->allocate_stream(d, - mWidth, mHeight, mFormatRequested, getStreamOps(), + mWidth, mHeight, mFormat, getStreamOps(), &id, &formatActual, &usage, &maxBuffers); if (res != OK) { ALOGE("%s: Device stream allocation failed: %s (%d)", @@ -362,7 +362,6 @@ status_t StreamAdapter::connectToDevice(camera2_device_t *d, mDevice = d; mId = id; - mFormat = formatActual; mUsage = usage; mMaxProducerBuffers = maxBuffers; diff --git a/tests/camera2/camera2_utils.h b/tests/camera2/camera2_utils.h index 2c9f801..7822f5b 100644 --- a/tests/camera2/camera2_utils.h +++ b/tests/camera2/camera2_utils.h @@ -194,8 +194,6 @@ class StreamAdapter: public camera2_stream_ops { uint32_t mMaxProducerBuffers; uint32_t mMaxConsumerBuffers; - int mFormatRequested; - const camera2_stream_ops *getStreamOps(); static ANativeWindow* toANW(const camera2_stream_ops_t *w); -- cgit v1.1 From 3f5b522ac9a472de756c08b16f357acd6dc26e34 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 28 Aug 2012 15:23:58 -0700 Subject: Encode header version in api versions Change-Id: I0216bef3ba0cfaed2fe908f735e546d0734c0b13 --- include/hardware/hardware.h | 8 ++++++++ include/hardware/hwcomposer_defs.h | 15 +++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/hardware/hardware.h b/include/hardware/hardware.h index 78c4572..416ae39 100644 --- a/include/hardware/hardware.h +++ b/include/hardware/hardware.h @@ -37,6 +37,12 @@ __BEGIN_DECLS #define HARDWARE_MAKE_API_VERSION(maj,min) \ ((((maj) & 0xff) << 8) | ((min) & 0xff)) +#define HARDWARE_MAKE_API_VERSION_2(maj,min,hdr) \ + ((((maj) & 0xff) << 24) | (((min) & 0xff) << 16) | ((hdr) & 0xffff)) +#define HARDWARE_API_VERSION_2_MAJ_MIN_MASK 0xffff0000 +#define HARDWARE_API_VERSION_2_HEADER_MASK 0x0000ffff + + /* * The current HAL API version. * @@ -60,11 +66,13 @@ __BEGIN_DECLS * Use this macro to set the hw_module_t.module_api_version field. */ #define HARDWARE_MODULE_API_VERSION(maj,min) HARDWARE_MAKE_API_VERSION(maj,min) +#define HARDWARE_MODULE_API_VERSION_2(maj,min,hdr) HARDWARE_MAKE_API_VERSION_2(maj,min,hdr) /* * Use this macro to set the hw_device_t.version field */ #define HARDWARE_DEVICE_API_VERSION(maj,min) HARDWARE_MAKE_API_VERSION(maj,min) +#define HARDWARE_DEVICE_API_VERSION_2(maj,min,hdr) HARDWARE_MAKE_API_VERSION_2(maj,min,hdr) struct hw_module_t; struct hw_module_methods_t; diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index f0f97fc..bd9f41c 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -28,13 +28,16 @@ __BEGIN_DECLS /*****************************************************************************/ -#define HWC_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1) +#define HWC_HEADER_VERSION 1 -#define HWC_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION(0, 1) -#define HWC_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION(0, 2) -#define HWC_DEVICE_API_VERSION_0_3 HARDWARE_DEVICE_API_VERSION(0, 3) -#define HWC_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0) -#define HWC_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION(1, 1) +#define HWC_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION_2(0, 1, HWC_HEADER_VERSION) + +#define HWC_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION_2(0, 1, HWC_HEADER_VERSION) +#define HWC_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION_2(0, 2, HWC_HEADER_VERSION) +#define HWC_DEVICE_API_VERSION_0_3 HARDWARE_DEVICE_API_VERSION_2(0, 3, HWC_HEADER_VERSION) +#define HWC_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION_2(1, 0, HWC_HEADER_VERSION) +#define HWC_DEVICE_API_VERSION_1_1 HARDWARE_DEVICE_API_VERSION_2(1, 1, HWC_HEADER_VERSION) +#define HWC_DEVICE_API_VERSION_1_2 HARDWARE_DEVICE_API_VERSION_2(1, 2, HWC_HEADER_VERSION) enum { /* hwc_composer_device_t::set failed in EGL */ -- cgit v1.1 From 2c13759c61dd111efc9509ddf37330f50f706f64 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Wed, 29 Aug 2012 10:37:37 -0700 Subject: Add new HWC 1.1 queries and hotplug callback Change-Id: I40164e60b33174e98a3843ec99f1680b1bb1c675 --- include/hardware/hwcomposer.h | 69 +++++++++++++++++++++++++++++++++++--- include/hardware/hwcomposer_defs.h | 39 +++++++++++++++++---- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 29ea54c..0a4d40d 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -270,7 +270,7 @@ typedef struct hwc_procs { * received and HWC_EVENT_VSYNC is enabled on a display * (see: hwc_event_control). * - * the "dpy" parameter indicates which display the vsync event is for. + * the "disp" parameter indicates which display the vsync event is for. * the "timestamp" parameter is the system monotonic clock timestamp in * nanosecond of when the vsync event happened. * @@ -285,7 +285,27 @@ typedef struct hwc_procs { * can either stop or continue to process VSYNC events, but must not * crash or cause other problems. */ - void (*vsync)(const struct hwc_procs* procs, int dpy, int64_t timestamp); + void (*vsync)(const struct hwc_procs* procs, int disp, int64_t timestamp); + + /* + * (*hotplug)() is called by the h/w composer HAL when a display is + * connected or disconnected. The PRIMARY display is always connected and + * the hotplug callback should not be called for it. + * + * The disp parameter indicates which display type this event is for. + * The connected parameter indicates whether the display has just been + * connected (1) or disconnected (0). + * + * The hotplug() callback may call back into the h/w composer on the same + * thread to query refresh rate and dpi for the display. Additionally, + * other threads may be calling into the h/w composer while the callback + * is in progress. + * + * This callback will be NULL if the h/w composer is using + * HWC_DEVICE_API_VERSION_1_0. + */ + void (*hotplug)(const struct hwc_procs* procs, int disp, int connected); + } hwc_procs_t; @@ -384,7 +404,7 @@ typedef struct hwc_composer_device_1 { * returns -EINVAL if the "event" parameter is not one of the value above * or if the "enabled" parameter is not 0 or 1. */ - int (*eventControl)(struct hwc_composer_device_1* dev, int dpy, + int (*eventControl)(struct hwc_composer_device_1* dev, int disp, int event, int enabled); /* @@ -398,7 +418,7 @@ typedef struct hwc_composer_device_1 { * * returns 0 on success, negative on error. */ - int (*blank)(struct hwc_composer_device_1* dev, int dpy, int blank); + int (*blank)(struct hwc_composer_device_1* dev, int disp, int blank); /* * Used to retrieve information about the h/w composer @@ -425,6 +445,47 @@ typedef struct hwc_composer_device_1 { void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len); /* + * (*getDisplayConfigs)() returns handles for the configurations available + * on the connected display. These handles must remain valid as long as the + * display is connected. + * + * Configuration handles are written to configs. The number of entries + * allocated by the caller is passed in *numConfigs; getDisplayConfigs must + * not try to write more than this number of config handles. On return, the + * total number of configurations available for the display is returned in + * *numConfigs. If *numConfigs is zero on entry, then configs may be NULL. + * + * HWC_DEVICE_API_VERSION_1_1 does not provide a way to choose a config. + * For displays that support multiple configurations, the h/w composer + * implementation should choose one and report it as the first config in + * the list. Reporting the not-chosen configs is not required. + * + * Returns 0 on success or -errno on error. + * + * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later. + * It should be NULL for previous versions. + */ + int (*getDisplayConfigs)(struct hwc_composer_device_1* dev, int disp, + uint32_t* configs, size_t* numConfigs); + + /* + * (*getDisplayAttributes)() returns attributes for a specific config of a + * connected display. The config parameter is one of the config handles + * returned by getDisplayConfigs. + * + * The list of attributes to return is provided in the attributes + * parameter, terminated by HWC_DISPLAY_NO_ATTRIBUTE. The value for each + * requested attribute is written in order to the values array. The + * HWC_DISPLAY_NO_ATTRIBUTE attribute does not have a value, so the values + * array will have one less value than the attributes array. + * + * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later. + * It should be NULL for previous versions. + */ + void (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp, + uint32_t config, const uint32_t* attributes, int32_t* values); + + /* * Reserved for future use. Must be NULL. */ void* reserved_proc[4]; diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index bd9f41c..04f4c2c 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -132,24 +132,51 @@ enum { /* attributes queriable with query() */ enum { /* - * availability: HWC_DEVICE_API_VERSION_0_2 - * must return 1 if the background layer is supported, 0 otherwise + * Availability: HWC_DEVICE_API_VERSION_0_2 + * Must return 1 if the background layer is supported, 0 otherwise. */ HWC_BACKGROUND_LAYER_SUPPORTED = 0, /* - * availability: HWC_DEVICE_API_VERSION_0_3 - * returns the vsync period in nanosecond + * Availability: HWC_DEVICE_API_VERSION_0_3 + * Returns the vsync period in nanoseconds. + * + * This query is not used for HWC_DEVICE_API_VERSION_1_1 and later. + * Instead, the per-display attribute HWC_DISPLAY_VSYNC_PERIOD is used. */ HWC_VSYNC_PERIOD = 1, /* - * availability: HWC_DEVICE_API_VERSION_1_1 - * returns a mask of supported display types + * Availability: HWC_DEVICE_API_VERSION_1_1 + * Returns a mask of supported display types. */ HWC_DISPLAY_TYPES_SUPPORTED = 2, }; +/* display attributes returned by getDisplayAttributes() */ +enum { + /* Indicates the end of an attribute list */ + HWC_DISPLAY_NO_ATTRIBUTE = 0, + + /* The vsync period in nanoseconds */ + HWC_DISPLAY_VSYNC_PERIOD = 1, + + /* The number of pixels in the horizontal and vertical directions. */ + HWC_DISPLAY_RESOLUTION_X = 2, + HWC_DISPLAY_RESOLUTION_Y = 3, + + /* The number of pixels per thousand inches of this configuration. + * + * Scaling DPI by 1000 allows it to be stored in an int without losing + * too much precision. + * + * If the DPI for a configuration is unavailable or the HWC implementation + * considers it unreliable, it should set these attributes to zero. + */ + HWC_DISPLAY_DPI_X = 4, + HWC_DISPLAY_DPI_Y = 5, +}; + /* Allowed events for hwc_methods::eventControl() */ enum { HWC_EVENT_VSYNC = 0 -- cgit v1.1 From a07ef69482e28199bb34ac94e1e621f7afaf842e Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 31 Aug 2012 18:42:35 -0700 Subject: audio effects: add audio source indication Added a command to audio effect API to indicate the audio source to audio pre processings. Change-Id: Ia9d68bc095b8bc5d3cf847a406ec0a719a1c14ac --- include/hardware/audio_effect.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/hardware/audio_effect.h b/include/hardware/audio_effect.h index 4037bbb..46e323d 100644 --- a/include/hardware/audio_effect.h +++ b/include/hardware/audio_effect.h @@ -142,6 +142,10 @@ typedef struct effect_descriptor_s { // | | | 1 requires audio mode updates // | | | 2..3 reserved // +---------------------------+-----------+----------------------------------- +// | Audio source indication | 20..21 | 0 none +// | | | 1 requires audio source updates +// | | | 2..3 reserved +// +---------------------------+-----------+----------------------------------- // Insert mode #define EFFECT_FLAG_TYPE_SHIFT 0 @@ -216,6 +220,13 @@ typedef struct effect_descriptor_s { #define EFFECT_FLAG_AUDIO_MODE_IND (1 << EFFECT_FLAG_AUDIO_MODE_SHIFT) #define EFFECT_FLAG_AUDIO_MODE_NONE (0 << EFFECT_FLAG_AUDIO_MODE_SHIFT) +// Audio source indication +#define EFFECT_FLAG_AUDIO_SOURCE_SHIFT (EFFECT_FLAG_AUDIO_MODE_SHIFT + EFFECT_FLAG_AUDIO_MODE_SIZE) +#define EFFECT_FLAG_AUDIO_SOURCE_SIZE 2 +#define EFFECT_FLAG_AUDIO_SOURCE_MASK (((1 << EFFECT_FLAG_AUDIO_SOURCE_SIZE) -1) \ + << EFFECT_FLAG_AUDIO_SOURCE_SHIFT) +#define EFFECT_FLAG_AUDIO_SOURCE_IND (1 << EFFECT_FLAG_AUDIO_SOURCE_SHIFT) +#define EFFECT_FLAG_AUDIO_SOURCE_NONE (0 << EFFECT_FLAG_AUDIO_SOURCE_SHIFT) #define EFFECT_MAKE_API_VERSION(M, m) (((M)<<16) | ((m) & 0xFFFF)) #define EFFECT_API_VERSION_MAJOR(v) ((v)>>16) @@ -413,6 +424,7 @@ enum effect_command_e { EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS,// get all supported configurations for a feature. EFFECT_CMD_GET_FEATURE_CONFIG, // get current feature configuration EFFECT_CMD_SET_FEATURE_CONFIG, // set current feature configuration + EFFECT_CMD_SET_AUDIO_SOURCE, // set the audio source (see audio.h, audio_source_t) EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code }; @@ -705,6 +717,20 @@ enum effect_command_e { // size: sizeof(uint32_t) // data: status //================================================================================================== +// command: EFFECT_CMD_SET_AUDIO_SOURCE +//-------------------------------------------------------------------------------------------------- +// description: +// Set the audio source the capture path is configured for (Camcorder, voice recognition...). +// See audio.h, audio_source_t for values. +//-------------------------------------------------------------------------------------------------- +// command format: +// size: sizeof(uint32_t) +// data: uint32_t +//-------------------------------------------------------------------------------------------------- +// reply format: +// size: 0 +// data: N/A +//================================================================================================== // command: EFFECT_CMD_FIRST_PROPRIETARY //-------------------------------------------------------------------------------------------------- // description: -- cgit v1.1 From 70d87bf07ecd686a2860980fb8e7d18fb2312dbd Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 30 Aug 2012 23:55:53 -0700 Subject: Add reprocess method, redefine gralloc ZSL usage flag - Camera2: Add allocate_reprocess_stream_from_stream for ZSL usecases - Gralloc: Make GRALLOC_USAGE_HW_CAMERA_ZSL be simply GRALLOC_USAGE_HW_CAMERA_READ | GRALLOC_USAGE_HW_CAMERA_WRITE - Gralloc: Add GRALLOC_USAGE_HW_CAMERA_MASK Change-Id: Icd8ac1f786e3adb6a422f27f03a5a4cb04a815cc --- include/hardware/camera2.h | 42 ++++++++++++++++++++++++++++++++++++++++++ include/hardware/gralloc.h | 4 +++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 8209985..8b789ec 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -667,6 +667,48 @@ typedef struct camera2_device_ops { uint32_t *max_buffers); /** + * allocate_reprocess_stream_from_stream: + * + * Allocate a new input stream for use, which will use the buffers allocated + * for an existing output stream. That is, after the HAL enqueues a buffer + * onto the output stream, it may see that same buffer handed to it from + * this input reprocessing stream. After the HAL releases the buffer back to + * the reprocessing stream, it will be returned to the output queue for + * reuse. + * + * Error conditions: + * + * - Using an output stream of unsuitable size/format for the basis of the + * reprocessing stream. + * + * - Attempting to allocatee too many reprocessing streams at once. + * + * Input parameters: + * + * - output_stream_id: The ID of an existing output stream which has + * a size and format suitable for reprocessing. + * + * - reprocess_stream_ops: A structure of function pointers for acquiring + * and releasing buffers for this stream. The underlying stream will use + * the same graphics buffer handles as the output stream uses. + * + * Output parameters: + * + * - stream_id: An unsigned integer identifying this stream. This value is + * used in incoming requests to identify the stream, and in releasing the + * stream. These ids are numbered separately from the input stream ids. + * + * The HAL client must always release the reprocessing stream before it + * releases the output stream it is based on. + * + */ + int (*allocate_reprocess_stream_from_stream)(const struct camera2_device *, + uint32_t output_stream_id, + const camera2_stream_in_ops_t *reprocess_stream_ops, + // outputs + uint32_t *stream_id); + + /** * Release a reprocessing stream. Returns an error if called when * get_in_progress_count is non-zero, or if the stream id is not * valid. diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h index 4fdd2e6..7c819f0 100644 --- a/include/hardware/gralloc.h +++ b/include/hardware/gralloc.h @@ -81,7 +81,9 @@ enum { /* buffer will be read by the HW camera pipeline */ GRALLOC_USAGE_HW_CAMERA_READ = 0x00040000, /* buffer will be used as part of zero-shutter-lag queue */ - GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00080000, + GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00060000, + /* mask for the camera access values */ + GRALLOC_USAGE_HW_CAMERA_MASK = 0x00060000, /* mask for the software usage bit-mask */ GRALLOC_USAGE_HW_MASK = 0x00071F00, -- cgit v1.1 From 903811cd0020f555d826870f018823b9063b37ab Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Tue, 4 Sep 2012 11:42:09 -0700 Subject: Make HWC_MODULE_API_VERSION fit in uint16_t again Change-Id: I4e32c3b7be9826cfac1e7226f7fd8894b6c97c1e --- include/hardware/hwcomposer_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index 04f4c2c..60cf827 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -30,7 +30,7 @@ __BEGIN_DECLS #define HWC_HEADER_VERSION 1 -#define HWC_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION_2(0, 1, HWC_HEADER_VERSION) +#define HWC_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1) #define HWC_DEVICE_API_VERSION_0_1 HARDWARE_DEVICE_API_VERSION_2(0, 1, HWC_HEADER_VERSION) #define HWC_DEVICE_API_VERSION_0_2 HARDWARE_DEVICE_API_VERSION_2(0, 2, HWC_HEADER_VERSION) -- cgit v1.1 From 3b98ffb168119f657befb1e3204183401ef4fd4f Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 4 Sep 2012 12:27:14 -0700 Subject: Revert "Add reprocess method, redefine gralloc ZSL usage flag" More dependent projects than I realized This reverts commit 7fa4a7e706cd8da0a4fd6722ff3b00b8088a01ae Change-Id: I813ffde0f8d602fd6d75186bf82e93c7ffed9a9a --- include/hardware/camera2.h | 42 ------------------------------------------ include/hardware/gralloc.h | 4 +--- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 8b789ec..8209985 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -667,48 +667,6 @@ typedef struct camera2_device_ops { uint32_t *max_buffers); /** - * allocate_reprocess_stream_from_stream: - * - * Allocate a new input stream for use, which will use the buffers allocated - * for an existing output stream. That is, after the HAL enqueues a buffer - * onto the output stream, it may see that same buffer handed to it from - * this input reprocessing stream. After the HAL releases the buffer back to - * the reprocessing stream, it will be returned to the output queue for - * reuse. - * - * Error conditions: - * - * - Using an output stream of unsuitable size/format for the basis of the - * reprocessing stream. - * - * - Attempting to allocatee too many reprocessing streams at once. - * - * Input parameters: - * - * - output_stream_id: The ID of an existing output stream which has - * a size and format suitable for reprocessing. - * - * - reprocess_stream_ops: A structure of function pointers for acquiring - * and releasing buffers for this stream. The underlying stream will use - * the same graphics buffer handles as the output stream uses. - * - * Output parameters: - * - * - stream_id: An unsigned integer identifying this stream. This value is - * used in incoming requests to identify the stream, and in releasing the - * stream. These ids are numbered separately from the input stream ids. - * - * The HAL client must always release the reprocessing stream before it - * releases the output stream it is based on. - * - */ - int (*allocate_reprocess_stream_from_stream)(const struct camera2_device *, - uint32_t output_stream_id, - const camera2_stream_in_ops_t *reprocess_stream_ops, - // outputs - uint32_t *stream_id); - - /** * Release a reprocessing stream. Returns an error if called when * get_in_progress_count is non-zero, or if the stream id is not * valid. diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h index 7c819f0..4fdd2e6 100644 --- a/include/hardware/gralloc.h +++ b/include/hardware/gralloc.h @@ -81,9 +81,7 @@ enum { /* buffer will be read by the HW camera pipeline */ GRALLOC_USAGE_HW_CAMERA_READ = 0x00040000, /* buffer will be used as part of zero-shutter-lag queue */ - GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00060000, - /* mask for the camera access values */ - GRALLOC_USAGE_HW_CAMERA_MASK = 0x00060000, + GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00080000, /* mask for the software usage bit-mask */ GRALLOC_USAGE_HW_MASK = 0x00071F00, -- cgit v1.1 From 7f8dd0ad2d3d40b57c8359971a351fd194668613 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 4 Sep 2012 14:21:07 -0700 Subject: Revert "Revert "Add reprocess method, redefine gralloc ZSL usage flag"" Missing project ready to go. This reverts commit 536148699beffcc4e6a2ced7c41fbbc3bcfa9886 Change-Id: I101343b443be6febe160685de6d72ddbf7e6aea5 --- include/hardware/camera2.h | 42 ++++++++++++++++++++++++++++++++++++++++++ include/hardware/gralloc.h | 4 +++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 8209985..8b789ec 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -667,6 +667,48 @@ typedef struct camera2_device_ops { uint32_t *max_buffers); /** + * allocate_reprocess_stream_from_stream: + * + * Allocate a new input stream for use, which will use the buffers allocated + * for an existing output stream. That is, after the HAL enqueues a buffer + * onto the output stream, it may see that same buffer handed to it from + * this input reprocessing stream. After the HAL releases the buffer back to + * the reprocessing stream, it will be returned to the output queue for + * reuse. + * + * Error conditions: + * + * - Using an output stream of unsuitable size/format for the basis of the + * reprocessing stream. + * + * - Attempting to allocatee too many reprocessing streams at once. + * + * Input parameters: + * + * - output_stream_id: The ID of an existing output stream which has + * a size and format suitable for reprocessing. + * + * - reprocess_stream_ops: A structure of function pointers for acquiring + * and releasing buffers for this stream. The underlying stream will use + * the same graphics buffer handles as the output stream uses. + * + * Output parameters: + * + * - stream_id: An unsigned integer identifying this stream. This value is + * used in incoming requests to identify the stream, and in releasing the + * stream. These ids are numbered separately from the input stream ids. + * + * The HAL client must always release the reprocessing stream before it + * releases the output stream it is based on. + * + */ + int (*allocate_reprocess_stream_from_stream)(const struct camera2_device *, + uint32_t output_stream_id, + const camera2_stream_in_ops_t *reprocess_stream_ops, + // outputs + uint32_t *stream_id); + + /** * Release a reprocessing stream. Returns an error if called when * get_in_progress_count is non-zero, or if the stream id is not * valid. diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h index 4fdd2e6..7c819f0 100644 --- a/include/hardware/gralloc.h +++ b/include/hardware/gralloc.h @@ -81,7 +81,9 @@ enum { /* buffer will be read by the HW camera pipeline */ GRALLOC_USAGE_HW_CAMERA_READ = 0x00040000, /* buffer will be used as part of zero-shutter-lag queue */ - GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00080000, + GRALLOC_USAGE_HW_CAMERA_ZSL = 0x00060000, + /* mask for the camera access values */ + GRALLOC_USAGE_HW_CAMERA_MASK = 0x00060000, /* mask for the software usage bit-mask */ GRALLOC_USAGE_HW_MASK = 0x00071F00, -- cgit v1.1 From 88b79cb001d1c733275c7cad490c32b143f78860 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 16 Aug 2012 13:56:03 -0700 Subject: Add audio module for remote submix New definitions of audio devices for remote submix: one representing a sink for writing the audio buffers that won't be played directly locally, another representing the audio source that can be read from to obtain the audio mix. New audio hardware module encapsulating the submix loop functionality. Create a Pipe to serve as non-blocking audio ring buffer between the output device (the sink) and the input device (the source). Change-Id: I527f4721a69ced0430a99ebba3b4db7d419f2bb2 --- include/hardware/audio.h | 1 + modules/audio_remote_submix/Android.mk | 29 ++ modules/audio_remote_submix/audio_hw.cpp | 724 +++++++++++++++++++++++++++++++ 3 files changed, 754 insertions(+) create mode 100644 modules/audio_remote_submix/Android.mk create mode 100644 modules/audio_remote_submix/audio_hw.cpp diff --git a/include/hardware/audio.h b/include/hardware/audio.h index 26e9ea9..4fd73a2 100644 --- a/include/hardware/audio.h +++ b/include/hardware/audio.h @@ -65,6 +65,7 @@ __BEGIN_DECLS #define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary" #define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp" #define AUDIO_HARDWARE_MODULE_ID_USB "usb" +#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix" /**************************************/ diff --git a/modules/audio_remote_submix/Android.mk b/modules/audio_remote_submix/Android.mk new file mode 100644 index 0000000..735215e --- /dev/null +++ b/modules/audio_remote_submix/Android.mk @@ -0,0 +1,29 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := audio.r_submix.default +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SRC_FILES := \ + audio_hw.cpp +LOCAL_C_INCLUDES += \ + frameworks/av/include/ \ + frameworks/native/include/ +LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libnbaio +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) + diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp new file mode 100644 index 0000000..2468309 --- /dev/null +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 "r_submix" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +extern "C" { + +namespace android { + +#define MAX_PIPE_DEPTH_IN_FRAMES (1024*4) +#define MAX_READ_ATTEMPTS 10 +#define READ_ATTEMPT_SLEEP_MS 10 // 10ms between two read attempts when pipe is empty +#define DEFAULT_RATE_HZ 48000 // default sample rate + +struct submix_config { + audio_format_t format; + audio_channel_mask_t channel_mask; + unsigned int rate; // sample rate for the device + unsigned int period_size; // size of the audio pipe is period_size * period_count in frames + unsigned int period_count; +}; + +struct submix_audio_device { + struct audio_hw_device device; + submix_config config; + // Pipe variables: they handle the ring buffer that "pipes" audio: + // - from the submix virtual audio output == what needs to be played by + // the remotely, seen as an output for AudioFlinger + // - to the virtual audio source == what is captured by the component + // which "records" the submix / virtual audio source, and handles it as needed. + // An usecase example is one where the component capturing the audio is then sending it over + // Wifi for presentation on a remote Wifi Display device (e.g. a dongle attached to a TV, or a + // TV with Wifi Display capabilities), or to a wireless audio player. + sp rsxSink; + sp rsxSource; + + pthread_mutex_t lock; +}; + +struct submix_stream_out { + struct audio_stream_out stream; + struct submix_audio_device *dev; +}; + +struct submix_stream_in { + struct audio_stream_in stream; + struct submix_audio_device *dev; +}; + + +/* audio HAL functions */ + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + const struct submix_stream_out *out = + reinterpret_cast(stream); + uint32_t out_rate = out->dev->config.rate; + //ALOGV("out_get_sample_rate() returns %u", out_rate); + return out_rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + if ((rate != 44100) && (rate != 48000)) { + ALOGE("out_set_sample_rate(rate=%u) rate unsupported", rate); + return -ENOSYS; + } + struct submix_stream_out *out = reinterpret_cast(stream); + //ALOGV("out_set_sample_rate(rate=%u)", rate); + out->dev->config.rate = rate; + return 0; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + const struct submix_stream_out *out = + reinterpret_cast(stream); + const struct submix_config& config_out = out->dev->config; + size_t buffer_size = config_out.period_size * popcount(config_out.channel_mask) + * sizeof(int16_t); // only PCM 16bit + //ALOGV("out_get_buffer_size() returns %u, period size=%u", + // buffer_size, config_out.period_size); + return buffer_size; +} + +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) +{ + const struct submix_stream_out *out = + reinterpret_cast(stream); + uint32_t channels = out->dev->config.channel_mask; + //ALOGV("out_get_channels() returns %08x", channels); + return channels; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + if (format != AUDIO_FORMAT_PCM_16_BIT) { + return -ENOSYS; + } else { + return 0; + } +} + +static int out_standby(struct audio_stream *stream) +{ + // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here + return 0; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + return 0; +} + +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + return strdup(""); +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + const struct submix_stream_out *out = + reinterpret_cast(stream); + const struct submix_config * config_out = &(out->dev->config); + uint32_t latency = (MAX_PIPE_DEPTH_IN_FRAMES * 1000) / config_out->rate; + ALOGV("out_get_latency() returns %u", latency); + return latency; +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + return -ENOSYS; +} + +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, + size_t bytes) +{ + //ALOGV("out_write(bytes=%d)", bytes); + ssize_t written = 0; + struct submix_stream_out *out = reinterpret_cast(stream); + + pthread_mutex_lock(&out->dev->lock); + + Pipe* sink = out->dev->rsxSink.get(); + if (sink != NULL) { + out->dev->rsxSink->incStrong(buffer); + } else { + pthread_mutex_unlock(&out->dev->lock); + ALOGE("out_write without a pipe!"); + ALOG_ASSERT("out_write without a pipe!"); + return 0; + } + + pthread_mutex_unlock(&out->dev->lock); + + const size_t frames = bytes / audio_stream_frame_size(&stream->common); + written = sink->write(buffer, frames); + if (written < 0) { + if (written == (ssize_t)NEGOTIATE) { + ALOGE("out_write() write to pipe returned NEGOTIATE"); + written = 0; + } else { + // write() returned UNDERRUN or WOULD_BLOCK, retry + written = sink->write(buffer, frames); + } + } + + pthread_mutex_lock(&out->dev->lock); + + out->dev->rsxSink->decStrong(buffer); + + pthread_mutex_unlock(&out->dev->lock); + + if (written > 0) { + // fake timing for audio output, we can't return right after pushing the data in the pipe + // TODO who's doing the flow control here? the wifi display link, or the audio HAL? + usleep(written * 1000000 / out_get_sample_rate(&stream->common)); + return written * audio_stream_frame_size(&stream->common);; + } else { + // error occurred, fake timing + usleep(frames * 1000000 / out_get_sample_rate(&stream->common)); + ALOGE("out_write error=%16lx", written); + return 0; + } +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + return -EINVAL; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + return -EINVAL; +} + +/** audio_stream_in implementation **/ +static uint32_t in_get_sample_rate(const struct audio_stream *stream) +{ + const struct submix_stream_in *in = reinterpret_cast(stream); + ALOGV("in_get_sample_rate() returns %u", in->dev->config.rate); + return in->dev->config.rate; +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return -ENOSYS; +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) +{ + const struct submix_stream_in *in = reinterpret_cast(stream); + ALOGV("in_get_buffer_size() returns %u", + in->dev->config.period_size * audio_stream_frame_size(stream)); + return in->dev->config.period_size * audio_stream_frame_size(stream); +} + +static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) +{ + return AUDIO_CHANNEL_IN_STEREO; +} + +static audio_format_t in_get_format(const struct audio_stream *stream) +{ + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) +{ + if (format != AUDIO_FORMAT_PCM_16_BIT) { + return -ENOSYS; + } else { + return 0; + } +} + +static int in_standby(struct audio_stream *stream) +{ + // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here + return 0; +} + +static int in_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + return 0; +} + +static char * in_get_parameters(const struct audio_stream *stream, + const char *keys) +{ + return strdup(""); +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) +{ + return 0; +} + +static ssize_t in_read(struct audio_stream_in *stream, void* buffer, + size_t bytes) +{ + ssize_t frames_read = -1977; + const struct submix_stream_in *in = reinterpret_cast(stream); + const size_t frame_size = audio_stream_frame_size(&stream->common); + + pthread_mutex_lock(&in->dev->lock); + + PipeReader* source = in->dev->rsxSource.get(); + if (source != NULL) { + in->dev->rsxSource->incStrong(in); + } else { + pthread_mutex_unlock(&in->dev->lock); + usleep((bytes / frame_size) * 1000000 / in_get_sample_rate(&stream->common)); + memset(buffer, 0, bytes); + return bytes; + } + + pthread_mutex_unlock(&in->dev->lock); + + int attempts = MAX_READ_ATTEMPTS; + size_t remaining_frames = bytes / frame_size; + char* buff = (char*)buffer; + while (attempts > 0) { + frames_read = source->read(buff, remaining_frames, AudioBufferProvider::kInvalidPTS); + if (frames_read > 0) { + //ALOGV("in_read frames=%ld size=%u", remaining_frames, frame_size); + remaining_frames -= frames_read; + buff += frames_read * frame_size; + if (remaining_frames == 0) { + // TODO simplify code by breaking out of loop + + pthread_mutex_lock(&in->dev->lock); + + in->dev->rsxSource->decStrong(in); + + pthread_mutex_unlock(&in->dev->lock); + + return bytes; + } + } else if (frames_read == 0) { + // TODO sleep should be tied to how much data is expected + usleep(READ_ATTEMPT_SLEEP_MS*1000); + attempts--; + } else { // frames_read is an error code + if (frames_read != (ssize_t)OVERRUN) { + attempts--; + } + // else OVERRUN: error has been signaled, ok to read, do not decrement counter + } + } + + pthread_mutex_lock(&in->dev->lock); + + in->dev->rsxSource->decStrong(in); + + pthread_mutex_unlock(&in->dev->lock); + + // TODO how to handle partial reads? + + if (frames_read < 0) { + ALOGE("in_read error=%16lx", frames_read); + } + return 0; +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +{ + return 0; +} + +static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out) +{ + ALOGV("adev_open_output_stream()"); + struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; + struct submix_stream_out *out; + int ret; + + out = (struct submix_stream_out *)calloc(1, sizeof(struct submix_stream_out)); + if (!out) { + ret = -ENOMEM; + goto err_open; + } + + pthread_mutex_lock(&rsxadev->lock); + + 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.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + 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.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + + config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + rsxadev->config.channel_mask = config->channel_mask; + + if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) { + config->sample_rate = DEFAULT_RATE_HZ; + } + rsxadev->config.rate = config->sample_rate; + + config->format = AUDIO_FORMAT_PCM_16_BIT; + rsxadev->config.format = config->format; + + rsxadev->config.period_size = 1024; + rsxadev->config.period_count = 4; + out->dev = rsxadev; + + *stream_out = &out->stream; + + // initialize pipe + { + ALOGV(" initializing pipe"); + const NBAIO_Format format = + config->sample_rate == 48000 ? Format_SR48_C2_I16 : Format_SR44_1_C2_I16; + const NBAIO_Format offers[1] = {format}; + size_t numCounterOffers = 0; + // creating a Pipe, not a MonoPipe with optional blocking set to true, so audio frames + // entering a full sink will overwrite the contents of the pipe. + Pipe* sink = new Pipe(MAX_PIPE_DEPTH_IN_FRAMES, format); + ssize_t index = sink->negotiate(offers, 1, NULL, numCounterOffers); + ALOG_ASSERT(index == 0); + PipeReader* source = new PipeReader(*sink); + numCounterOffers = 0; + index = source->negotiate(offers, 1, NULL, numCounterOffers); + ALOG_ASSERT(index == 0); + rsxadev->rsxSink = sink; + rsxadev->rsxSource = source; + } + + pthread_mutex_unlock(&rsxadev->lock); + + return 0; + +err_open: + *stream_out = NULL; + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + ALOGV("adev_close_output_stream()"); + struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; + + pthread_mutex_lock(&rsxadev->lock); + + rsxadev->rsxSink.clear(); + rsxadev->rsxSource.clear(); + free(stream); + + pthread_mutex_unlock(&rsxadev->lock); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + return -ENOSYS; +} + +static char * adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + return strdup("");; +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + ALOGI("adev_init_check()"); + return 0; +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) +{ + return -ENOSYS; +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +{ + return -ENOSYS; +} + +static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) +{ + return -ENOSYS; +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + return -ENOSYS; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + return -ENOSYS; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + //### TODO correlate this with pipe parameters + return 4096; +} + +static int adev_open_input_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + struct audio_stream_in **stream_in) +{ + ALOGI("adev_open_input_stream()"); + + struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; + struct submix_stream_in *in; + int ret; + + in = (struct submix_stream_in *)calloc(1, sizeof(struct submix_stream_in)); + if (!in) { + ret = -ENOMEM; + goto err_open; + } + + pthread_mutex_lock(&rsxadev->lock); + + 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.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.set_gain = in_set_gain; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + config->channel_mask = AUDIO_CHANNEL_IN_STEREO; + rsxadev->config.channel_mask = config->channel_mask; + + if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) { + config->sample_rate = DEFAULT_RATE_HZ; + } + rsxadev->config.rate = config->sample_rate; + + config->format = AUDIO_FORMAT_PCM_16_BIT; + rsxadev->config.format = config->format; + + rsxadev->config.period_size = 1024; + rsxadev->config.period_count = 4; + + *stream_in = &in->stream; + + in->dev = rsxadev; + + pthread_mutex_unlock(&rsxadev->lock); + + return 0; + +err_open: + *stream_in = NULL; + return ret; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + ALOGV("adev_close_input_stream()"); + struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; + + pthread_mutex_lock(&rsxadev->lock); + + free(stream); + + pthread_mutex_unlock(&rsxadev->lock); +} + +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + return 0; +} + +static int adev_close(hw_device_t *device) +{ + ALOGI("adev_close()"); + free(device); + return 0; +} + +static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) +{ + ALOGI("adev_get_supported_devices() returns %08x", + AUDIO_DEVICE_OUT_REMOTE_SUBMIX |AUDIO_DEVICE_IN_REMOTE_SUBMIX); + return (/* OUT */ + AUDIO_DEVICE_OUT_REMOTE_SUBMIX | + /* IN */ + AUDIO_DEVICE_IN_REMOTE_SUBMIX); +} + +static int adev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + ALOGI("adev_open(name=%s)", name); + struct submix_audio_device *rsxadev; + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + rsxadev = (submix_audio_device*) calloc(1, sizeof(struct submix_audio_device)); + if (!rsxadev) + return -ENOMEM; + + rsxadev->device.common.tag = HARDWARE_DEVICE_TAG; + rsxadev->device.common.version = AUDIO_DEVICE_API_VERSION_1_0; + rsxadev->device.common.module = (struct hw_module_t *) module; + rsxadev->device.common.close = adev_close; + + rsxadev->device.get_supported_devices = adev_get_supported_devices; + rsxadev->device.init_check = adev_init_check; + rsxadev->device.set_voice_volume = adev_set_voice_volume; + rsxadev->device.set_master_volume = adev_set_master_volume; + rsxadev->device.get_master_volume = adev_get_master_volume; + rsxadev->device.set_master_mute = adev_set_master_mute; + rsxadev->device.get_master_mute = adev_get_master_mute; + rsxadev->device.set_mode = adev_set_mode; + rsxadev->device.set_mic_mute = adev_set_mic_mute; + rsxadev->device.get_mic_mute = adev_get_mic_mute; + rsxadev->device.set_parameters = adev_set_parameters; + rsxadev->device.get_parameters = adev_get_parameters; + rsxadev->device.get_input_buffer_size = adev_get_input_buffer_size; + rsxadev->device.open_output_stream = adev_open_output_stream; + rsxadev->device.close_output_stream = adev_close_output_stream; + rsxadev->device.open_input_stream = adev_open_input_stream; + rsxadev->device.close_input_stream = adev_close_input_stream; + rsxadev->device.dump = adev_dump; + + *device = &rsxadev->device.common; + + return 0; +} + +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 */ "Wifi Display audio HAL", + /* author */ "The Android Open Source Project", + /* methods */ &hal_module_methods, + /* dso */ NULL, + /* reserved */ { 0 }, + }, +}; + +} //namespace android + +} //extern "C" -- cgit v1.1 From 85e08e26258711f2fd672d9a920d88bf91410f6b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 28 Aug 2012 14:30:35 -0700 Subject: audio: new audio devices enums Changed audio device API version to 2.0 because of new enums for audio input and output devices. Removed implementations of get_supported_devices() in stub and usb audio modules. Change-Id: I09345d38929d931e5015e36d18259f5a5f950298 --- include/hardware/audio.h | 9 ++++++++- modules/audio/audio_hw.c | 26 +------------------------- modules/usbaudio/audio_hw.c | 8 +------- 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/include/hardware/audio.h b/include/hardware/audio.h index 4fd73a2..3a0962e 100644 --- a/include/hardware/audio.h +++ b/include/hardware/audio.h @@ -53,7 +53,8 @@ __BEGIN_DECLS */ #define AUDIO_DEVICE_API_VERSION_0_0 HARDWARE_DEVICE_API_VERSION(0, 0) #define AUDIO_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0) -#define AUDIO_DEVICE_API_VERSION_CURRENT AUDIO_DEVICE_API_VERSION_1_0 +#define AUDIO_DEVICE_API_VERSION_2_0 HARDWARE_DEVICE_API_VERSION(2, 0) +#define AUDIO_DEVICE_API_VERSION_CURRENT AUDIO_DEVICE_API_VERSION_2_0 /** * List of known audio HAL modules. This is the base name of the audio HAL @@ -329,6 +330,12 @@ struct audio_hw_device { * each audio_hw_device implementation. * * Return value is a bitmask of 1 or more values of audio_devices_t + * + * NOTE: audio HAL implementations starting with + * AUDIO_DEVICE_API_VERSION_2_0 do not implement this function. + * All supported devices should be listed in audio_policy.conf + * file and the audio policy manager must choose the appropriate + * audio module based on information in this file. */ uint32_t (*get_supported_devices)(const struct audio_hw_device *dev); diff --git a/modules/audio/audio_hw.c b/modules/audio/audio_hw.c index e4fb711..3051519 100644 --- a/modules/audio/audio_hw.c +++ b/modules/audio/audio_hw.c @@ -379,29 +379,6 @@ static int adev_close(hw_device_t *device) return 0; } -static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) -{ - return (/* OUT */ - AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_ALL_SCO | - AUDIO_DEVICE_OUT_DEFAULT | - /* IN */ - AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_ALL_SCO | - AUDIO_DEVICE_IN_DEFAULT); -} - static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) { @@ -416,11 +393,10 @@ static int adev_open(const hw_module_t* module, const char* name, return -ENOMEM; adev->device.common.tag = HARDWARE_DEVICE_TAG; - adev->device.common.version = AUDIO_DEVICE_API_VERSION_1_0; + adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; adev->device.common.module = (struct hw_module_t *) module; adev->device.common.close = adev_close; - adev->device.get_supported_devices = adev_get_supported_devices; adev->device.init_check = adev_init_check; adev->device.set_voice_volume = adev_set_voice_volume; adev->device.set_master_volume = adev_set_master_volume; diff --git a/modules/usbaudio/audio_hw.c b/modules/usbaudio/audio_hw.c index 9283016..f33c343 100644 --- a/modules/usbaudio/audio_hw.c +++ b/modules/usbaudio/audio_hw.c @@ -379,11 +379,6 @@ static int adev_close(hw_device_t *device) return 0; } -static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) -{ - return AUDIO_DEVICE_OUT_ALL_USB; -} - static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) { @@ -398,11 +393,10 @@ static int adev_open(const hw_module_t* module, const char* name, return -ENOMEM; adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; - adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_1_0; + adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; adev->hw_device.common.module = (struct hw_module_t *) module; adev->hw_device.common.close = adev_close; - adev->hw_device.get_supported_devices = adev_get_supported_devices; 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; -- cgit v1.1 From 416d37b37b9f84c3e759d78af50d88be7e778247 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 7 Sep 2012 11:25:59 -0700 Subject: Audio remote submix in hardware modules Change-Id: I878c6f36685eff48a3cd51acceec812b61994945 --- modules/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Android.mk b/modules/Android.mk index 871b984..3f410c1 100644 --- a/modules/Android.mk +++ b/modules/Android.mk @@ -1,2 +1,2 @@ -hardware_modules := gralloc hwcomposer audio nfc local_time power usbaudio +hardware_modules := gralloc hwcomposer audio nfc local_time power usbaudio audio_remote_submix include $(call all-named-subdir-makefiles,$(hardware_modules)) -- cgit v1.1 From 5d85c537fcae931428ba8b7a47fdd393cc3cbd88 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 10 Sep 2012 10:36:09 -0700 Subject: update audio remote submix API revision Update remote submix audio HAL API revision to 2.0 (new audio device enums). Change-Id: I61d5faf498144002929e570ee50375b059fb17c5 --- modules/audio_remote_submix/audio_hw.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index 2468309..e97a96e 100644 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -649,16 +649,6 @@ static int adev_close(hw_device_t *device) return 0; } -static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) -{ - ALOGI("adev_get_supported_devices() returns %08x", - AUDIO_DEVICE_OUT_REMOTE_SUBMIX |AUDIO_DEVICE_IN_REMOTE_SUBMIX); - return (/* OUT */ - AUDIO_DEVICE_OUT_REMOTE_SUBMIX | - /* IN */ - AUDIO_DEVICE_IN_REMOTE_SUBMIX); -} - static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) { @@ -673,11 +663,10 @@ static int adev_open(const hw_module_t* module, const char* name, return -ENOMEM; rsxadev->device.common.tag = HARDWARE_DEVICE_TAG; - rsxadev->device.common.version = AUDIO_DEVICE_API_VERSION_1_0; + rsxadev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; rsxadev->device.common.module = (struct hw_module_t *) module; rsxadev->device.common.close = adev_close; - rsxadev->device.get_supported_devices = adev_get_supported_devices; rsxadev->device.init_check = adev_init_check; rsxadev->device.set_voice_volume = adev_set_voice_volume; rsxadev->device.set_master_volume = adev_set_master_volume; -- cgit v1.1 From 7cb03d79b3040d9b43ffc81414e9853e8a57adb1 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Thu, 6 Sep 2012 16:57:12 -0700 Subject: Add outbuf fields for HWC 1.2 virtual displays Also rename HWC_DISPLAY_RESOLUTION_* to HWC_DISPLAY_WIDTH and HWC_DISPLAY_HEIGHT for consistency. Change-Id: Iabe6db0816f6f6eaaac24c3c9ae554177bcabf1d --- include/hardware/hwcomposer.h | 56 ++++++++++++++++++++++++++++---------- include/hardware/hwcomposer_defs.h | 4 +-- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 0a4d40d..5488e75 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -222,23 +222,49 @@ enum { */ typedef struct hwc_display_contents_1 { /* File descriptor referring to a Sync HAL fence object which will signal - * when this display image is no longer visible, i.e. when the following - * set() takes effect. The fence object is created and returned by the set - * call; this field will be -1 on entry to prepare and set. SurfaceFlinger - * will close the returned file descriptor. + * when this composition is retired. For a physical display, a composition + * is retired when it has been replaced on-screen by a subsequent set. For + * a virtual display, the composition is retired when the writes to + * outputBuffer are complete and can be read. The fence object is created + * and returned by the set call; this field will be -1 on entry to prepare + * and set. SurfaceFlinger will close the returned file descriptor. */ - int flipFenceFd; + int retireFenceFd; - /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES composition for - * HWC versions before HWC_DEVICE_VERSION_1_1. They aren't relevant to - * prepare. The set call should commit this surface atomically to the - * display along with any overlay layers. - * - * For HWC_DEVICE_VERSION_1_1 and later, these will always be set to - * EGL_NO_DISPLAY and EGL_NO_SURFACE. - */ - hwc_display_t dpy; - hwc_surface_t sur; + union { + /* Fields only relevant for HWC_DEVICE_VERSION_1_0. */ + struct { + /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES + * composition for HWC_DEVICE_VERSION_1_0. They aren't relevant to + * prepare. The set call should commit this surface atomically to + * the display along with any overlay layers. + */ + hwc_display_t dpy; + hwc_surface_t sur; + }; + + /* Fields only relevant for HWC_DEVICE_VERSION_1_2 and later. */ + struct { + /* outbuf is the buffer that receives the composed image for + * virtual displays. Writes to the outbuf must wait until + * outbufAcquireFenceFd signals. A fence that will signal when + * writes to outbuf are complete should be returned in + * retireFenceFd. + * + * For physical displays, outbuf will be NULL. + */ + buffer_handle_t outbuf; + + /* File descriptor for a fence that will signal when outbuf is + * ready to be written. The h/w composer is responsible for closing + * this when no longer needed. + * + * Will be -1 whenever outbuf is NULL, or when the outbuf can be + * written immediately. + */ + int outbufAcquireFenceFd; + }; + }; /* List of layers that will be composed on the display. The buffer handles * in the list will be unique. If numHwLayers is 0, all composition will be diff --git a/include/hardware/hwcomposer_defs.h b/include/hardware/hwcomposer_defs.h index 60cf827..ef8fcf1 100644 --- a/include/hardware/hwcomposer_defs.h +++ b/include/hardware/hwcomposer_defs.h @@ -162,8 +162,8 @@ enum { HWC_DISPLAY_VSYNC_PERIOD = 1, /* The number of pixels in the horizontal and vertical directions. */ - HWC_DISPLAY_RESOLUTION_X = 2, - HWC_DISPLAY_RESOLUTION_Y = 3, + HWC_DISPLAY_WIDTH = 2, + HWC_DISPLAY_HEIGHT = 3, /* The number of pixels per thousand inches of this configuration. * -- cgit v1.1 From 6acd966320c7f124f103044f3a152d90d6e38749 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 11 Sep 2012 19:19:08 -0700 Subject: Remote submix audio module: sleep less, log errors Neither write nor read are blocking, but write simulates timing by checking the clock between two writes and computing how long the next sleep should last. Change-Id: I495ae6d44b0cf75a24fe4b70662cfac679049c67 --- modules/audio_remote_submix/audio_hw.cpp | 47 +++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index e97a96e..0e5589b 100644 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -40,7 +40,7 @@ extern "C" { namespace android { #define MAX_PIPE_DEPTH_IN_FRAMES (1024*4) -#define MAX_READ_ATTEMPTS 10 +#define MAX_READ_ATTEMPTS 3 #define READ_ATTEMPT_SLEEP_MS 10 // 10ms between two read attempts when pipe is empty #define DEFAULT_RATE_HZ 48000 // default sample rate @@ -79,6 +79,8 @@ struct submix_stream_in { struct submix_audio_device *dev; }; +static struct timespec currentTs; + /* audio HAL functions */ @@ -202,8 +204,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, if (written == (ssize_t)NEGOTIATE) { ALOGE("out_write() write to pipe returned NEGOTIATE"); written = 0; + return 0; } else { // write() returned UNDERRUN or WOULD_BLOCK, retry + ALOGE("out_write() write to pipe returned unexpected %16lx", written); written = sink->write(buffer, frames); } } @@ -214,17 +218,25 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_unlock(&out->dev->lock); - if (written > 0) { - // fake timing for audio output, we can't return right after pushing the data in the pipe - // TODO who's doing the flow control here? the wifi display link, or the audio HAL? - usleep(written * 1000000 / out_get_sample_rate(&stream->common)); - return written * audio_stream_frame_size(&stream->common);; - } else { - // error occurred, fake timing - usleep(frames * 1000000 / out_get_sample_rate(&stream->common)); - ALOGE("out_write error=%16lx", written); - return 0; + struct timespec newTs; + int toSleepUs = 0; + int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); + if (rc == 0) { + time_t sec = newTs.tv_sec - currentTs.tv_sec; + long nsec = newTs.tv_nsec - currentTs.tv_nsec; + if (nsec < 0) { + --sec; + nsec += 1000000000; + } + if ((nsec / 1000) < (frames * 1000000 / out_get_sample_rate(&stream->common))) { + toSleepUs = (frames * 1000000 / out_get_sample_rate(&stream->common)) - (nsec/1000); + ALOGI("sleeping %dus", toSleepUs); + usleep(toSleepUs); + } } + clock_gettime(CLOCK_MONOTONIC, ¤tTs); + //ALOGV("out_write(bytes=%d) written=%d", bytes, written); + return written * audio_stream_frame_size(&stream->common); } static int out_get_render_position(const struct audio_stream_out *stream, @@ -319,6 +331,7 @@ static int in_set_gain(struct audio_stream_in *stream, float gain) static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) { + //ALOGV("in_read bytes=%u", bytes); ssize_t frames_read = -1977; const struct submix_stream_in *in = reinterpret_cast(stream); const size_t frame_size = audio_stream_frame_size(&stream->common); @@ -337,13 +350,14 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); + int attempts = MAX_READ_ATTEMPTS; size_t remaining_frames = bytes / frame_size; char* buff = (char*)buffer; while (attempts > 0) { frames_read = source->read(buff, remaining_frames, AudioBufferProvider::kInvalidPTS); if (frames_read > 0) { - //ALOGV("in_read frames=%ld size=%u", remaining_frames, frame_size); + //ALOGV(" in_read got frames=%u size=%u attempts=%d", remaining_frames, frame_size, attempts); remaining_frames -= frames_read; buff += frames_read * frame_size; if (remaining_frames == 0) { @@ -359,6 +373,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, } } else if (frames_read == 0) { // TODO sleep should be tied to how much data is expected + //ALOGW("sleeping %dms", READ_ATTEMPT_SLEEP_MS); usleep(READ_ATTEMPT_SLEEP_MS*1000); attempts--; } else { // frames_read is an error code @@ -375,11 +390,17 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); - // TODO how to handle partial reads? + if (remaining_frames > 0) { + ALOGW("remaining_frames = %d", remaining_frames); + memset(((char*)buffer)+ bytes - (remaining_frames * frame_size), 0, + remaining_frames * frame_size); + return bytes; + } if (frames_read < 0) { ALOGE("in_read error=%16lx", frames_read); } + ALOGE_IF(attempts == 0, "attempts == 0 "); return 0; } -- cgit v1.1 From 9633d506b798cfd44172f467b59b2305b19b9b00 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 13 Sep 2012 16:32:14 -0700 Subject: Camera2: Add CAMERA2_HAL_PIXEL_FORMAT_ZSL temporarily. Until all HAL implementations move to the new gralloc format selection scheme, define FORMAT_ZSL for indicating ZSL streams. Bug: 6243944 Change-Id: I90249beaaca5da80c9464eedd6aa9d3648bb56cc --- include/hardware/camera2.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 8b789ec..e6b99b7 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -97,10 +97,20 @@ typedef struct camera2_stream_ops { } camera2_stream_ops_t; /** - * Temporary definition during transition. TODO: Remove once HALs no longer - * reference this */ + * Temporary definition during transition. + * + * These formats will be removed and replaced with + * HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED. To maximize forward compatibility, + * HAL implementations are strongly recommended to treat FORMAT_OPAQUE and + * FORMAT_ZSL as equivalent to HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, and + * return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED in the format_actual output + * parameter of allocate_stream, allowing the gralloc module to select the + * specific format based on the usage flags from the camera and the stream + * consumer. + */ enum { - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + CAMERA2_HAL_PIXEL_FORMAT_ZSL = -1 }; /** -- cgit v1.1 From 1c970f1a493371aaa68f9227a8c3c395c5112fac Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 12 Sep 2012 17:59:39 -0400 Subject: Initial NFC HAL for NCI controllers. Bug: 7123942 Change-Id: Ic64aa6477f2eb65b489b3be5d49ad21ccce63e2d --- include/hardware/nfc.h | 192 +++++++++++++++++++++++++++++++++++++- modules/Android.mk | 2 +- modules/nfc-nci/Android.mk | 25 +++++ modules/nfc-nci/nfc_nci_example.c | 119 +++++++++++++++++++++++ modules/nfc/Android.mk | 2 +- modules/nfc/nfc_hw_example.c | 71 -------------- modules/nfc/nfc_pn544_example.c | 71 ++++++++++++++ 7 files changed, 406 insertions(+), 76 deletions(-) create mode 100644 modules/nfc-nci/Android.mk create mode 100644 modules/nfc-nci/nfc_nci_example.c delete mode 100644 modules/nfc/nfc_hw_example.c create mode 100644 modules/nfc/nfc_pn544_example.c diff --git a/include/hardware/nfc.h b/include/hardware/nfc.h index 74b3cfb..31410fb 100644 --- a/include/hardware/nfc.h +++ b/include/hardware/nfc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2011, 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef ANDROID_NFC_HAL_INTERFACE_H #define ANDROID_NFC_HAL_INTERFACE_H @@ -27,11 +26,198 @@ __BEGIN_DECLS -#define NFC_HARDWARE_MODULE_ID "nfc" + +/* NFC device HAL for NCI-based NFC controllers. + * + * This HAL allows NCI silicon vendors to make use + * of the core NCI stack in Android for their own silicon. + * + * The responibilities of the NCI HAL implementation + * are as follows: + * + * - Implement the transport to the NFC controller + * - Implement each of the HAL methods specified below as applicable to their silicon + * - Pass up received NCI messages from the controller to the stack + * + * A simplified timeline of NCI HAL method calls: + * 1) Core NCI stack calls open() + * 2) Core NCI stack executes CORE_RESET and CORE_INIT through calls to write() + * 3) Core NCI stack calls core_initialized() to allow HAL to do post-init configuration + * 4) Core NCI stack calls pre_discover() to allow HAL to prepare for RF discovery + * 5) Core NCI stack starts discovery through calls to write() + * 6) Core NCI stack stops discovery through calls to write() (e.g. screen turns off) + * 7) Core NCI stack calls pre_discover() to prepare for RF discovery (e.g. screen turned back on) + * 8) Core NCI stack starts discovery through calls to write() + * ... + * ... + * 9) Core NCI stack calls close() + */ +#define NFC_NCI_HARDWARE_MODULE_ID "nfc_nci" +#define NFC_NCI_CONTROLLER "nci" + +/* + * nfc_nci_module_t should contain module-specific parameters + */ +typedef struct nfc_nci_module_t { + struct hw_module_t common; +} nfc_nci_module_t; + +/* + * HAL events that can be passed back to the stack + */ +typedef uint8_t nfc_event_t; + +enum { + HAL_NFC_OPEN_CPLT_EVT = 0x00, + HAL_NFC_CLOSE_CPLT_EVT = 0x01, + HAL_NFC_POST_INIT_CPLT_EVT = 0x02, + HAL_NFC_NCI_RX_EVT = 0x03, + HAL_NFC_PRE_DISCOVER_CPLT_EVT = 0x04, + HAL_NFC_REQUEST_CONTROL_EVT = 0x05, + HAL_NFC_RELEASE_CONTROL_EVT = 0x06, + HAL_NFC_ERROR_EVT = 0x07 +}; + +/* + * Allowed status return values for each of the HAL methods + */ +typedef uint8_t nfc_status_t; + +enum { + HAL_NFC_STATUS_OK = 0x00, + HAL_NFC_STATUS_FAILED = 0x01, + HAL_NFC_STATUS_ERR_TRANSPORT = 0x02, + HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 0x03, + HAL_NFC_STATUS_REFUSED = 0x04 +}; + +/* + * nfc_rx_data + * Struct used to pass received NCI packets up to the stack + */ +typedef struct nfc_rx_data { + uint16_t len; + uint8_t *p_data; +} nfc_rx_data_t; /* + */ +typedef union +{ + nfc_status_t status; + nfc_rx_data_t nci_rx; +} nfc_event_data_t; + +/* + * The callback passed in from the NFC stack that the HAL + * can use to pass events back to the stack. + */ +typedef void (nfc_stack_callback_t) (nfc_event_t event, nfc_event_data_t* p_data); + +/* nfc_nci_device_t starts with a hw_device_t struct, + * followed by device-specific methods and members. + * + * All methods in the NCI HAL are asynchronous. + */ +typedef struct nfc_nci_device { + struct hw_device_t common; + /* + * (*open)() Opens the NFC controller device and performs initialization. + * This may include patch download and other vendor-specific initialization. + * + * If open completes successfully, the controller should be ready to perform + * NCI initialization - ie accept CORE_RESET and subsequent commands through + * the write() call. + * + * If open() returns 0, the NCI stack will wait for a HAL_NFC_OPEN_CPLT_EVT + * before continuing. + * + * If open() returns any other value, the NCI stack will stop. + * + */ + int (*open)(const struct nfc_nci_device *p_dev, nfc_stack_callback_t *p_cback); + + /* + * (*write)() Performs an NCI write. + * + * This method may queue writes and return immediately. The only + * requirement is that the writes are executed in order. + */ + int (*write)(const struct nfc_nci_device *p_dev, uint16_t data_len, const uint8_t *p_data); + + /* + * (*core_initialized)() is called after the CORE_INIT_RSP is received from the NFCC. + * At this time, the HAL can do any chip-specific configuration. + * + * If core_initialized() returns 0, the NCI stack will wait for a HAL_NFC_POST_INIT_CPLT_EVT + * before continuing. + * + * If core_initialized() returns any other value, the NCI stack will continue + * immediately. + */ + int (*core_initialized)(const struct nfc_nci_device *p_dev, uint8_t* p_core_init_rsp_params); + + /* + * (*pre_discover)() Is called every time before starting RF discovery. + * It is a good place to do vendor-specific configuration that must be + * performed every time RF discovery is about to be started. + * + * If pre_discover() returns 0, the NCI stack will wait for a HAL_NFC_PRE_DISCOVER_CPLT_EVT + * before continuing. + * + * If pre_discover() returns any other value, the NCI stack will start + * RF discovery immediately. + */ + int (*pre_discover)(const struct nfc_nci_device *p_dev); + + /* + * (*close)() Closed the NFC controller. Should free all resources. + */ + int (*close)(const struct nfc_nci_device *p_dev); + + /* + * (*control_granted)() Grant HAL the exclusive control to send NCI commands. + * Called in response to HAL_REQUEST_CONTROL_EVT. + * Must only be called when there are no NCI commands pending. + * HAL_RELEASE_CONTROL_EVT will notify when HAL no longer needs exclusive control. + */ + int (*control_granted)(const struct nfc_nci_device *p_dev); + + /* + * (*power_cycle)() Restart controller by power cyle; + * HAL_OPEN_CPLT_EVT will notify when operation is complete. + */ + int (*power_cycle)(const struct nfc_nci_device *p_dev); +} nfc_nci_device_t; + +/* + * Convenience methods that the NFC stack can use to open + * and close an NCI device + */ +static inline int nfc_nci_open(const struct hw_module_t* module, + nfc_nci_device_t** dev) { + return module->methods->open(module, NFC_NCI_CONTROLLER, + (struct hw_device_t**) dev); +} + +static inline int nfc_nci_close(nfc_nci_device_t* dev) { + return dev->common.close(&dev->common); +} +/* + * End NFC NCI HAL + */ + +/* + * This is a limited NFC HAL for NXP PN544-based devices. + * This HAL as Android is moving to + * an NCI-based NFC stack. + * + * All NCI-based NFC controllers should use the NFC-NCI + * HAL instead. * Begin PN544 specific HAL */ +#define NFC_HARDWARE_MODULE_ID "nfc" + #define NFC_PN544_CONTROLLER "pn544" typedef struct nfc_module_t { diff --git a/modules/Android.mk b/modules/Android.mk index 3f410c1..faa8bb3 100644 --- a/modules/Android.mk +++ b/modules/Android.mk @@ -1,2 +1,2 @@ -hardware_modules := gralloc hwcomposer audio nfc local_time power usbaudio audio_remote_submix +hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time power usbaudio audio_remote_submix include $(call all-named-subdir-makefiles,$(hardware_modules)) diff --git a/modules/nfc-nci/Android.mk b/modules/nfc-nci/Android.mk new file mode 100644 index 0000000..97262ef --- /dev/null +++ b/modules/nfc-nci/Android.mk @@ -0,0 +1,25 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := nfc_nci.default +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SRC_FILES := nfc_nci_example.c +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/modules/nfc-nci/nfc_nci_example.c b/modules/nfc-nci/nfc_nci_example.c new file mode 100644 index 0000000..01914f0 --- /dev/null +++ b/modules/nfc-nci/nfc_nci_example.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ +#include +#include + +#include +#include +#include + + +/* + * NCI HAL method implementations. These must be overriden + */ +static int hal_open(const struct nfc_nci_device *dev, + nfc_stack_callback_t *p_cback) { + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +static int hal_write(const struct nfc_nci_device *dev, + uint16_t data_len, const uint8_t *p_data) { + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +static int hal_core_initialized(const struct nfc_nci_device *dev, + uint8_t* p_core_init_rsp_params) { + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +static int hal_pre_discover(const struct nfc_nci_device *dev) { + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +static int hal_close(const struct nfc_nci_device *dev) { + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +static int hal_control_granted (const struct nfc_nci_device *p_dev) +{ + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + + +static int hal_power_cycle (const struct nfc_nci_device *p_dev) +{ + ALOGE("NFC-NCI HAL: %s", __FUNCTION__); + return 0; +} + +/* + * Generic device handling below - can generally be left unchanged. + */ +/* Close an opened nfc device instance */ +static int nfc_close(hw_device_t *dev) { + free(dev); + return 0; +} + +static int nfc_open(const hw_module_t* module, const char* name, + hw_device_t** device) { + if (strcmp(name, NFC_NCI_CONTROLLER) == 0) { + nfc_nci_device_t *dev = calloc(1, sizeof(nfc_nci_device_t)); + + dev->common.tag = HARDWARE_DEVICE_TAG; + dev->common.version = 0x00010000; // [31:16] major, [15:0] minor + dev->common.module = (struct hw_module_t*) module; + dev->common.close = nfc_close; + + // NCI HAL method pointers + dev->open = hal_open; + dev->write = hal_write; + dev->core_initialized = hal_core_initialized; + dev->pre_discover = hal_pre_discover; + dev->close = hal_close; + dev->control_granted = hal_control_granted; + dev->power_cycle = hal_power_cycle; + + *device = (hw_device_t*) dev; + + return 0; + } else { + return -EINVAL; + } +} + + +static struct hw_module_methods_t nfc_module_methods = { + .open = nfc_open, +}; + +struct nfc_nci_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = 0x0100, // [15:8] major, [7:0] minor (1.0) + .hal_api_version = 0x00, // 0 is only valid value + .id = NFC_NCI_HARDWARE_MODULE_ID, + .name = "Default NFC NCI HW HAL", + .author = "The Android Open Source Project", + .methods = &nfc_module_methods, + }, +}; diff --git a/modules/nfc/Android.mk b/modules/nfc/Android.mk index d541b21..429fb43 100644 --- a/modules/nfc/Android.mk +++ b/modules/nfc/Android.mk @@ -18,7 +18,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := nfc.default LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_SRC_FILES := nfc_hw_example.c +LOCAL_SRC_FILES := nfc_pn544_example.c LOCAL_SHARED_LIBRARIES := liblog libcutils LOCAL_MODULE_TAGS := optional diff --git a/modules/nfc/nfc_hw_example.c b/modules/nfc/nfc_hw_example.c deleted file mode 100644 index 54c9c56..0000000 --- a/modules/nfc/nfc_hw_example.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ -#include -#include - -#include -#include - -/* Close an opened pn544 device instance */ -static int pn544_close(hw_device_t *dev) { - free(dev); - return 0; -} - -/* - * Generic device handling - */ -static int nfc_open(const hw_module_t* module, const char* name, - hw_device_t** device) { - if (strcmp(name, NFC_PN544_CONTROLLER) == 0) { - nfc_pn544_device_t *dev = calloc(1, sizeof(nfc_pn544_device_t)); - - dev->common.tag = HARDWARE_DEVICE_TAG; - dev->common.version = 0; - dev->common.module = (struct hw_module_t*) module; - dev->common.close = pn544_close; - - /* Example settings */ - dev->num_eeprom_settings = 0; - dev->eeprom_settings = NULL; - dev->linktype = PN544_LINK_TYPE_INVALID; - dev->device_node = NULL; - dev->enable_i2c_workaround = 0; - dev->i2c_device_address = 0; - - *device = (hw_device_t*) dev; - return 0; - } else { - return -EINVAL; - } -} - - -static struct hw_module_methods_t nfc_module_methods = { - .open = nfc_open, -}; - -struct nfc_module_t HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .version_major = 1, - .version_minor = 0, - .id = NFC_HARDWARE_MODULE_ID, - .name = "Default NFC HW HAL", - .author = "The Android Open Source Project", - .methods = &nfc_module_methods, - }, -}; diff --git a/modules/nfc/nfc_pn544_example.c b/modules/nfc/nfc_pn544_example.c new file mode 100644 index 0000000..54c9c56 --- /dev/null +++ b/modules/nfc/nfc_pn544_example.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +#include +#include + +#include +#include + +/* Close an opened pn544 device instance */ +static int pn544_close(hw_device_t *dev) { + free(dev); + return 0; +} + +/* + * Generic device handling + */ +static int nfc_open(const hw_module_t* module, const char* name, + hw_device_t** device) { + if (strcmp(name, NFC_PN544_CONTROLLER) == 0) { + nfc_pn544_device_t *dev = calloc(1, sizeof(nfc_pn544_device_t)); + + dev->common.tag = HARDWARE_DEVICE_TAG; + dev->common.version = 0; + dev->common.module = (struct hw_module_t*) module; + dev->common.close = pn544_close; + + /* Example settings */ + dev->num_eeprom_settings = 0; + dev->eeprom_settings = NULL; + dev->linktype = PN544_LINK_TYPE_INVALID; + dev->device_node = NULL; + dev->enable_i2c_workaround = 0; + dev->i2c_device_address = 0; + + *device = (hw_device_t*) dev; + return 0; + } else { + return -EINVAL; + } +} + + +static struct hw_module_methods_t nfc_module_methods = { + .open = nfc_open, +}; + +struct nfc_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = NFC_HARDWARE_MODULE_ID, + .name = "Default NFC HW HAL", + .author = "The Android Open Source Project", + .methods = &nfc_module_methods, + }, +}; -- cgit v1.1 From 6b01e2eaf7fb7f167730c0bde1b55ae7ac928060 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Fri, 14 Sep 2012 17:21:22 -0700 Subject: Layer flags won't change between prepare and set Change-Id: I0f25766976e4f783066e5b6fd917d1769906e43e --- include/hardware/hwcomposer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 5488e75..0bebb98 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -97,8 +97,7 @@ typedef struct hwc_layer_1 { * Indicates this layer is the framebuffer surface used as the target of * OpenGL ES composition. If the HWC sets all other layers to HWC_OVERLAY * or HWC_BACKGROUND, then no OpenGL ES composition will be done, and - * this layer should be ignored during set(); the HWC_SKIP_LAYER flag - * will indicate this case. + * this layer should be ignored during set(). * * This flag (and the framebuffer surface layer) will only be used if the * HWC version is HWC_DEVICE_API_VERSION_1_1 or higher. In older versions, -- cgit v1.1 -- cgit v1.1 From eec87706d21fc0ac4ad10ede86943770b2533564 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 17 Sep 2012 09:59:42 -0700 Subject: Remote audio submix: blocking writes and sleeping reads. Change how the remote audio submix is handling piping audio through the pipe: - use a MonoPipe as audio sink for blocking writes, - use a MonoPipeReader as audio source for non blocking reads, and keep track of when recording started to align the time at which the in_read() call should return with the projected time of the recording duration. Change-Id: I8b0f8c56a0486806101e272dfbf9c6d2d1c11112 --- modules/audio_remote_submix/audio_hw.cpp | 224 ++++++++++++++++++++----------- 1 file changed, 144 insertions(+), 80 deletions(-) mode change 100644 => 100755 modules/audio_remote_submix/audio_hw.cpp diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp old mode 100644 new mode 100755 index 0e5589b..b17020a --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -15,7 +15,7 @@ */ #define LOG_TAG "r_submix" -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #include #include @@ -31,17 +31,23 @@ #include #include -#include -#include +//#include +//#include +#include +#include #include extern "C" { namespace android { -#define MAX_PIPE_DEPTH_IN_FRAMES (1024*4) +#define MAX_PIPE_DEPTH_IN_FRAMES (1024*8) +// The duration of MAX_READ_ATTEMPTS * READ_ATTEMPT_SLEEP_MS must be stricly inferior to +// the duration of a record buffer at the current record sample rate (of the device, not of +// the recording itself). Here we have: +// 3 * 5ms = 15ms < 1024 frames * 1000 / 48000 = 21.333ms #define MAX_READ_ATTEMPTS 3 -#define READ_ATTEMPT_SLEEP_MS 10 // 10ms between two read attempts when pipe is empty +#define READ_ATTEMPT_SLEEP_MS 5 // 5ms between two read attempts when pipe is empty #define DEFAULT_RATE_HZ 48000 // default sample rate struct submix_config { @@ -54,18 +60,21 @@ struct submix_config { struct submix_audio_device { struct audio_hw_device device; + bool output_standby; + bool input_standby; submix_config config; // Pipe variables: they handle the ring buffer that "pipes" audio: - // - from the submix virtual audio output == what needs to be played by - // the remotely, seen as an output for AudioFlinger + // - from the submix virtual audio output == what needs to be played + // remotely, seen as an output for AudioFlinger // - to the virtual audio source == what is captured by the component // which "records" the submix / virtual audio source, and handles it as needed. - // An usecase example is one where the component capturing the audio is then sending it over + // A usecase example is one where the component capturing the audio is then sending it over // Wifi for presentation on a remote Wifi Display device (e.g. a dongle attached to a TV, or a // TV with Wifi Display capabilities), or to a wireless audio player. - sp rsxSink; - sp rsxSource; + sp rsxSink; + sp rsxSource; + // device lock, also used to protect access to the audio pipe pthread_mutex_t lock; }; @@ -77,9 +86,13 @@ struct submix_stream_out { struct submix_stream_in { struct audio_stream_in stream; struct submix_audio_device *dev; -}; + bool output_standby; // output standby state as seen from record thread -static struct timespec currentTs; + // wall clock when recording starts + struct timespec record_start_time; + // how many frames have been requested to be read + int64_t read_counter_frames; +}; /* audio HAL functions */ @@ -142,7 +155,16 @@ static int out_set_format(struct audio_stream *stream, audio_format_t format) static int out_standby(struct audio_stream *stream) { - // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here + ALOGI("out_standby()"); + + const struct submix_stream_out *out = reinterpret_cast(stream); + + pthread_mutex_lock(&out->dev->lock); + + out->dev->output_standby = true; + + pthread_mutex_unlock(&out->dev->lock); + return 0; } @@ -181,12 +203,14 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) { //ALOGV("out_write(bytes=%d)", bytes); - ssize_t written = 0; + ssize_t written_frames = 0; struct submix_stream_out *out = reinterpret_cast(stream); pthread_mutex_lock(&out->dev->lock); - Pipe* sink = out->dev->rsxSink.get(); + out->dev->output_standby = false; + + MonoPipe* sink = out->dev->rsxSink.get(); if (sink != NULL) { out->dev->rsxSink->incStrong(buffer); } else { @@ -198,17 +222,23 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_unlock(&out->dev->lock); - const size_t frames = bytes / audio_stream_frame_size(&stream->common); - written = sink->write(buffer, frames); - if (written < 0) { - if (written == (ssize_t)NEGOTIATE) { + const size_t frame_size = audio_stream_frame_size(&stream->common); + const size_t frames = bytes / frame_size; + written_frames = sink->write(buffer, frames); + if (written_frames < 0) { + if (written_frames == (ssize_t)NEGOTIATE) { ALOGE("out_write() write to pipe returned NEGOTIATE"); - written = 0; + + pthread_mutex_lock(&out->dev->lock); + out->dev->rsxSink->decStrong(buffer); + pthread_mutex_unlock(&out->dev->lock); + + written_frames = 0; return 0; } else { // write() returned UNDERRUN or WOULD_BLOCK, retry - ALOGE("out_write() write to pipe returned unexpected %16lx", written); - written = sink->write(buffer, frames); + ALOGE("out_write() write to pipe returned unexpected %16lx", written_frames); + written_frames = sink->write(buffer, frames); } } @@ -218,25 +248,13 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_unlock(&out->dev->lock); - struct timespec newTs; - int toSleepUs = 0; - int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); - if (rc == 0) { - time_t sec = newTs.tv_sec - currentTs.tv_sec; - long nsec = newTs.tv_nsec - currentTs.tv_nsec; - if (nsec < 0) { - --sec; - nsec += 1000000000; - } - if ((nsec / 1000) < (frames * 1000000 / out_get_sample_rate(&stream->common))) { - toSleepUs = (frames * 1000000 / out_get_sample_rate(&stream->common)) - (nsec/1000); - ALOGI("sleeping %dus", toSleepUs); - usleep(toSleepUs); - } + if (written_frames < 0) { + ALOGE("out_write() failed writing to pipe with %16lx", written_frames); + return 0; + } else { + ALOGV("out_write() wrote %lu bytes)", written_frames * frame_size); + return written_frames * frame_size; } - clock_gettime(CLOCK_MONOTONIC, ¤tTs); - //ALOGV("out_write(bytes=%d) written=%d", bytes, written); - return written * audio_stream_frame_size(&stream->common); } static int out_get_render_position(const struct audio_stream_out *stream, @@ -265,7 +283,7 @@ static int out_get_next_write_timestamp(const struct audio_stream_out *stream, static uint32_t in_get_sample_rate(const struct audio_stream *stream) { const struct submix_stream_in *in = reinterpret_cast(stream); - ALOGV("in_get_sample_rate() returns %u", in->dev->config.rate); + //ALOGV("in_get_sample_rate() returns %u", in->dev->config.rate); return in->dev->config.rate; } @@ -303,7 +321,15 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) static int in_standby(struct audio_stream *stream) { - // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here + ALOGI("in_standby()"); + const struct submix_stream_in *in = reinterpret_cast(stream); + + pthread_mutex_lock(&in->dev->lock); + + in->dev->input_standby = true; + + pthread_mutex_unlock(&in->dev->lock); + return 0; } @@ -333,15 +359,32 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, { //ALOGV("in_read bytes=%u", bytes); ssize_t frames_read = -1977; - const struct submix_stream_in *in = reinterpret_cast(stream); + struct submix_stream_in *in = reinterpret_cast(stream); const size_t frame_size = audio_stream_frame_size(&stream->common); + const size_t frames_to_read = bytes / frame_size; pthread_mutex_lock(&in->dev->lock); - PipeReader* source = in->dev->rsxSource.get(); + const bool output_standby_transition = (in->output_standby != in->dev->output_standby); + in->output_standby = in->dev->output_standby; + + if (in->dev->input_standby || output_standby_transition) { + in->dev->input_standby = false; + // keep track of when we exit input standby (== first read == start "real recording") + // or when we start recording silence, and reset projected time + int rc = clock_gettime(CLOCK_MONOTONIC, &in->record_start_time); + if (rc == 0) { + in->read_counter_frames = 0; + } + } + + in->read_counter_frames += frames_to_read; + + MonoPipeReader* source = in->dev->rsxSource.get(); if (source != NULL) { in->dev->rsxSource->incStrong(in); } else { + ALOGE("no audio pipe yet we're trying to read!"); pthread_mutex_unlock(&in->dev->lock); usleep((bytes / frame_size) * 1000000 / in_get_sample_rate(&stream->common)); memset(buffer, 0, bytes); @@ -350,40 +393,25 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); - - int attempts = MAX_READ_ATTEMPTS; - size_t remaining_frames = bytes / frame_size; + // read the data from the pipe (it's non blocking) + size_t remaining_frames = frames_to_read; + int attempts = 0; char* buff = (char*)buffer; - while (attempts > 0) { + while ((remaining_frames > 0) && (attempts < MAX_READ_ATTEMPTS)) { + attempts++; frames_read = source->read(buff, remaining_frames, AudioBufferProvider::kInvalidPTS); if (frames_read > 0) { - //ALOGV(" in_read got frames=%u size=%u attempts=%d", remaining_frames, frame_size, attempts); remaining_frames -= frames_read; buff += frames_read * frame_size; - if (remaining_frames == 0) { - // TODO simplify code by breaking out of loop - - pthread_mutex_lock(&in->dev->lock); - - in->dev->rsxSource->decStrong(in); - - pthread_mutex_unlock(&in->dev->lock); - - return bytes; - } - } else if (frames_read == 0) { - // TODO sleep should be tied to how much data is expected - //ALOGW("sleeping %dms", READ_ATTEMPT_SLEEP_MS); - usleep(READ_ATTEMPT_SLEEP_MS*1000); - attempts--; - } else { // frames_read is an error code - if (frames_read != (ssize_t)OVERRUN) { - attempts--; - } - // else OVERRUN: error has been signaled, ok to read, do not decrement counter + //ALOGV(" in_read (att=%d) got %ld frames, remaining=%u", + // attempts, frames_read, remaining_frames); + } else { + //ALOGE(" in_read read returned %ld", frames_read); + usleep(READ_ATTEMPT_SLEEP_MS * 1000); } } + // done using the source pthread_mutex_lock(&in->dev->lock); in->dev->rsxSource->decStrong(in); @@ -391,17 +419,48 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, pthread_mutex_unlock(&in->dev->lock); if (remaining_frames > 0) { - ALOGW("remaining_frames = %d", remaining_frames); + ALOGV(" remaining_frames = %d", remaining_frames); memset(((char*)buffer)+ bytes - (remaining_frames * frame_size), 0, remaining_frames * frame_size); - return bytes; } - if (frames_read < 0) { - ALOGE("in_read error=%16lx", frames_read); + // compute how much we need to sleep after reading the data by comparing the wall clock with + // the projected time at which we should return. + struct timespec time_after_read;// wall clock after reading from the pipe + struct timespec record_duration;// observed record duration + int rc = clock_gettime(CLOCK_MONOTONIC, &time_after_read); + const uint32_t sample_rate = in_get_sample_rate(&stream->common); + if (rc == 0) { + // for how long have we been recording? + record_duration.tv_sec = time_after_read.tv_sec - in->record_start_time.tv_sec; + record_duration.tv_nsec = time_after_read.tv_nsec - in->record_start_time.tv_nsec; + if (record_duration.tv_nsec < 0) { + record_duration.tv_sec--; + record_duration.tv_nsec += 1000000000; + } + + // read_counter_frames contains the number of frames that have been read since the beginning + // of recording (including this call): it's converted to usec and compared to how long we've + // been recording for, which gives us how long we must wait to sync the projected recording + // time, and the observed recording time + long projected_vs_observed_offset_us = + ((int64_t)(in->read_counter_frames + - (record_duration.tv_sec*sample_rate))) + * 1000000 / sample_rate + - (record_duration.tv_nsec / 1000); + + ALOGV(" record duration %5lds %3ldms, will wait: %7ldus", + record_duration.tv_sec, record_duration.tv_nsec/1000000, + projected_vs_observed_offset_us); + if (projected_vs_observed_offset_us > 0) { + usleep(projected_vs_observed_offset_us); + } } - ALOGE_IF(attempts == 0, "attempts == 0 "); - return 0; + + + ALOGV("in_read returns %d", bytes); + return bytes; + } static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) @@ -481,12 +540,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, config->sample_rate == 48000 ? Format_SR48_C2_I16 : Format_SR44_1_C2_I16; const NBAIO_Format offers[1] = {format}; size_t numCounterOffers = 0; - // creating a Pipe, not a MonoPipe with optional blocking set to true, so audio frames - // entering a full sink will overwrite the contents of the pipe. - Pipe* sink = new Pipe(MAX_PIPE_DEPTH_IN_FRAMES, format); + // creating a MonoPipe with optional blocking set to true. + MonoPipe* sink = new MonoPipe(MAX_PIPE_DEPTH_IN_FRAMES, format, true/*writeCanBlock*/); ssize_t index = sink->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); - PipeReader* source = new PipeReader(*sink); + MonoPipeReader* source = new MonoPipeReader(sink); numCounterOffers = 0; index = source->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); @@ -636,6 +694,9 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->dev = rsxadev; + in->read_counter_frames = 0; + in->output_standby = rsxadev->output_standby; + pthread_mutex_unlock(&rsxadev->lock); return 0; @@ -706,6 +767,9 @@ static int adev_open(const hw_module_t* module, const char* name, rsxadev->device.close_input_stream = adev_close_input_stream; rsxadev->device.dump = adev_dump; + rsxadev->input_standby = true; + rsxadev->output_standby = true; + *device = &rsxadev->device.common; return 0; -- cgit v1.1 From 35a2c167b4ee090b5dd9779ecb40f82cdaf1c74d Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 17 Sep 2012 10:13:26 -0700 Subject: Turn off logs in remote submix audio module Change-Id: I61cd15534b1cd764b06f615569cdf02edbba909c --- modules/audio_remote_submix/audio_hw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index b17020a..82bac1a 100755 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -15,7 +15,7 @@ */ #define LOG_TAG "r_submix" -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include #include -- cgit v1.1 From 97c262fc848c407f316fd7fe2b468a540f3bc38f Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 17 Sep 2012 18:27:56 -0700 Subject: Remote submix: fix sink/source reference count handling The reference count on the strong pointers to the audio sink and source should be done on the object retrieved from the device structure, not by accessing the corresponding fields, as they can be cleared while reading or writing audio data. Change-Id: I446a2c7bdcb0758b4013b0ad75450a15203fb9da --- modules/audio_remote_submix/audio_hw.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index 82bac1a..0f8adab 100755 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -212,7 +212,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, MonoPipe* sink = out->dev->rsxSink.get(); if (sink != NULL) { - out->dev->rsxSink->incStrong(buffer); + sink->incStrong(buffer); } else { pthread_mutex_unlock(&out->dev->lock); ALOGE("out_write without a pipe!"); @@ -230,7 +230,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, ALOGE("out_write() write to pipe returned NEGOTIATE"); pthread_mutex_lock(&out->dev->lock); - out->dev->rsxSink->decStrong(buffer); + sink->decStrong(buffer); pthread_mutex_unlock(&out->dev->lock); written_frames = 0; @@ -244,7 +244,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_lock(&out->dev->lock); - out->dev->rsxSink->decStrong(buffer); + sink->decStrong(buffer); pthread_mutex_unlock(&out->dev->lock); @@ -382,7 +382,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, MonoPipeReader* source = in->dev->rsxSource.get(); if (source != NULL) { - in->dev->rsxSource->incStrong(in); + source->incStrong(buffer); } else { ALOGE("no audio pipe yet we're trying to read!"); pthread_mutex_unlock(&in->dev->lock); @@ -414,7 +414,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, // done using the source pthread_mutex_lock(&in->dev->lock); - in->dev->rsxSource->decStrong(in); + source->decStrong(buffer); pthread_mutex_unlock(&in->dev->lock); -- cgit v1.1 From 05f49546a9c70805cbd77e71c7998652f91ec535 Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Tue, 18 Sep 2012 12:15:26 -0700 Subject: Initial Bluetooth open source release Change-Id: I27bb95db854806d7deedaf6c622b17cb09f62f16 --- include/hardware/bluetooth.h | 441 +++++++++++++++++++++++++++++++++++++++++++ include/hardware/bt_av.h | 90 +++++++++ include/hardware/bt_hf.h | 284 ++++++++++++++++++++++++++++ include/hardware/bt_hh.h | 179 ++++++++++++++++++ include/hardware/bt_hl.h | 123 ++++++++++++ include/hardware/bt_pan.h | 87 +++++++++ include/hardware/bt_sock.h | 58 ++++++ 7 files changed, 1262 insertions(+) create mode 100644 include/hardware/bluetooth.h create mode 100644 include/hardware/bt_av.h create mode 100644 include/hardware/bt_hf.h create mode 100644 include/hardware/bt_hh.h create mode 100644 include/hardware/bt_hl.h create mode 100644 include/hardware/bt_pan.h create mode 100644 include/hardware/bt_sock.h diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h new file mode 100644 index 0000000..be7f0b1 --- /dev/null +++ b/include/hardware/bluetooth.h @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BLUETOOTH_H +#define ANDROID_INCLUDE_BLUETOOTH_H + +#include +#include +#include + +#include + +__BEGIN_DECLS + +/** + * The Bluetooth Hardware Module ID + */ + +#define BT_HARDWARE_MODULE_ID "bluetooth" +#define BT_STACK_MODULE_ID "bluetooth" +#define BT_STACK_TEST_MODULE_ID "bluetooth_test" + + +/* Bluetooth profile interface IDs */ + +#define BT_PROFILE_HANDSFREE_ID "handsfree" +#define BT_PROFILE_ADVANCED_AUDIO_ID "a2dp" +#define BT_PROFILE_HEALTH_ID "health" +#define BT_PROFILE_SOCKETS_ID "socket" +#define BT_PROFILE_HIDHOST_ID "hidhost" +#define BT_PROFILE_PAN_ID "pan" + + +/** Bluetooth Address */ +typedef struct { + uint8_t address[6]; +} __attribute__((packed))bt_bdaddr_t; + +/** Bluetooth Device Name */ +typedef struct { + uint8_t name[248]; +} __attribute__((packed))bt_bdname_t; + +/** Bluetooth Adapter Visibility Modes*/ +typedef enum { + BT_SCAN_MODE_NONE, + BT_SCAN_MODE_CONNECTABLE, + BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE +} bt_scan_mode_t; + +/** Bluetooth Adapter State */ +typedef enum { + BT_STATE_OFF, + BT_STATE_ON +} bt_state_t; + +/** Bluetooth Error Status */ +/** We need to build on this */ + +typedef enum { + BT_STATUS_SUCCESS, + BT_STATUS_FAIL, + BT_STATUS_NOT_READY, + BT_STATUS_NOMEM, + BT_STATUS_BUSY, + BT_STATUS_DONE, /* request already completed */ + BT_STATUS_UNSUPPORTED, + BT_STATUS_PARM_INVALID, + BT_STATUS_UNHANDLED, + BT_STATUS_AUTH_FAILURE, + BT_STATUS_RMT_DEV_DOWN + +} bt_status_t; + +/** Bluetooth PinKey Code */ +typedef struct { + uint8_t pin[16]; +} __attribute__((packed))bt_pin_code_t; + +/** Bluetooth Adapter Discovery state */ +typedef enum { + BT_DISCOVERY_STOPPED, + BT_DISCOVERY_STARTED +} bt_discovery_state_t; + +/** Bluetooth ACL connection state */ +typedef enum { + BT_ACL_STATE_CONNECTED, + BT_ACL_STATE_DISCONNECTED +} bt_acl_state_t; + +/** Bluetooth 128-bit UUID */ +typedef struct { + uint8_t uu[16]; +} bt_uuid_t; + +/** Bluetooth SDP service record */ +typedef struct +{ + bt_uuid_t uuid; + uint16_t channel; + char name[256]; // what's the maximum length +} bt_service_record_t; + +/* Bluetooth Adapter and Remote Device property types */ +typedef enum { + /* Properties common to both adapter and remote device */ + /** + * Description - Bluetooth Device Name + * Access mode - Adapter name can be GET/SET. Remote device can be GET + * Data type - bt_bdname_t + */ + BT_PROPERTY_BDNAME = 0x1, + /** + * Description - Bluetooth Device Address + * Access mode - Only GET. + * Data type - bt_bdaddr_t + */ + BT_PROPERTY_BDADDR, + /** + * Description - Bluetooth Service 128-bit UUIDs + * Access mode - Only GET. + * Data type - Array of bt_uuid_t (Array size inferred from property length). + */ + BT_PROPERTY_UUIDS, + /** + * Description - Bluetooth Class of Device as found in Assigned Numbers + * Access mode - Only GET. + * Data type - uint32_t. + */ + BT_PROPERTY_CLASS_OF_DEVICE, + /** + * Description - Device Type - BREDR, BLE or DUAL Mode + * Access mode - Only GET. + * Data type - bt_device_type_t + */ + BT_PROPERTY_TYPE_OF_DEVICE, + /** + * Description - Bluetooth Service Record + * Access mode - Only GET. + * Data type - bt_service_record_t + */ + BT_PROPERTY_SERVICE_RECORD, + + /* Properties unique to adapter */ + /** + * Description - Bluetooth Adapter scan mode + * Access mode - GET and SET + * Data type - bt_scan_mode_t. + */ + BT_PROPERTY_ADAPTER_SCAN_MODE, + /** + * Description - List of bonded devices + * Access mode - Only GET. + * Data type - Array of bt_bdaddr_t of the bonded remote devices + * (Array size inferred from property length). + */ + BT_PROPERTY_ADAPTER_BONDED_DEVICES, + /** + * Description - Bluetooth Adapter Discovery timeout (in seconds) + * Access mode - GET and SET + * Data type - uint32_t + */ + BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, + + /* Properties unique to remote device */ + /** + * Description - User defined friendly name of the remote device + * Access mode - GET and SET + * Data type - bt_bdname_t. + */ + BT_PROPERTY_REMOTE_FRIENDLY_NAME, + /** + * Description - RSSI value of the inquired remote device + * Access mode - Only GET. + * Data type - int32_t. + */ + BT_PROPERTY_REMOTE_RSSI, + + BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF, +} bt_property_type_t; + +/** Bluetooth Adapter Property data structure */ +typedef struct +{ + bt_property_type_t type; + int len; + void *val; +} bt_property_t; + +/** Bluetooth Device Type */ +typedef enum { + BT_DEVICE_DEVTYPE_BREDR = 0x1, + BT_DEVICE_DEVTYPE_BLE, + BT_DEVICE_DEVTYPE_DUAL +} bt_device_type_t; +/** Bluetooth Bond state */ +typedef enum { + BT_BOND_STATE_NONE, + BT_BOND_STATE_BONDING, + BT_BOND_STATE_BONDED +} bt_bond_state_t; + +/** Bluetooth SSP Bonding Variant */ +typedef enum { + BT_SSP_VARIANT_PASSKEY_CONFIRMATION, + BT_SSP_VARIANT_PASSKEY_ENTRY, + BT_SSP_VARIANT_CONSENT, + BT_SSP_VARIANT_PASSKEY_NOTIFICATION +} bt_ssp_variant_t; + +#define BT_MAX_NUM_UUIDS 32 + +/** Bluetooth Interface callbacks */ + +/** Bluetooth Enable/Disable Callback. */ +typedef void (*adapter_state_changed_callback)(bt_state_t state); + +/** GET/SET Adapter Properties callback */ +/* TODO: For the GET/SET property APIs/callbacks, we may need a session + * identifier to associate the call with the callback. This would be needed + * whenever more than one simultaneous instance of the same adapter_type + * is get/set. + * + * If this is going to be handled in the Java framework, then we do not need + * to manage sessions here. + */ +typedef void (*adapter_properties_callback)(bt_status_t status, + int num_properties, + bt_property_t *properties); + +/** GET/SET Remote Device Properties callback */ +/** TODO: For remote device properties, do not see a need to get/set + * multiple properties - num_properties shall be 1 + */ +typedef void (*remote_device_properties_callback)(bt_status_t status, + bt_bdaddr_t *bd_addr, + int num_properties, + bt_property_t *properties); + +/** New device discovered callback */ +/** If EIR data is not present, then BD_NAME and RSSI shall be NULL and -1 + * respectively */ +typedef void (*device_found_callback)(int num_properties, + bt_property_t *properties); + +/** Discovery state changed callback */ +typedef void (*discovery_state_changed_callback)(bt_discovery_state_t state); + +/** Bluetooth Legacy PinKey Request callback */ +typedef void (*pin_request_callback)(bt_bdaddr_t *remote_bd_addr, + bt_bdname_t *bd_name, uint32_t cod); + +/** Bluetooth SSP Request callback - Just Works & Numeric Comparison*/ +/** pass_key - Shall be 0 for BT_SSP_PAIRING_VARIANT_CONSENT & + * BT_SSP_PAIRING_PASSKEY_ENTRY */ +/* TODO: Passkey request callback shall not be needed for devices with display + * capability. We still need support this in the stack for completeness */ +typedef void (*ssp_request_callback)(bt_bdaddr_t *remote_bd_addr, + bt_bdname_t *bd_name, + uint32_t cod, + bt_ssp_variant_t pairing_variant, + uint32_t pass_key); + +/** Bluetooth Bond state changed callback */ +/* Invoked in response to create_bond, cancel_bond or remove_bond */ +typedef void (*bond_state_changed_callback)(bt_status_t status, + bt_bdaddr_t *remote_bd_addr, + bt_bond_state_t state); + +/** Bluetooth ACL connection state changed callback */ +typedef void (*acl_state_changed_callback)(bt_status_t status, bt_bdaddr_t *remote_bd_addr, + bt_acl_state_t state); + +typedef enum { + ASSOCIATE_JVM, + DISASSOCIATE_JVM +} bt_cb_thread_evt; + +/** Thread Associate/Disassociate JVM Callback */ +/* Callback that is invoked by the callback thread to allow upper layer to attach/detach to/from + * the JVM */ +typedef void (*callback_thread_event)(bt_cb_thread_evt evt); + +/** Bluetooth Test Mode Callback */ +/* Receive any HCI event from controller. Must be in DUT Mode for this callback to be received */ +typedef void (*dut_mode_recv_callback)(uint16_t opcode, uint8_t *buf, uint8_t len); + +/** TODO: Add callbacks for Link Up/Down and other generic + * notifications/callbacks */ + +/** Bluetooth DM callback structure. */ +typedef struct { + /** set to sizeof(bt_callbacks_t) */ + size_t size; + adapter_state_changed_callback adapter_state_changed_cb; + adapter_properties_callback adapter_properties_cb; + remote_device_properties_callback remote_device_properties_cb; + device_found_callback device_found_cb; + discovery_state_changed_callback discovery_state_changed_cb; + pin_request_callback pin_request_cb; + ssp_request_callback ssp_request_cb; + bond_state_changed_callback bond_state_changed_cb; + acl_state_changed_callback acl_state_changed_cb; + callback_thread_event thread_evt_cb; + dut_mode_recv_callback dut_mode_recv_cb; +} bt_callbacks_t; + +/** NOTE: By default, no profiles are initialized at the time of init/enable. + * Whenever the application invokes the 'init' API of a profile, then one of + * the following shall occur: + * + * 1.) If Bluetooth is not enabled, then the Bluetooth core shall mark the + * profile as enabled. Subsequently, when the application invokes the + * Bluetooth 'enable', as part of the enable sequence the profile that were + * marked shall be enabled by calling appropriate stack APIs. The + * 'adapter_properties_cb' shall return the list of UUIDs of the + * enabled profiles. + * + * 2.) If Bluetooth is enabled, then the Bluetooth core shall invoke the stack + * profile API to initialize the profile and trigger a + * 'adapter_properties_cb' with the current list of UUIDs including the + * newly added profile's UUID. + * + * The reverse shall occur whenever the profile 'cleanup' APIs are invoked + */ + +/** Represents the standard Bluetooth DM interface. */ +typedef struct { + /** set to sizeof(bt_interface_t) */ + size_t size; + /** + * Opens the interface and provides the callback routines + * to the implemenation of this interface. + */ + int (*init)(bt_callbacks_t* callbacks ); + + /** Enable Bluetooth. */ + int (*enable)(void); + + /** Disable Bluetooth. */ + int (*disable)(void); + + /** Closes the interface. */ + void (*cleanup)(void); + + /** Get all Bluetooth Adapter properties at init */ + int (*get_adapter_properties)(void); + + /** Get Bluetooth Adapter property of 'type' */ + int (*get_adapter_property)(bt_property_type_t type); + + /** Set Bluetooth Adapter property of 'type' */ + /* Based on the type, val shall be one of + * bt_bdaddr_t or bt_bdname_t or bt_scanmode_t etc + */ + int (*set_adapter_property)(const bt_property_t *property); + + /** Get all Remote Device properties */ + int (*get_remote_device_properties)(bt_bdaddr_t *remote_addr); + + /** Get Remote Device property of 'type' */ + int (*get_remote_device_property)(bt_bdaddr_t *remote_addr, + bt_property_type_t type); + + /** Set Remote Device property of 'type' */ + int (*set_remote_device_property)(bt_bdaddr_t *remote_addr, + const bt_property_t *property); + + /** Get Remote Device's service record for the given UUID */ + int (*get_remote_service_record)(bt_bdaddr_t *remote_addr, + bt_uuid_t *uuid); + + /** Start SDP to get remote services */ + int (*get_remote_services)(bt_bdaddr_t *remote_addr); + + /** Start Discovery */ + int (*start_discovery)(void); + + /** Cancel Discovery */ + int (*cancel_discovery)(void); + + /** Create Bluetooth Bonding */ + int (*create_bond)(const bt_bdaddr_t *bd_addr); + + /** Remove Bond */ + int (*remove_bond)(const bt_bdaddr_t *bd_addr); + + /** Cancel Bond */ + int (*cancel_bond)(const bt_bdaddr_t *bd_addr); + + /** BT Legacy PinKey Reply */ + /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */ + int (*pin_reply)(const bt_bdaddr_t *bd_addr, uint8_t accept, + uint8_t pin_len, bt_pin_code_t *pin_code); + + /** BT SSP Reply - Just Works, Numeric Comparison and Passkey + * passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON & + * BT_SSP_VARIANT_CONSENT + * For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey + * shall be zero */ + int (*ssp_reply)(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant, + uint8_t accept, uint32_t passkey); + + /** Get Bluetooth profile interface */ + const void* (*get_profile_interface) (const char *profile_id); + + /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */ + /* Configure DUT Mode - Use this mode to enter/exit DUT mode */ + int (*dut_mode_configure)(uint8_t enable); + + /* Send any test HCI (vendor-specific) command to the controller. Must be in DUT Mode */ + int (*dut_mode_send)(uint16_t opcode, uint8_t *buf, uint8_t len); +} bt_interface_t; + +/** TODO: Need to add APIs for Service Discovery, Service authorization and + * connection management. Also need to add APIs for configuring + * properties of remote bonded devices such as name, UUID etc. */ + +typedef struct { + struct hw_device_t common; + const bt_interface_t* (*get_bluetooth_interface)(); +} bluetooth_device_t; + +typedef bluetooth_device_t bluetooth_module_t; +__END_DECLS + +#endif /* ANDROID_INCLUDE_BLUETOOTH_H */ diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h new file mode 100644 index 0000000..2ec00c3 --- /dev/null +++ b/include/hardware/bt_av.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_AV_H +#define ANDROID_INCLUDE_BT_AV_H + +__BEGIN_DECLS + +/* Bluetooth AV connection states */ +typedef enum { + BTAV_CONNECTION_STATE_DISCONNECTED = 0, + BTAV_CONNECTION_STATE_CONNECTING, + BTAV_CONNECTION_STATE_CONNECTED, + BTAV_CONNECTION_STATE_DISCONNECTING +} btav_connection_state_t; + +/* Bluetooth AV datapath states */ +typedef enum { + BTAV_AUDIO_STATE_REMOTE_SUSPEND = 0, + BTAV_AUDIO_STATE_STOPPED, + BTAV_AUDIO_STATE_STARTED, +} btav_audio_state_t; + + +/** Callback for connection state change. + * state will have one of the values from btav_connection_state_t + */ +typedef void (* btav_connection_state_callback)(btav_connection_state_t state, + bt_bdaddr_t *bd_addr); + +/** Callback for audiopath state change. + * state will have one of the values from btav_audio_state_t + */ +typedef void (* btav_audio_state_callback)(btav_audio_state_t state, + bt_bdaddr_t *bd_addr); + +/** BT-AV callback structure. */ +typedef struct { + /** set to sizeof(btav_callbacks_t) */ + size_t size; + btav_connection_state_callback connection_state_cb; + btav_audio_state_callback audio_state_cb; +} btav_callbacks_t; + +/** + * NOTE: + * + * 1. AVRCP 1.0 shall be supported initially. AVRCP passthrough commands + * shall be handled internally via uinput + * + * 2. A2DP data path shall be handled via a socket pipe between the AudioFlinger + * android_audio_hw library and the Bluetooth stack. + * + */ +/** Represents the standard BT-AV interface. */ +typedef struct { + + /** set to sizeof(btav_interface_t) */ + size_t size; + /** + * Register the BtAv callbacks + */ + bt_status_t (*init)( btav_callbacks_t* callbacks ); + + /** connect to headset */ + bt_status_t (*connect)( bt_bdaddr_t *bd_addr ); + + /** dis-connect from headset */ + bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr ); + + /** Closes the interface. */ + void (*cleanup)( void ); +} btav_interface_t; + +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_AV_H */ diff --git a/include/hardware/bt_hf.h b/include/hardware/bt_hf.h new file mode 100644 index 0000000..6135ac4 --- /dev/null +++ b/include/hardware/bt_hf.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_HF_H +#define ANDROID_INCLUDE_BT_HF_H + +__BEGIN_DECLS + +/* AT response code - OK/Error */ +typedef enum { + BTHF_AT_RESPONSE_ERROR = 0, + BTHF_AT_RESPONSE_OK +} bthf_at_response_t; + +typedef enum { + BTHF_CONNECTION_STATE_DISCONNECTED = 0, + BTHF_CONNECTION_STATE_CONNECTING, + BTHF_CONNECTION_STATE_CONNECTED, + BTHF_CONNECTION_STATE_SLC_CONNECTED, + BTHF_CONNECTION_STATE_DISCONNECTING +} bthf_connection_state_t; + +typedef enum { + BTHF_AUDIO_STATE_DISCONNECTED = 0, + BTHF_AUDIO_STATE_CONNECTING, + BTHF_AUDIO_STATE_CONNECTED, + BTHF_AUDIO_STATE_DISCONNECTING +} bthf_audio_state_t; + +typedef enum { + BTHF_VR_STATE_STOPPED = 0, + BTHF_VR_STATE_STARTED +} bthf_vr_state_t; + +typedef enum { + BTHF_VOLUME_TYPE_SPK = 0, + BTHF_VOLUME_TYPE_MIC +} bthf_volume_type_t; + +/* Noise Reduction and Echo Cancellation */ +typedef enum +{ + BTHF_NREC_STOP, + BTHF_NREC_START +} bthf_nrec_t; + +/* CHLD - Call held handling */ +typedef enum +{ + BTHF_CHLD_TYPE_RELEASEHELD, // Terminate all held or set UDUB("busy") to a waiting call + BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD, // Terminate all active calls and accepts a waiting/held call + BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD, // Hold all active calls and accepts a waiting/held call + BTHF_CHLD_TYPE_ADDHELDTOCONF, // Add all held calls to a conference +} bthf_chld_type_t; + +/** Callback for connection state change. + * state will have one of the values from BtHfConnectionState + */ +typedef void (* bthf_connection_state_callback)(bthf_connection_state_t state, bt_bdaddr_t *bd_addr); + +/** Callback for audio connection state change. + * state will have one of the values from BtHfAudioState + */ +typedef void (* bthf_audio_state_callback)(bthf_audio_state_t state, bt_bdaddr_t *bd_addr); + +/** Callback for VR connection state change. + * state will have one of the values from BtHfVRState + */ +typedef void (* bthf_vr_cmd_callback)(bthf_vr_state_t state); + +/** Callback for answer incoming call (ATA) + */ +typedef void (* bthf_answer_call_cmd_callback)(); + +/** Callback for disconnect call (AT+CHUP) + */ +typedef void (* bthf_hangup_call_cmd_callback)(); + +/** Callback for disconnect call (AT+CHUP) + * type will denote Speaker/Mic gain (BtHfVolumeControl). + */ +typedef void (* bthf_volume_cmd_callback)(bthf_volume_type_t type, int volume); + +/** Callback for dialing an outgoing call + * If number is NULL, redial + */ +typedef void (* bthf_dial_call_cmd_callback)(char *number); + +/** Callback for sending DTMF tones + * tone contains the dtmf character to be sent + */ +typedef void (* bthf_dtmf_cmd_callback)(char tone); + +/** Callback for enabling/disabling noise reduction/echo cancellation + * value will be 1 to enable, 0 to disable + */ +typedef void (* bthf_nrec_cmd_callback)(bthf_nrec_t nrec); + +/** Callback for call hold handling (AT+CHLD) + * value will contain the call hold command (0, 1, 2, 3) + */ +typedef void (* bthf_chld_cmd_callback)(bthf_chld_type_t chld); + +/** Callback for CNUM (subscriber number) + */ +typedef void (* bthf_cnum_cmd_callback)(); + +/** Callback for indicators (CIND) + */ +typedef void (* bthf_cind_cmd_callback)(); + +/** Callback for operator selection (COPS) + */ +typedef void (* bthf_cops_cmd_callback)(); + +/** Callback for call list (AT+CLCC) + */ +typedef void (* bthf_clcc_cmd_callback) (); + +/** Callback for unknown AT command recd from HF + * at_string will contain the unparsed AT string + */ +typedef void (* bthf_unknown_at_cmd_callback)(char *at_string); + +/** Callback for keypressed (HSP) event. + */ +typedef void (* bthf_key_pressed_cmd_callback)(); + +/** BT-HF callback structure. */ +typedef struct { + /** set to sizeof(BtHfCallbacks) */ + size_t size; + bthf_connection_state_callback connection_state_cb; + bthf_audio_state_callback audio_state_cb; + bthf_vr_cmd_callback vr_cmd_cb; + bthf_answer_call_cmd_callback answer_call_cmd_cb; + bthf_hangup_call_cmd_callback hangup_call_cmd_cb; + bthf_volume_cmd_callback volume_cmd_cb; + bthf_dial_call_cmd_callback dial_call_cmd_cb; + bthf_dtmf_cmd_callback dtmf_cmd_cb; + bthf_nrec_cmd_callback nrec_cmd_cb; + bthf_chld_cmd_callback chld_cmd_cb; + bthf_cnum_cmd_callback cnum_cmd_cb; + bthf_cind_cmd_callback cind_cmd_cb; + bthf_cops_cmd_callback cops_cmd_cb; + bthf_clcc_cmd_callback clcc_cmd_cb; + bthf_unknown_at_cmd_callback unknown_at_cmd_cb; + bthf_key_pressed_cmd_callback key_pressed_cmd_cb; +} bthf_callbacks_t; + +/** Network Status */ +typedef enum +{ + BTHF_NETWORK_STATE_NOT_AVAILABLE = 0, + BTHF_NETWORK_STATE_AVAILABLE +} bthf_network_state_t; + +/** Service type */ +typedef enum +{ + BTHF_SERVICE_TYPE_HOME = 0, + BTHF_SERVICE_TYPE_ROAMING +} bthf_service_type_t; + +typedef enum { + BTHF_CALL_STATE_ACTIVE = 0, + BTHF_CALL_STATE_HELD, + BTHF_CALL_STATE_DIALING, + BTHF_CALL_STATE_ALERTING, + BTHF_CALL_STATE_INCOMING, + BTHF_CALL_STATE_WAITING, + BTHF_CALL_STATE_IDLE +} bthf_call_state_t; + +typedef enum { + BTHF_CALL_DIRECTION_OUTGOING = 0, + BTHF_CALL_DIRECTION_INCOMING +} bthf_call_direction_t; + +typedef enum { + BTHF_CALL_TYPE_VOICE = 0, + BTHF_CALL_TYPE_DATA, + BTHF_CALL_TYPE_FAX +} bthf_call_mode_t; + +typedef enum { + BTHF_CALL_MPTY_TYPE_SINGLE = 0, + BTHF_CALL_MPTY_TYPE_MULTI +} bthf_call_mpty_type_t; + +typedef enum { + BTHF_CALL_ADDRTYPE_UNKNOWN = 0x81, + BTHF_CALL_ADDRTYPE_INTERNATIONAL = 0x91 +} bthf_call_addrtype_t; +/** Represents the standard BT-HF interface. */ +typedef struct { + + /** set to sizeof(BtHfInterface) */ + size_t size; + /** + * Register the BtHf callbacks + */ + bt_status_t (*init)( bthf_callbacks_t* callbacks ); + + /** connect to headset */ + bt_status_t (*connect)( bt_bdaddr_t *bd_addr ); + + /** dis-connect from headset */ + bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr ); + + /** create an audio connection */ + bt_status_t (*connect_audio)( bt_bdaddr_t *bd_addr ); + + /** close the audio connection */ + bt_status_t (*disconnect_audio)( bt_bdaddr_t *bd_addr ); + + /** start voice recognition */ + bt_status_t (*start_voice_recognition)(); + + /** stop voice recognition */ + bt_status_t (*stop_voice_recognition)(); + + /** volume control */ + bt_status_t (*volume_control) (bthf_volume_type_t type, int volume); + + /** Combined device status change notification */ + bt_status_t (*device_status_notification)(bthf_network_state_t ntk_state, bthf_service_type_t svc_type, int signal, + int batt_chg); + + /** Response for COPS command */ + bt_status_t (*cops_response)(const char *cops); + + /** Response for CIND command */ + bt_status_t (*cind_response)(int svc, int num_active, int num_held, bthf_call_state_t call_setup_state, + int signal, int roam, int batt_chg); + + /** Pre-formatted AT response, typically in response to unknown AT cmd */ + bt_status_t (*formatted_at_response)(const char *rsp); + + /** ok/error response + * ERROR (0) + * OK (1) + */ + bt_status_t (*at_response) (bthf_at_response_t response_code, int error_code); + + /** response for CLCC command + * Can be iteratively called for each call index + * Call index of 0 will be treated as NULL termination (Completes response) + */ + bt_status_t (*clcc_response) (int index, bthf_call_direction_t dir, + bthf_call_state_t state, bthf_call_mode_t mode, + bthf_call_mpty_type_t mpty, const char *number, + bthf_call_addrtype_t type); + + /** notify of a call state change + * Each update notifies + * 1. Number of active/held/ringing calls + * 2. call_state: This denotes the state change that triggered this msg + * This will take one of the values from BtHfCallState + * 3. number & type: valid only for incoming & waiting call + */ + bt_status_t (*phone_state_change) (int num_active, int num_held, bthf_call_state_t call_setup_state, + const char *number, bthf_call_addrtype_t type); + + /** Closes the interface. */ + void (*cleanup)( void ); +} bthf_interface_t; + +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_HF_H */ diff --git a/include/hardware/bt_hh.h b/include/hardware/bt_hh.h new file mode 100644 index 0000000..09f547b --- /dev/null +++ b/include/hardware/bt_hh.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_HH_H +#define ANDROID_INCLUDE_BT_HH_H + +#include + +__BEGIN_DECLS + +#define BTHH_MAX_DSC_LEN 884 + +/* HH connection states */ +typedef enum +{ + BTHH_CONN_STATE_CONNECTED = 0, + BTHH_CONN_STATE_CONNECTING, + BTHH_CONN_STATE_DISCONNECTED, + BTHH_CONN_STATE_DISCONNECTING, + BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST, + BTHH_CONN_STATE_FAILED_KBD_FROM_HOST, + BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES, + BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER, + BTHH_CONN_STATE_FAILED_GENERIC, + BTHH_CONN_STATE_UNKNOWN +} bthh_connection_state_t; + +typedef enum +{ + BTHH_OK = 0, + BTHH_HS_HID_NOT_READY, /* handshake error : device not ready */ + BTHH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */ + BTHH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */ + BTHH_HS_INVALID_PARAM, /* handshake error : invalid paremter */ + BTHH_HS_ERROR, /* handshake error : unspecified HS error */ + BTHH_ERR, /* general BTA HH error */ + BTHH_ERR_SDP, /* SDP error */ + BTHH_ERR_PROTO, /* SET_Protocol error, + only used in BTA_HH_OPEN_EVT callback */ + BTHH_ERR_DB_FULL, /* device database full error, used */ + BTHH_ERR_TOD_UNSPT, /* type of device not supported */ + BTHH_ERR_NO_RES, /* out of system resources */ + BTHH_ERR_AUTH_FAILED, /* authentication fail */ + BTHH_ERR_HDL +}bthh_status_t; + +/* Protocol modes */ +typedef enum { + BTHH_REPORT_MODE = 0x00, + BTHH_BOOT_MODE = 0x01, + BTHH_UNSUPPORTED_MODE = 0xff +}bthh_protocol_mode_t; + +/* Report types */ +typedef enum { + BTHH_INPUT_REPORT = 1, + BTHH_OUTPUT_REPORT, + BTHH_FEATURE_REPORT +}bthh_report_type_t; + +typedef struct +{ + int attr_mask; + uint8_t sub_class; + uint8_t app_id; + int vendor_id; + int product_id; + int version; + uint8_t ctry_code; + int dl_len; + uint8_t dsc_list[BTHH_MAX_DSC_LEN]; +} bthh_hid_info_t; + +/** Callback for connection state change. + * state will have one of the values from bthh_connection_state_t + */ +typedef void (* bthh_connection_state_callback)(bt_bdaddr_t *bd_addr, bthh_connection_state_t state); + +/** Callback for vitual unplug api. + * the status of the vitual unplug + */ +typedef void (* bthh_virtual_unplug_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status); + +/** Callback for get hid info + * hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id, version, ctry_code, len + */ +typedef void (* bthh_hid_info_callback)(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info); + +/** Callback for get/set protocal api. + * the protocol mode is one of the value from bthh_protocol_mode_t + */ +typedef void (* bthh_protocol_mode_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode); + +/** Callback for get/set_idle_time api. + */ +typedef void (* bthh_idle_time_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, int idle_rate); + + +/** Callback for get report api. + * if staus is ok rpt_data contains the report data + */ +typedef void (* bthh_get_report_callback)(bt_bdaddr_t *bd_addr, bthh_status_t hh_status, uint8_t* rpt_data, int rpt_size); + + +/** BT-HH callback structure. */ +typedef struct { + /** set to sizeof(BtHfCallbacks) */ + size_t size; + bthh_connection_state_callback connection_state_cb; + bthh_hid_info_callback hid_info_cb; + bthh_protocol_mode_callback protocol_mode_cb; + bthh_idle_time_callback idle_time_cb; + bthh_get_report_callback get_report_cb; + bthh_virtual_unplug_callback virtual_unplug_cb; + +} bthh_callbacks_t; + + + +/** Represents the standard BT-HH interface. */ +typedef struct { + + /** set to sizeof(BtHhInterface) */ + size_t size; + + /** + * Register the BtHh callbacks + */ + bt_status_t (*init)( bthh_callbacks_t* callbacks ); + + /** connect to hid device */ + bt_status_t (*connect)( bt_bdaddr_t *bd_addr); + + /** dis-connect from hid device */ + bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr ); + + /** Virtual UnPlug (VUP) the specified HID device */ + bt_status_t (*virtual_unplug)(bt_bdaddr_t *bd_addr); + + /** Set the HID device descriptor for the specified HID device. */ + bt_status_t (*set_info)(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info ); + + /** Get the HID proto mode. */ + bt_status_t (*get_protocol) (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode); + + /** Set the HID proto mode. */ + bt_status_t (*set_protocol)(bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode); + + /** Send a GET_REPORT to HID device. */ + bt_status_t (*get_report)(bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, uint8_t reportId, int bufferSize); + + /** Send a SET_REPORT to HID device. */ + bt_status_t (*set_report)(bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, char* report); + + /** Send data to HID device. */ + bt_status_t (*send_data)(bt_bdaddr_t *bd_addr, char* data); + + /** Closes the interface. */ + void (*cleanup)( void ); + +} bthh_interface_t; +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_HH_H */ + + diff --git a/include/hardware/bt_hl.h b/include/hardware/bt_hl.h new file mode 100644 index 0000000..bd29e3a --- /dev/null +++ b/include/hardware/bt_hl.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_HL_H +#define ANDROID_INCLUDE_BT_HL_H + +__BEGIN_DECLS + +/* HL connection states */ + +typedef enum +{ + BTHL_MDEP_ROLE_SOURCE, + BTHL_MDEP_ROLE_SINK +} bthl_mdep_role_t; + +typedef enum { + BTHL_APP_REG_STATE_REG_SUCCESS, + BTHL_APP_REG_STATE_REG_FAILED, + BTHL_APP_REG_STATE_DEREG_SUCCESS, + BTHL_APP_REG_STATE_DEREG_FAILED +} bthl_app_reg_state_t; + +typedef enum +{ + BTHL_CHANNEL_TYPE_RELIABLE, + BTHL_CHANNEL_TYPE_STREAMING, + BTHL_CHANNEL_TYPE_ANY +} bthl_channel_type_t; + + +/* HL connection states */ +typedef enum { + BTHL_CONN_STATE_CONNECTING, + BTHL_CONN_STATE_CONNECTED, + BTHL_CONN_STATE_DISCONNECTING, + BTHL_CONN_STATE_DISCONNECTED, + BTHL_CONN_STATE_DESTROYED +} bthl_channel_state_t; + +typedef struct +{ + bthl_mdep_role_t mdep_role; + int data_type; + bthl_channel_type_t channel_type; + const char *mdep_description; /* MDEP description to be used in the SDP (optional); null terminated */ +} bthl_mdep_cfg_t; + +typedef struct +{ + const char *application_name; + const char *provider_name; /* provider name to be used in the SDP (optional); null terminated */ + const char *srv_name; /* service name to be used in the SDP (optional); null terminated*/ + const char *srv_desp; /* service description to be used in the SDP (optional); null terminated */ + int number_of_mdeps; + bthl_mdep_cfg_t *mdep_cfg; /* Dynamic array */ +} bthl_reg_param_t; + +/** Callback for application registration status. + * state will have one of the values from bthl_app_reg_state_t + */ +typedef void (* bthl_app_reg_state_callback)(int app_id, bthl_app_reg_state_t state); + +/** Callback for channel connection state change. + * state will have one of the values from + * bthl_connection_state_t and fd (file descriptor) + */ +typedef void (* bthl_channel_state_callback)(int app_id, bt_bdaddr_t *bd_addr, int mdep_cfg_index, int channel_id, bthl_channel_state_t state, int fd); + +/** BT-HL callback structure. */ +typedef struct { + /** set to sizeof(bthl_callbacks_t) */ + size_t size; + bthl_app_reg_state_callback app_reg_state_cb; + bthl_channel_state_callback channel_state_cb; +} bthl_callbacks_t; + + +/** Represents the standard BT-HL interface. */ +typedef struct { + + /** set to sizeof(bthl_interface_t) */ + size_t size; + + /** + * Register the Bthl callbacks + */ + bt_status_t (*init)( bthl_callbacks_t* callbacks ); + + /** Register HL application */ + bt_status_t (*register_application) ( bthl_reg_param_t *p_reg_param, int *app_id); + + /** Unregister HL application */ + bt_status_t (*unregister_application) (int app_id); + + /** connect channel */ + bt_status_t (*connect_channel)(int app_id, bt_bdaddr_t *bd_addr, int mdep_cfg_index, int *channel_id); + + /** destroy channel */ + bt_status_t (*destroy_channel)(int channel_id); + + /** Close the Bthl callback **/ + void (*cleanup)(void); + +} bthl_interface_t; +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_HL_H */ + + diff --git a/include/hardware/bt_pan.h b/include/hardware/bt_pan.h new file mode 100644 index 0000000..c8b36b4 --- /dev/null +++ b/include/hardware/bt_pan.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_PAN_H +#define ANDROID_INCLUDE_BT_PAN_H + +__BEGIN_DECLS + +#define BTPAN_ROLE_NONE 0 +#define BTPAN_ROLE_PANNAP 1 +#define BTPAN_ROLE_PANU 2 + +typedef enum { + BTPAN_STATE_CONNECTED = 0, + BTPAN_STATE_CONNECTING = 1, + BTPAN_STATE_DISCONNECTED = 2, + BTPAN_STATE_DISCONNECTING = 3 +} btpan_connection_state_t; + +typedef enum { + BTPAN_STATE_ENABLED = 0, + BTPAN_STATE_DISABLED = 1 +} btpan_control_state_t; + +/** +* Callback for pan connection state +*/ +typedef void (*btpan_connection_state_callback)(btpan_connection_state_t state, bt_status_t error, + const bt_bdaddr_t *bd_addr, int local_role, int remote_role); +typedef void (*btpan_control_state_callback)(btpan_control_state_t state, bt_status_t error, + int local_role, const char* ifname); + +typedef struct { + size_t size; + btpan_control_state_callback control_state_cb; + btpan_connection_state_callback connection_state_cb; +} btpan_callbacks_t; +typedef struct { + /** set to size of this struct*/ + size_t size; + /** + * Initialize the pan interface and register the btpan callbacks + */ + bt_status_t (*init)(const btpan_callbacks_t* callbacks); + /* + * enable the pan service by specified role. The result state of + * enabl will be returned by btpan_control_state_callback. when pan-nap is enabled, + * the state of connecting panu device will be notified by btpan_connection_state_callback + */ + bt_status_t (*enable)(int local_role); + /* + * get current pan local role + */ + int (*get_local_role)(void); + /** + * start bluetooth pan connection to the remote device by specified pan role. The result state will be + * returned by btpan_connection_state_callback + */ + bt_status_t (*connect)(const bt_bdaddr_t *bd_addr, int local_role, int remote_role); + /** + * stop bluetooth pan connection. The result state will be returned by btpan_connection_state_callback + */ + bt_status_t (*disconnect)(const bt_bdaddr_t *bd_addr); + + /** + * Cleanup the pan interface + */ + void (*cleanup)(void); + +} btpan_interface_t; + +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_PAN_H */ diff --git a/include/hardware/bt_sock.h b/include/hardware/bt_sock.h new file mode 100644 index 0000000..a4aa046 --- /dev/null +++ b/include/hardware/bt_sock.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_INCLUDE_BT_SOCK_H +#define ANDROID_INCLUDE_BT_SOCK_H + +__BEGIN_DECLS + +#define BTSOCK_FLAG_ENCRYPT 1 +#define BTSOCK_FLAG_AUTH (1 << 1) + +typedef enum { + BTSOCK_RFCOMM = 1, + BTSOCK_SCO = 2, + BTSOCK_L2CAP = 3 +} btsock_type_t; + +/** Represents the standard BT SOCKET interface. */ +typedef struct { + short size; + bt_bdaddr_t bd_addr; + int channel; + int status; +} __attribute__((packed)) sock_connect_signal_t; + +typedef struct { + + /** set to size of this struct*/ + size_t size; + /** + * listen to a rfcomm uuid or channel. It returns the socket fd from which + * btsock_connect_signal can be read out when a remote device connected + */ + bt_status_t (*listen)(btsock_type_t type, const char* service_name, const uint8_t* service_uuid, int channel, int* sock_fd, int flags); + /* + * connect to a rfcomm uuid channel of remote device, It returns the socket fd from which + * the btsock_connect_signal and a new socket fd to be accepted can be read out when connected + */ + bt_status_t (*connect)(const bt_bdaddr_t *bd_addr, btsock_type_t type, const uint8_t* uuid, int channel, int* sock_fd, int flags); + +} btsock_interface_t; + +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_SOCK_H */ -- cgit v1.1 From ada3a97820dd48d513350d1365a3040d570bab6e Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Wed, 19 Sep 2012 11:42:40 -0700 Subject: Camera2: Add JPEG transport header To simplify passing compressed JPEG data between the HAL and the camera service, add a transport header for use with JPEG streams. Bug: 7108816 Change-Id: I91060051f59032e66eaaab3ee9f651badd1f2ac0 --- include/hardware/camera2.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index e6b99b7..8587fc5 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -114,6 +114,26 @@ enum { }; /** + * Transport header for compressed JPEG buffers in output streams. + * + * To capture JPEG images, a stream is created using the pixel format + * HAL_PIXEL_FORMAT_BLOB, and the static metadata field android.jpeg.maxSize is + * used as the buffer size. Since compressed JPEG images are of variable size, + * the HAL needs to include the final size of the compressed image using this + * structure inside the output stream buffer. The JPEG blob ID field must be set + * to CAMERA2_JPEG_BLOB_ID. + */ +typedef struct camera2_jpeg_blob { + uint16_t jpeg_blob_id; + uint32_t jpeg_size; + uint8_t jpeg_data[0]; +}; + +enum { + CAMERA2_JPEG_BLOB_ID = 0x00FF +}; + +/** * Input reprocess stream queue management. A set of these methods is provided * to the HAL device in allocate_reprocess_stream(); they are used to interact * with the reprocess stream's input gralloc buffer queue. -- cgit v1.1 From d91697ab8fee9b4c55170230f355f5a25eceefaf Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Wed, 19 Sep 2012 22:53:30 -0700 Subject: Document reentrancy and error conditions The hotplug callback is non-reentrant. The display config functions return an error if called for a disconnected display type. Change-Id: I52d11a53f9b30a7c39e98b0a9b07eb97a3d2becd --- include/hardware/hwcomposer.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index 0bebb98..f03ac70 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -326,6 +326,9 @@ typedef struct hwc_procs { * other threads may be calling into the h/w composer while the callback * is in progress. * + * The h/w composer must serialize calls to the hotplug callback; only + * one thread may call it at a time. + * * This callback will be NULL if the h/w composer is using * HWC_DEVICE_API_VERSION_1_0. */ @@ -485,7 +488,8 @@ typedef struct hwc_composer_device_1 { * implementation should choose one and report it as the first config in * the list. Reporting the not-chosen configs is not required. * - * Returns 0 on success or -errno on error. + * Returns 0 on success or -errno on error. If disp is a hotpluggable + * display type and no display is connected, an error should be returned. * * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later. * It should be NULL for previous versions. @@ -506,8 +510,12 @@ typedef struct hwc_composer_device_1 { * * This field is REQUIRED for HWC_DEVICE_API_VERSION_1_1 and later. * It should be NULL for previous versions. + * + * If disp is a hotpluggable display type and no display is connected, + * or if config is not a valid configuration for the display, a negative + * value should be returned. */ - void (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp, + int (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp, uint32_t config, const uint32_t* attributes, int32_t* values); /* -- cgit v1.1 From cecacd4e71c35fd50dbe1e9855cbab0faa17b550 Mon Sep 17 00:00:00 2001 From: Alex Ray Date: Thu, 27 Sep 2012 15:48:23 -0700 Subject: Camera2: Change JPEG transport header The way buffers are passed to JPEG encoders makes it difficult to account for a header offset. This explains moving the header to the end, and clarifies the required header packing. Bug: 7108816 Change-Id: I569cd0cde37bd6fd7110fbc95d7fced9a55cff9c --- include/hardware/camera2.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/hardware/camera2.h b/include/hardware/camera2.h index 8587fc5..5d45325 100644 --- a/include/hardware/camera2.h +++ b/include/hardware/camera2.h @@ -122,11 +122,16 @@ enum { * the HAL needs to include the final size of the compressed image using this * structure inside the output stream buffer. The JPEG blob ID field must be set * to CAMERA2_JPEG_BLOB_ID. + * + * Transport header should be at the end of the JPEG output stream buffer. That + * means the jpeg_blob_id must start at byte[android.jpeg.maxSize - + * sizeof(camera2_jpeg_blob)]. Any HAL using this transport header must + * account for it in android.jpeg.maxSize. The JPEG data itself starts at + * byte[0] and should be jpeg_size bytes long. */ typedef struct camera2_jpeg_blob { uint16_t jpeg_blob_id; uint32_t jpeg_size; - uint8_t jpeg_data[0]; }; enum { -- cgit v1.1 From 442752aecdc54c32e77227e792fca64dcf1c1fb8 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Sun, 30 Sep 2012 11:06:22 -0700 Subject: NFC HAL: Use a separate callback for data. Bug: 7258325 Change-Id: I02d8ea1bdcb8ea6a9430e3dc286f5c2647277f72 --- include/hardware/nfc.h | 33 +++++++++++---------------------- modules/nfc-nci/nfc_nci_example.c | 2 +- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/include/hardware/nfc.h b/include/hardware/nfc.h index 31410fb..09523b3 100644 --- a/include/hardware/nfc.h +++ b/include/hardware/nfc.h @@ -71,11 +71,10 @@ enum { HAL_NFC_OPEN_CPLT_EVT = 0x00, HAL_NFC_CLOSE_CPLT_EVT = 0x01, HAL_NFC_POST_INIT_CPLT_EVT = 0x02, - HAL_NFC_NCI_RX_EVT = 0x03, - HAL_NFC_PRE_DISCOVER_CPLT_EVT = 0x04, - HAL_NFC_REQUEST_CONTROL_EVT = 0x05, - HAL_NFC_RELEASE_CONTROL_EVT = 0x06, - HAL_NFC_ERROR_EVT = 0x07 + HAL_NFC_PRE_DISCOVER_CPLT_EVT = 0x03, + HAL_NFC_REQUEST_CONTROL_EVT = 0x04, + HAL_NFC_RELEASE_CONTROL_EVT = 0x05, + HAL_NFC_ERROR_EVT = 0x06 }; /* @@ -92,27 +91,16 @@ enum { }; /* - * nfc_rx_data - * Struct used to pass received NCI packets up to the stack - */ -typedef struct nfc_rx_data { - uint16_t len; - uint8_t *p_data; -} nfc_rx_data_t; - -/* + * The callback passed in from the NFC stack that the HAL + * can use to pass events back to the stack. */ -typedef union -{ - nfc_status_t status; - nfc_rx_data_t nci_rx; -} nfc_event_data_t; +typedef void (nfc_stack_callback_t) (nfc_event_t event, nfc_status_t event_status); /* * The callback passed in from the NFC stack that the HAL - * can use to pass events back to the stack. + * can use to pass incomming data to the stack. */ -typedef void (nfc_stack_callback_t) (nfc_event_t event, nfc_event_data_t* p_data); +typedef void (nfc_stack_data_callback_t) (uint16_t data_len, uint8_t* p_data); /* nfc_nci_device_t starts with a hw_device_t struct, * followed by device-specific methods and members. @@ -135,7 +123,8 @@ typedef struct nfc_nci_device { * If open() returns any other value, the NCI stack will stop. * */ - int (*open)(const struct nfc_nci_device *p_dev, nfc_stack_callback_t *p_cback); + int (*open)(const struct nfc_nci_device *p_dev, nfc_stack_callback_t *p_cback, + nfc_stack_data_callback_t *p_data_cback); /* * (*write)() Performs an NCI write. diff --git a/modules/nfc-nci/nfc_nci_example.c b/modules/nfc-nci/nfc_nci_example.c index 01914f0..2514225 100644 --- a/modules/nfc-nci/nfc_nci_example.c +++ b/modules/nfc-nci/nfc_nci_example.c @@ -25,7 +25,7 @@ * NCI HAL method implementations. These must be overriden */ static int hal_open(const struct nfc_nci_device *dev, - nfc_stack_callback_t *p_cback) { + nfc_stack_callback_t *p_cback, nfc_stack_data_callback_t *p_data_cback) { ALOGE("NFC-NCI HAL: %s", __FUNCTION__); return 0; } -- cgit v1.1 From d44130339c7317faaa5cbab767eccc37347ffd25 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Sun, 30 Sep 2012 11:08:06 -0700 Subject: bug 7253033 Add "exiting" state to remote audio submix module Support receiving a parameter that sets the remote audio submix module in a state where the audio pipe will unblock any current write operation and not block anymore. Change-Id: Ia3119cd79972afff0de24187dae627855a468ebf --- modules/audio_remote_submix/Android.mk | 1 + modules/audio_remote_submix/audio_hw.cpp | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/audio_remote_submix/Android.mk b/modules/audio_remote_submix/Android.mk index 735215e..5f54902 100644 --- a/modules/audio_remote_submix/Android.mk +++ b/modules/audio_remote_submix/Android.mk @@ -24,6 +24,7 @@ LOCAL_C_INCLUDES += \ frameworks/av/include/ \ frameworks/native/include/ LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libnbaio +LOCAL_STATIC_LIBRARIES := libmedia_helper LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index 0f8adab..b24608f 100755 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -31,12 +31,13 @@ #include #include -//#include -//#include #include #include #include +#include +#include + extern "C" { namespace android { @@ -175,6 +176,32 @@ static int out_dump(const struct audio_stream *stream, int fd) static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { + int exiting = -1; + AudioParameter parms = AudioParameter(String8(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)) { + const struct submix_stream_out *out = + reinterpret_cast(stream); + + pthread_mutex_lock(&out->dev->lock); + + MonoPipe* sink = out->dev->rsxSink.get(); + if (sink != NULL) { + sink->incStrong(out); + } else { + pthread_mutex_unlock(&out->dev->lock); + return 0; + } + + ALOGI("shutdown"); + sink->shutdown(true); + + sink->decStrong(out); + + pthread_mutex_unlock(&out->dev->lock); + } + return 0; } -- cgit v1.1 From c7545189c8b260bbaf09653407450418a3d1860b Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Mon, 8 Oct 2012 19:23:56 -0700 Subject: hwcomposer: Specify set() call error behavior. Bug: 7308829 Change-Id: Ibab6f0d2929860f02c17d6ffadb326fc0c333c4d --- include/hardware/hwcomposer.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/hardware/hwcomposer.h b/include/hardware/hwcomposer.h index f03ac70..0722e32 100644 --- a/include/hardware/hwcomposer.h +++ b/include/hardware/hwcomposer.h @@ -407,13 +407,20 @@ typedef struct hwc_composer_device_1 { * non-NULL. In HWC 1.2, support for one virtual display is required, and * no more than one will be used. Future HWC versions might require more. * - * IMPORTANT NOTE: there is an implicit layer containing opaque black + * IMPORTANT NOTE: There is an implicit layer containing opaque black * pixels behind all the layers in the list. It is the responsibility of * the hwcomposer module to make sure black pixels are output (or blended * from). * - * returns: 0 on success. An negative error code on error: - * HWC_EGL_ERROR: eglGetError() will provide the proper error code + * IMPORTANT NOTE: In the event of an error this call *MUST* still cause + * any fences returned in the previous call to set to eventually become + * signaled. The caller may have already issued wait commands on these + * fences, and having set return without causing those fences to signal + * will likely result in a deadlock. + * + * returns: 0 on success. A negative error code on error: + * HWC_EGL_ERROR: eglGetError() will provide the proper error code (only + * allowed prior to HWComposer 1.1) * Another code for non EGL errors. */ int (*set)(struct hwc_composer_device_1 *dev, -- cgit v1.1 From 20c7f50cd5d60ee7d76f2f502866187992e7675b Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 10 Oct 2012 12:23:17 -0700 Subject: Support querying active record sources Add support for querying whether there is currently a recording underway from the specified audio source. Bug 7314859 Change-Id: I270f27eff4dcf1cc179089859a4c690140825ad1 --- include/hardware/audio_policy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/hardware/audio_policy.h b/include/hardware/audio_policy.h index 6dd5fd7..9e145f8 100644 --- a/include/hardware/audio_policy.h +++ b/include/hardware/audio_policy.h @@ -232,6 +232,9 @@ struct audio_policy { audio_stream_type_t stream, uint32_t in_past_ms); + bool (*is_source_active)(const struct audio_policy *pol, + audio_source_t source); + /* dump state */ int (*dump)(const struct audio_policy *pol, int fd); }; -- cgit v1.1 From 90b0fbd13f97127e29ea565c09b64cc25ab6e9c9 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 30 Oct 2012 19:03:22 -0700 Subject: Shutdown audio pipe when closing input stream Writing to the audio pipe for the remote submix is blocking, unless the audio output pipe is in shutdown mode. The playback thread could stay blocked on the write if the input stream has already been closed. The change consists in shutting down the pipe also when the input stream gets closed. When the pipe is in this state, simulate timing in the write operation so we don't drain the output faster than realtime. Bug 7424646 Change-Id: I5feb3be642b0ee7eef10dee0141308684ee9c811 --- modules/audio_remote_submix/audio_hw.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index b24608f..3756274 100755 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -233,12 +233,22 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, ssize_t written_frames = 0; struct submix_stream_out *out = reinterpret_cast(stream); + const size_t frame_size = audio_stream_frame_size(&stream->common); + const size_t frames = bytes / frame_size; + pthread_mutex_lock(&out->dev->lock); out->dev->output_standby = false; MonoPipe* sink = out->dev->rsxSink.get(); if (sink != NULL) { + if (sink->isShutdown()) { + pthread_mutex_unlock(&out->dev->lock); + // the pipe has already been shutdown, this buffer will be lost but we must + // simulate timing so we don't drain the output faster than realtime + usleep(frames * 1000000 / out_get_sample_rate(&stream->common)); + return bytes; + } sink->incStrong(buffer); } else { pthread_mutex_unlock(&out->dev->lock); @@ -249,8 +259,6 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_unlock(&out->dev->lock); - const size_t frame_size = audio_stream_frame_size(&stream->common); - const size_t frames = bytes / frame_size; written_frames = sink->write(buffer, frames); if (written_frames < 0) { if (written_frames == (ssize_t)NEGOTIATE) { @@ -741,6 +749,12 @@ static void adev_close_input_stream(struct audio_hw_device *dev, pthread_mutex_lock(&rsxadev->lock); + MonoPipe* sink = rsxadev->rsxSink.get(); + if (sink != NULL) { + ALOGI("shutdown"); + sink->shutdown(true); + } + free(stream); pthread_mutex_unlock(&rsxadev->lock); -- cgit v1.1