summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Friedrich <efriedrich@de.adit-jv.com>2023-04-28 09:15:24 +0200
committerEugen Friedrich <efriedrich@de.adit-jv.com>2023-04-28 09:15:24 +0200
commit6405590f6a8786b986e1cf153e369bc3791f067a (patch)
treebe399ddd26f01fe938e723c1fe4a891f49178fd5
parente8cef46a8339e3f930a5bd436a3807ffa8889d4f (diff)
parentd65adaebc70cd36da3878c44980fcd99d24c9b6c (diff)
downloadwayland-ivi-extension-6405590f6a8786b986e1cf153e369bc3791f067a.tar.gz
Merge remote-tracking branch 'upstream/pull/149'
* upstream/pull/149 tests: create tests for new screenshot functions with callbacks ilmControl: Extend screenshot API with callback support Reviewed-by: Eugen Friedrich <efriedrich@de.adit-jv.com> Reviewed-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com> Tested-by: Doan Ngoc Au <au.doanngoc@vn.bosch.com>
-rw-r--r--ivi-layermanagement-api/ilmCommon/include/ilm_types.h29
-rw-r--r--ivi-layermanagement-api/ilmControl/include/ilm_control.h35
-rw-r--r--ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c145
-rw-r--r--ivi-layermanagement-api/test/ilm_control_notification_test.cpp60
4 files changed, 240 insertions, 29 deletions
diff --git a/ivi-layermanagement-api/ilmCommon/include/ilm_types.h b/ivi-layermanagement-api/ilmCommon/include/ilm_types.h
index 98a8e62..64e30a7 100644
--- a/ivi-layermanagement-api/ilmCommon/include/ilm_types.h
+++ b/ivi-layermanagement-api/ilmCommon/include/ilm_types.h
@@ -287,4 +287,33 @@ typedef void(*notificationFunc)(ilmObjectType object,
typedef void(*shutdownNotificationFunc)(t_ilm_shutdown_error_type error_type,
int errornum,
void* user_data);
+
+/**
+ * Typedef for notification callback on screenshot send done event
+ * @param user_data the use data, be passed when call the screenshot api
+ * @param fd fd for file containing image data, don't close it in callback,
+ * it will be closed and shouldn't be accessed any longer after the callback execution.
+ * @param width image width in pixels
+ * @param height image height in pixels
+ * @param stride number of bytes per pixel row
+ * @param format image format of type wl_shm.format
+ * @param timestamp timestamp in milliseconds
+ */
+typedef ilmErrorTypes(*screenshotDoneNotificationFunc)(void *user_data,
+ t_ilm_int fd,
+ t_ilm_uint width,
+ t_ilm_uint height,
+ t_ilm_uint stride,
+ t_ilm_uint format,
+ t_ilm_uint timestamp);
+
+/**
+ * Typedef for notification callback on screenshot send error event
+ * @param user_data the use data, be passed when call the screenshot api
+ * @param error error code
+ * @param message error description
+ */
+typedef void(*screenshotErrorNotificationFunc)(void *user_data,
+ t_ilm_uint error,
+ const char *message);
#endif /* _ILM_TYPES_H_*/
diff --git a/ivi-layermanagement-api/ilmControl/include/ilm_control.h b/ivi-layermanagement-api/ilmControl/include/ilm_control.h
index 71e4968..c67152a 100644
--- a/ivi-layermanagement-api/ilmControl/include/ilm_control.h
+++ b/ivi-layermanagement-api/ilmControl/include/ilm_control.h
@@ -366,6 +366,23 @@ ilmErrorTypes ilm_displaySetRenderOrder(t_ilm_display display, t_ilm_layer *pLay
ilmErrorTypes ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename);
/**
+ * \brief Take a screenshot from the current displayed layer scene with non-blocking.
+ * The function allows to setup callbacks when capturing the display,
+ * It helps to avoid a blocking, user can handle screenshot data or error in
+ * the callbacks.
+ * \param[in] screen Id of screen where screenshot should be taken
+ * \param[in] callback_done callback called when screenshot is acquired
+ * \param[in] callback_error callback called when screenshot acqusition failed
+ * \param[in] user_data callback user data passed in by called
+ * \return ILM_SUCCESS if the method call was successful
+ * \return ILM_FAILED if the client can not call the method on the service.
+ */
+ilmErrorTypes ilm_takeAsyncScreenshot(t_ilm_uint screen,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data);
+
+/**
* \brief Take a screenshot of a certain surface
* The screenshot is saved as bmp file with the corresponding filename.
* \ingroup ilmControl
@@ -377,6 +394,24 @@ ilmErrorTypes ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename)
ilmErrorTypes ilm_takeSurfaceScreenshot(t_ilm_const_string filename, t_ilm_surface surfaceid);
/**
+ * \brief Take a screenshot of a certain surface with non-blocking.
+ * The function allows to setup callbacks when capturing a surface,
+ * It helps to avoid a blocking, user can handle screenshot data or error in
+ * the callbacks.
+ * \ingroup ilmControl
+ * \param[in] surfaceid Identifier of the surface to take the screenshot of
+ * \param[in] callback_done callback called when screenshot is acquired
+ * \param[in] callback_error callback called when screenshot acqusition failed
+ * \param[in] user_data callback user data passed in by called
+ * \return ILM_SUCCESS if the method call was successful
+ * \return ILM_FAILED if the client can not call the method on the service.
+ */
+ilmErrorTypes ilm_takeAsyncSurfaceScreenshot(t_ilm_surface surfaceid,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data);
+
+/**
* \brief register for notification on property changes of layer
* \ingroup ilmControl
* \param[in] layer id of layer to register for notification
diff --git a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c
index b4fdfbf..97e4e6d 100644
--- a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c
+++ b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c
@@ -70,6 +70,9 @@ struct screen_context {
struct screenshot_context {
const char *filename;
ilmErrorTypes result;
+ screenshotDoneNotificationFunc callback_done;
+ screenshotErrorNotificationFunc callback_error;
+ void *callback_priv;
};
static inline void lock_context(struct ilm_control_context *ctx)
@@ -2126,9 +2129,17 @@ static void screenshot_done(void *data, struct ivi_screenshot *ivi_screenshot,
ctx_scrshot->filename = NULL;
ivi_screenshot_destroy(ivi_screenshot);
- if (filename == NULL) {
- ctx_scrshot->result = ILM_FAILED;
- fprintf(stderr, "screenshot file name not provided: %m\n");
+ if (ctx_scrshot->callback_done)
+ if (ctx_scrshot->callback_done(ctx_scrshot->callback_priv,
+ fd, width, height, stride, format, timestamp) == ILM_FAILED) {
+ ctx_scrshot->result = ILM_FAILED;
+ close(fd);
+ return;
+ }
+ // if filename is null, free resource and return
+ if (!filename) {
+ close(fd);
+ free(ctx_scrshot);
return;
}
@@ -2170,9 +2181,15 @@ static void screenshot_error(void *data, struct ivi_screenshot *ivi_screenshot,
uint32_t error, const char *message)
{
struct screenshot_context *ctx_scrshot = data;
+ const char *filename = ctx_scrshot->filename;
ctx_scrshot->filename = NULL;
ivi_screenshot_destroy(ivi_screenshot);
+ if (ctx_scrshot->callback_error)
+ ctx_scrshot->callback_error(ctx_scrshot->callback_priv, error, message);
fprintf(stderr, "screenshot failed, error 0x%x: %s\n", error, message);
+ // free resource
+ if (!filename)
+ free(ctx_scrshot);
}
static struct ivi_screenshot_listener screenshot_listener = {
@@ -2180,76 +2197,146 @@ static struct ivi_screenshot_listener screenshot_listener = {
screenshot_error,
};
-ILM_EXPORT ilmErrorTypes
-ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename)
+static ilmErrorTypes
+ilm_takeShoot(t_ilm_uint screen, t_ilm_const_string filename,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data)
{
ilmErrorTypes returnValue = ILM_FAILED;
struct ilm_control_context *const ctx = &ilm_context;
struct screen_context *ctx_scrn = NULL;
+ // if filename, callback_done and callback_error are null, don't do anything, then return success
+ if (!filename && !callback_done && !callback_error) {
+ return ILM_SUCCESS;
+ }
+
lock_context(ctx);
ctx_scrn = get_screen_context_by_id(&ctx->wl, (uint32_t)screen);
if (ctx_scrn != NULL) {
- struct screenshot_context ctx_scrshot = {
- .filename = filename,
- .result = ILM_FAILED,
- };
+ struct screenshot_context *ctx_scrshot = calloc(1, sizeof(struct screenshot_context));
- struct ivi_screenshot *scrshot =
- ivi_wm_screen_screenshot(ctx_scrn->controller);
+ if (!ctx_scrshot) {
+ fprintf(stderr, "Failed to allocate memory for screenshot_context\n");
+ goto exit;
+ }
+ ctx_scrshot->filename = filename;
+ ctx_scrshot->result = ILM_FAILED;
+ ctx_scrshot->callback_done = callback_done;
+ ctx_scrshot->callback_error = callback_error;
+ ctx_scrshot->callback_priv = user_data;
+
+ struct ivi_screenshot *scrshot = ivi_wm_screen_screenshot(ctx_scrn->controller);
if (scrshot) {
- ivi_screenshot_add_listener(scrshot, &screenshot_listener,
- &ctx_scrshot);
+ ivi_screenshot_add_listener(scrshot, &screenshot_listener, ctx_scrshot);
+ // don't need to wait if file name is empty
+ if (!filename) {
+ wl_display_flush(ctx->wl.display);
+ returnValue = ILM_SUCCESS;
+ goto exit;
+ }
// dispatch until filename has been reset in done or error callback
int ret;
do {
ret =
wl_display_dispatch_queue(ctx->wl.display, ctx->wl.queue);
- } while ((ret != -1) && ctx_scrshot.filename);
+ } while ((ret != -1) && ctx_scrshot->filename);
- returnValue = ctx_scrshot.result;
+ returnValue = ctx_scrshot->result;
}
+ free(ctx_scrshot);
}
+exit:
unlock_context(ctx);
-
return returnValue;
}
ILM_EXPORT ilmErrorTypes
-ilm_takeSurfaceScreenshot(t_ilm_const_string filename,
- t_ilm_surface surfaceid)
+ilm_takeAsyncScreenshot(t_ilm_uint screen,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data)
+{
+ return ilm_takeShoot(screen, NULL, callback_done, callback_error, user_data);
+}
+
+ILM_EXPORT ilmErrorTypes
+ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename)
+{
+ return ilm_takeShoot(screen, filename, NULL, NULL, NULL);
+}
+
+static ilmErrorTypes
+ilm_takeSurfaceShoot(t_ilm_surface surfaceid, t_ilm_const_string filename,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data)
{
ilmErrorTypes returnValue = ILM_FAILED;
struct ilm_control_context *const ctx = &ilm_context;
+ // if filename, callback_done and callback_error are null, don't do anything, then return success
+ if (!filename && !callback_done && !callback_error) {
+ return ILM_SUCCESS;
+ }
+
lock_context(ctx);
if (ctx->wl.controller) {
- struct screenshot_context ctx_scrshot = {
- .filename = filename,
- .result = ILM_FAILED,
- };
+ struct screenshot_context *ctx_scrshot = calloc(1, sizeof(struct screenshot_context));
- struct ivi_screenshot *scrshot =
- ivi_wm_surface_screenshot(ctx->wl.controller, surfaceid);
+ if (!ctx_scrshot) {
+ fprintf(stderr, "Failed to allocate memory for screenshot_context\n");
+ goto exit;
+ }
+ ctx_scrshot->filename = filename;
+ ctx_scrshot->result = ILM_FAILED;
+ ctx_scrshot->callback_done = callback_done;
+ ctx_scrshot->callback_error = callback_error;
+ ctx_scrshot->callback_priv = user_data;
+
+ struct ivi_screenshot *scrshot = ivi_wm_surface_screenshot(ctx->wl.controller, surfaceid);
if (scrshot) {
- ivi_screenshot_add_listener(scrshot, &screenshot_listener,
- &ctx_scrshot);
+ ivi_screenshot_add_listener(scrshot, &screenshot_listener, ctx_scrshot);
+ // don't need to wait if file name is empty
+ if (!filename) {
+ wl_display_flush(ctx->wl.display);
+ returnValue = ILM_SUCCESS;
+ goto exit;
+ }
// dispatch until filename has been reset in done or error callback
int ret;
do {
ret =
wl_display_dispatch_queue(ctx->wl.display, ctx->wl.queue);
- } while ((ret != -1) && ctx_scrshot.filename);
+ } while ((ret != -1) && ctx_scrshot->filename);
- returnValue = ctx_scrshot.result;
+ returnValue = ctx_scrshot->result;
}
+ free(ctx_scrshot);
}
+exit:
unlock_context(ctx);
-
return returnValue;
}
ILM_EXPORT ilmErrorTypes
+ilm_takeAsyncSurfaceScreenshot(t_ilm_surface surfaceid,
+ screenshotDoneNotificationFunc callback_done,
+ screenshotErrorNotificationFunc callback_error,
+ void *user_data)
+{
+ return ilm_takeSurfaceShoot(surfaceid, NULL, callback_done, callback_error, user_data);
+}
+
+ILM_EXPORT ilmErrorTypes
+ilm_takeSurfaceScreenshot(t_ilm_const_string filename,
+ t_ilm_surface surfaceid)
+{
+ return ilm_takeSurfaceShoot(surfaceid, filename, NULL, NULL, NULL);
+}
+
+ILM_EXPORT ilmErrorTypes
ilm_layerAddNotification(t_ilm_layer layer,
layerNotificationFunc callback)
{
diff --git a/ivi-layermanagement-api/test/ilm_control_notification_test.cpp b/ivi-layermanagement-api/test/ilm_control_notification_test.cpp
index 2638a03..b918e42 100644
--- a/ivi-layermanagement-api/test/ilm_control_notification_test.cpp
+++ b/ivi-layermanagement-api/test/ilm_control_notification_test.cpp
@@ -33,6 +33,12 @@ extern "C" {
#include "ilm_control.h"
}
+struct screenshot_data_t {
+ std::atomic<int32_t> fd;
+ std::atomic<uint32_t> error;
+ ilmErrorTypes result = ILM_SUCCESS;
+};
+
void add_nsecs(struct timespec *tv, long nsec)
{
assert(nsec < 1000000000);
@@ -230,6 +236,25 @@ public:
pthread_cond_signal( &waiterVariable );
}
+
+ static ilmErrorTypes ScreenshotDoneCallbackFunc(void *user_data, t_ilm_int fd, t_ilm_uint width, t_ilm_uint height, t_ilm_uint stride, t_ilm_uint format, t_ilm_uint timestamp)
+ {
+ PthreadMutexLock lock(notificationMutex);
+ screenshot_data_t *screenshotData = static_cast<screenshot_data_t*>(user_data);
+ screenshotData->fd.store(fd);
+ timesCalled++;
+ pthread_cond_signal( &waiterVariable );
+ return screenshotData->result;
+ }
+
+ static void ScreenshotErrorCallbackFunc(void *user_data, t_ilm_uint error, const char *message)
+ {
+ PthreadMutexLock lock(notificationMutex);
+ screenshot_data_t *screenshotData = static_cast<screenshot_data_t*>(user_data);
+ screenshotData->error.store(error);
+ timesCalled++;
+ pthread_cond_signal( &waiterVariable );
+ }
};
// Pointers where to put received values for current Test
@@ -726,3 +751,38 @@ TEST_F(NotificationTest, DefaultIsNotToReceiveNotificationsSurface)
// assert that we have not been notified
assertNoCallbackIsCalled();
}
+
+TEST_F(NotificationTest, getNotificationWhenScreenshotDone)
+{
+ /* Call ilm_takeAsyncScreenshot with right screen id
+ * The ilm_takeAsyncScreenshot should return ILM_SUCCESS
+ * Screenshot done callback should trigged
+ */
+ screenshot_data_t screenshotData;
+ screenshotData.fd.store(-1);
+ ASSERT_EQ(ILM_SUCCESS, ilm_takeAsyncScreenshot(0, ScreenshotDoneCallbackFunc, ScreenshotErrorCallbackFunc, &screenshotData));
+ assertCallbackcalled();
+ ASSERT_NE(screenshotData.fd.load(), -1);
+
+ /* Call ilm_takeAsyncSurfaceScreenshot with right surface id
+ * The ilm_takeAsyncSurfaceScreenshot should return ILM_SUCCESS
+ * Screenshot done callback should trigged
+ */
+ screenshotData.fd.store(-1);
+ ASSERT_EQ(ILM_SUCCESS, ilm_takeAsyncSurfaceScreenshot(surface, ScreenshotDoneCallbackFunc, ScreenshotErrorCallbackFunc, &screenshotData));
+ assertCallbackcalled();
+ ASSERT_NE(screenshotData.fd.load(), -1);
+}
+
+TEST_F(NotificationTest, getNotificationWhenScreenshotError)
+{
+ /* Call ilm_takeAsyncSurfaceScreenshot with wrong surface id
+ * The ilm_takeAsyncSurfaceScreenshot should return ILM_SUCCESS
+ * Screenshot error callback should trigged
+ */
+ screenshot_data_t screenshotData;
+ screenshotData.error.store(0);
+ ASSERT_EQ(ILM_SUCCESS, ilm_takeAsyncSurfaceScreenshot(surface + 1, ScreenshotDoneCallbackFunc, ScreenshotErrorCallbackFunc, &screenshotData));
+ assertCallbackcalled();
+ ASSERT_EQ(screenshotData.error.load(), 3); //IVI_SCREENSHOT_ERROR_NO_SURFACE is 3
+}