Mir

Merge lp:~albaguirre/mir/add-mirscreencast-spec into lp:mir

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alberto Aguirre
Approved revision: no longer in the source branch.
Merged at revision: 3424
Proposed branch: lp:~albaguirre/mir/add-mirscreencast-spec
Merge into: lp:mir
Diff against target: 999 lines (+454/-189)
11 files modified
include/client/mir_toolkit/client_types.h (+1/-0)
include/client/mir_toolkit/mir_screencast.h (+90/-5)
include/common/mir/optional_value.h (+1/-1)
src/client/mir_screencast.cpp (+126/-48)
src/client/mir_screencast.h (+27/-11)
src/client/mir_screencast_api.cpp (+69/-44)
src/client/symbols.map (+9/-0)
tests/acceptance-tests/test_client_screencast.cpp (+10/-12)
tests/acceptance-tests/throwback/test_client_library_errors.cpp (+7/-0)
tests/integration-tests/test_client_screencast.cpp (+59/-3)
tests/unit-tests/client/test_mir_screencast.cpp (+55/-65)
To merge this branch: bzr merge lp:~albaguirre/mir/add-mirscreencast-spec
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Kevin DuBois (community) Approve
Review via email: mp+290158@code.launchpad.net

Commit message

Introduce MirScreencastSpec

MirScreencastParameters is not opaque and modifying it to to add more screencast creation options would break client ABI.
Instead use a MirScreencastSpec similar to MirSurfaceSpec to specify existing and future options.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3424
https://mir-jenkins.ubuntu.com/job/mir-ci/659/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/603
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/640
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/632
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/632
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/613
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/613/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/613
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/613/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/613
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/613/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/613
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/613/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/613
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/613/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/659/rebuild

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

+MirScreencast* create_screencast(MirScreencastSpec* spec)
more of a future improvement (as this seems built on what's in place), but we can get rid of the pointer release if the resource is managed via the connection with a function like:
connection->create_screencast(...)
(in the same sort of manner as streams/chains/surfaces, and this makes for better cleanup during certain destruction scenarios)

nits:
+ if (valid() && server)
do we have to check server? (initialized from a ref, if its invalid at call site, we'd still have a non-null (and deleted) ptr and still have a problem)

987/991 extra lines

review: Approve
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

>more of a future improvement (as this seems built on what's in place), but we can get rid of the >pointer release if the resource is managed via the connection with a function like:
>connection->create_screencast(...)

Yeah I plan to move the construction/destruction to connection like the others - but I wanted to keep this MP/diff small and mainly about the introduction of the MirScreencast spec.

>do we have to check server?

server is a pointer can be null in case an invalid MirScreencast object is created (like in like 535).

>987/991 extra lines

Fixed.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3425
https://mir-jenkins.ubuntu.com/job/mir-ci/672/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/620
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/657
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/649
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/649
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/630
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/630/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/630
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/630/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/630
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/630/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/630
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/630/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/630
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/630/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/672/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir_toolkit/client_types.h'
2--- include/client/mir_toolkit/client_types.h 2016-03-23 06:39:56 +0000
3+++ include/client/mir_toolkit/client_types.h 2016-03-28 14:29:53 +0000
4@@ -41,6 +41,7 @@
5 typedef struct MirSurface MirSurface;
6 typedef struct MirSurfaceSpec MirSurfaceSpec;
7 typedef struct MirScreencast MirScreencast;
8+typedef struct MirScreencastSpec MirScreencastSpec;
9 typedef struct MirPromptSession MirPromptSession;
10 typedef struct MirBufferStream MirBufferStream;
11 typedef struct MirPersistentId MirPersistentId;
12
13=== modified file 'include/client/mir_toolkit/mir_screencast.h'
14--- include/client/mir_toolkit/mir_screencast.h 2015-06-17 05:20:42 +0000
15+++ include/client/mir_toolkit/mir_screencast.h 2016-03-28 14:29:53 +0000
16@@ -28,6 +28,91 @@
17 #endif
18
19 /**
20+ * Create a screencast specification.
21+ *
22+ * \remark For use with mir_screencast_create() at the width, height,
23+ * pixel format and capture region must be set.
24+ *
25+ * \param [in] connection a valid mir connection
26+ * \return A handle that can ultimately be passed to
27+ * mir_surface_create() or mir_surface_apply_spec()
28+ */
29+MirScreencastSpec* mir_create_screencast_spec(MirConnection* connection);
30+
31+/**
32+ * Set the requested width, in pixels
33+ *
34+ * \param [in] spec Specification to mutate
35+ * \param [in] width Requested width.
36+ *
37+ */
38+void mir_screencast_spec_set_width(MirScreencastSpec* spec, unsigned width);
39+
40+/**
41+ * Set the requested height, in pixels
42+ *
43+ * \param [in] spec Specification to mutate
44+ * \param [in] height Requested height.
45+ *
46+ */
47+void mir_screencast_spec_set_height(MirScreencastSpec* spec, unsigned height);
48+
49+/**
50+ * Set the requested pixel format.
51+ *
52+ * \param [in] spec Specification to mutate
53+ * \param [in] format Requested pixel format
54+ *
55+ */
56+void mir_screencast_spec_set_pixel_format(MirScreencastSpec* spec, MirPixelFormat format);
57+
58+
59+/**
60+ * Set the rectangular region to capture.
61+ *
62+ * \param [in] spec Specification to mutate
63+ * \param [in] region The rectangular region of the screen to capture
64+ * specified in virtual screen space coordinates
65+ *
66+ */
67+void mir_screencast_spec_set_capture_region(MirScreencastSpec* spec, MirRectangle const* region);
68+
69+/**
70+ * Release the resources held by a MirScreencastSpec.
71+ *
72+ * \param [in] spec Specification to release
73+ */
74+void mir_screencast_spec_release(MirScreencastSpec* spec);
75+
76+/**
77+ * Create a screencast from a given specification
78+ *
79+ * \param [in] spec Specification of the screencast attributes
80+ * \return The resulting screencast
81+ */
82+MirScreencast* mir_screencast_create_sync(MirScreencastSpec* spec);
83+
84+/**
85+ * Test for a valid screencast
86+ *
87+ * \param [in] screencast The screencast to verify
88+ * \return True if the supplied screencast is valid, false otherwise.
89+ */
90+bool mir_screencast_is_valid(MirScreencast *screencast);
91+
92+/**
93+ * Retrieve a text description of the error. The returned string is owned by
94+ * the library and remains valid until the screencast or the associated
95+ * connection has been released.
96+ *
97+ * \param [in] screencast The screencast
98+ * \return A text description of any error resulting in an
99+ * invalid screencast, or the empty string "" if the
100+ * screencast is valid.
101+ */
102+char const *mir_screencast_get_error_message(MirScreencast *screencast);
103+
104+/**
105 * Create a screencast on the supplied connection.
106 *
107 * A screencast allows clients to read the contents of the screen.
108@@ -37,16 +122,16 @@
109 * \param [in] parameters The screencast parameters
110 * \return The resulting screencast
111 */
112-MirScreencast *mir_connection_create_screencast_sync(
113- MirConnection *connection,
114- MirScreencastParameters *parameters);
115+MirScreencast* mir_connection_create_screencast_sync(
116+ MirConnection* connection,
117+ MirScreencastParameters* parameters);
118
119 /**
120 * Release the specified screencast.
121 * \param [in] screencast The screencast to be released
122 */
123 void mir_screencast_release_sync(
124- MirScreencast *screencast);
125+ MirScreencast* screencast);
126
127 /**
128 * Retrieve the MirBufferStream associated with a screencast
129@@ -54,7 +139,7 @@
130 *
131 * \param[in] screencast The screencast
132 */
133-MirBufferStream* mir_screencast_get_buffer_stream(MirScreencast *screencast);
134+MirBufferStream* mir_screencast_get_buffer_stream(MirScreencast* screencast);
135
136 #ifdef __cplusplus
137 }
138
139=== modified file 'include/common/mir/optional_value.h'
140--- include/common/mir/optional_value.h 2016-01-29 08:18:22 +0000
141+++ include/common/mir/optional_value.h 2016-03-28 14:29:53 +0000
142@@ -29,7 +29,7 @@
143 {
144 public:
145 optional_value() = default;
146- optional_value(T const& value) : value_{value}, is_set_{true} {}
147+ optional_value(T const& value) : value_(value), is_set_{true} {}
148
149 optional_value& operator=(T const& value)
150 {
151
152=== modified file 'src/client/mir_screencast.cpp'
153--- src/client/mir_screencast.cpp 2016-03-23 06:39:56 +0000
154+++ src/client/mir_screencast.cpp 2016-03-28 14:29:53 +0000
155@@ -30,42 +30,99 @@
156 namespace mp = mir::protobuf;
157 namespace geom = mir::geometry;
158
159+namespace
160+{
161+mir::protobuf::ScreencastParameters serialize_spec(MirScreencastSpec const& spec)
162+{
163+ mp::ScreencastParameters message;
164+
165+#define SERIALIZE_OPTION_IF_SET(option) \
166+ if (spec.option.is_set()) \
167+ message.set_##option(spec.option.value());
168+
169+ SERIALIZE_OPTION_IF_SET(width);
170+ SERIALIZE_OPTION_IF_SET(height);
171+ SERIALIZE_OPTION_IF_SET(pixel_format);
172+
173+ if (spec.capture_region.is_set())
174+ {
175+ auto const region = spec.capture_region.value();
176+ message.mutable_region()->set_left(region.left);
177+ message.mutable_region()->set_top(region.top);
178+ message.mutable_region()->set_width(region.width);
179+ message.mutable_region()->set_height(region.height);
180+ }
181+
182+ return message;
183+}
184+
185+//TODO: it should be up to the server to decide if the parameters are acceptable
186+void throw_if_invalid(MirScreencastSpec const& spec)
187+{
188+#define THROW_IF_UNSET(option) \
189+ if (!spec.option.is_set()) \
190+ BOOST_THROW_EXCEPTION(std::runtime_error("Unset "#option));
191+
192+#define THROW_IF_EQ(option, val) \
193+ THROW_IF_UNSET(option); \
194+ if (spec.option.is_set() && spec.option.value() == val) \
195+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid "#option));
196+
197+#define THROW_IF_ZERO(option) THROW_IF_EQ(option, 0)
198+
199+ THROW_IF_ZERO(width);
200+ THROW_IF_ZERO(height);
201+ THROW_IF_EQ(pixel_format, mir_pixel_format_invalid);
202+ THROW_IF_UNSET(capture_region);
203+
204+ if (spec.capture_region.is_set())
205+ {
206+ auto const region = spec.capture_region.value();
207+ if (region.width == 0)
208+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid capture region width"));
209+ if (region.height == 0)
210+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid capture region height"));
211+ }
212+}
213+}
214+
215+MirScreencastSpec::MirScreencastSpec() = default;
216+
217+MirScreencastSpec::MirScreencastSpec(MirConnection* connection)
218+ : connection{connection}
219+{
220+}
221+
222+MirScreencastSpec::MirScreencastSpec(MirConnection* connection, MirScreencastParameters const& params)
223+ : connection{connection},
224+ width{params.width},
225+ height{params.height},
226+ pixel_format{params.pixel_format},
227+ capture_region{params.region}
228+{
229+}
230+
231+MirScreencast::MirScreencast(std::string const& error)
232+ : protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}
233+{
234+ protobuf_screencast->set_error(error);
235+}
236+
237 MirScreencast::MirScreencast(
238- geom::Rectangle const& region,
239- geom::Size const& size,
240- MirPixelFormat pixel_format,
241- mir::client::rpc::DisplayServer& server,
242- MirConnection* connection,
243+ MirScreencastSpec const& spec,
244+ mir::client::rpc::DisplayServer& the_server,
245 mir_screencast_callback callback, void* context)
246- : server(server),
247- connection{connection},
248- output_size{size},
249+ : server{&the_server},
250+ connection{spec.connection},
251 protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()},
252 protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()}
253 {
254- if (output_size.width.as_int() == 0 ||
255- output_size.height.as_int() == 0 ||
256- region.size.width.as_int() == 0 ||
257- region.size.height.as_int() == 0 ||
258- pixel_format == mir_pixel_format_invalid)
259- {
260- BOOST_THROW_EXCEPTION(std::runtime_error("Invalid parameters"));
261- }
262- protobuf_screencast->set_error("Not initialized");
263-
264- mp::ScreencastParameters parameters;
265-
266- parameters.mutable_region()->set_left(region.top_left.x.as_int());
267- parameters.mutable_region()->set_top(region.top_left.y.as_int());
268- parameters.mutable_region()->set_width(region.size.width.as_uint32_t());
269- parameters.mutable_region()->set_height(region.size.height.as_uint32_t());
270- parameters.set_width(output_size.width.as_uint32_t());
271- parameters.set_height(output_size.height.as_uint32_t());
272- parameters.set_pixel_format(pixel_format);
273+ throw_if_invalid(spec);
274+ auto const message = serialize_spec(spec);
275
276 create_screencast_wait_handle.expect_result();
277- server.create_screencast(
278- &parameters,
279+ server->create_screencast(
280+ &message,
281 protobuf_screencast.get(),
282 google::protobuf::NewCallback(
283 this, &MirScreencast::screencast_created,
284@@ -79,36 +136,53 @@
285
286 bool MirScreencast::valid()
287 {
288+ std::lock_guard<decltype(mutex)> lock(mutex);
289 return !protobuf_screencast->has_error();
290 }
291
292-MirWaitHandle* MirScreencast::release(
293- mir_screencast_callback callback, void* context)
294-{
295- mp::ScreencastId screencast_id;
296- screencast_id.set_value(protobuf_screencast->screencast_id().value());
297-
298+char const* MirScreencast::get_error_message()
299+{
300+ std::lock_guard<decltype(mutex)> lock(mutex);
301+ if (protobuf_screencast->has_error())
302+ {
303+ return protobuf_screencast->error().c_str();
304+ }
305+ return empty_error_message.c_str();
306+}
307+
308+MirWaitHandle* MirScreencast::release(mir_screencast_callback callback, void* context)
309+{
310 release_wait_handle.expect_result();
311- server.release_screencast(
312- &screencast_id,
313- protobuf_void.get(),
314- google::protobuf::NewCallback(
315- this, &MirScreencast::released, callback, context));
316+ if (valid() && server)
317+ {
318+ mp::ScreencastId screencast_id;
319+ {
320+ std::lock_guard<decltype(mutex)> lock(mutex);
321+ screencast_id.set_value(protobuf_screencast->screencast_id().value());
322+ }
323+ server->release_screencast(
324+ &screencast_id,
325+ protobuf_void.get(),
326+ google::protobuf::NewCallback(
327+ this, &MirScreencast::released, callback, context));
328+ }
329+ else
330+ {
331+ callback(this, context);
332+ release_wait_handle.result_received();
333+ }
334
335 return &release_wait_handle;
336 }
337
338-void MirScreencast::request_and_wait_for_configure(MirSurfaceAttrib, int)
339-{
340-}
341-
342 void MirScreencast::screencast_created(
343 mir_screencast_callback callback, void* context)
344 {
345 if (!protobuf_screencast->has_error() && connection)
346 {
347+ std::lock_guard<decltype(mutex)> lock(mutex);
348 buffer_stream = connection->make_consumer_stream(
349- protobuf_screencast->buffer_stream(), output_size);
350+ protobuf_screencast->buffer_stream(), {});
351 }
352
353 callback(this, context);
354@@ -119,14 +193,18 @@
355 mir_screencast_callback callback, void* context)
356 {
357 callback(this, context);
358- if (connection)
359- connection->release_consumer_stream(buffer_stream.get());
360- buffer_stream.reset();
361
362+ {
363+ std::lock_guard<decltype(mutex)> lock(mutex);
364+ if (connection)
365+ connection->release_consumer_stream(buffer_stream.get());
366+ buffer_stream.reset();
367+ }
368 release_wait_handle.result_received();
369 }
370
371 mir::client::ClientBufferStream* MirScreencast::get_buffer_stream()
372 {
373+ std::lock_guard<decltype(mutex)> lock(mutex);
374 return buffer_stream.get();
375 }
376
377=== modified file 'src/client/mir_screencast.h'
378--- src/client/mir_screencast.h 2016-01-29 08:18:22 +0000
379+++ src/client/mir_screencast.h 2016-03-28 14:29:53 +0000
380@@ -21,6 +21,7 @@
381
382 #include "mir_wait_handle.h"
383 #include "mir_toolkit/client_types.h"
384+#include "mir/optional_value.h"
385 #include "mir/geometry/size.h"
386 #include "mir/geometry/rectangle.h"
387
388@@ -46,27 +47,40 @@
389 }
390 }
391
392+struct MirScreencastSpec
393+{
394+ MirScreencastSpec();
395+ MirScreencastSpec(MirConnection* connection);
396+ MirScreencastSpec(MirConnection* connection, MirScreencastParameters const& params);
397+
398+ // Required parameters
399+ MirConnection* connection{nullptr};
400+
401+ // Optional parameters
402+ mir::optional_value<unsigned int> width;
403+ mir::optional_value<unsigned int> height;
404+ mir::optional_value<MirPixelFormat> pixel_format;
405+ mir::optional_value<MirRectangle> capture_region;
406+};
407+
408 struct MirScreencast
409 {
410 public:
411+ MirScreencast(std::string const& error);
412 MirScreencast(
413- mir::geometry::Rectangle const& region,
414- mir::geometry::Size const& size,
415- MirPixelFormat pixel_format,
416+ MirScreencastSpec const& spec,
417 mir::client::rpc::DisplayServer& server,
418- MirConnection* connection,
419 mir_screencast_callback callback, void* context);
420
421 MirWaitHandle* creation_wait_handle();
422 bool valid();
423+ char const* get_error_message();
424
425 MirWaitHandle* release(
426 mir_screencast_callback callback, void* context);
427
428 EGLNativeWindowType egl_native_window();
429
430- void request_and_wait_for_configure(MirSurfaceAttrib a, int value);
431-
432 mir::client::ClientBufferStream* get_buffer_stream();
433
434 private:
435@@ -75,16 +89,18 @@
436 void released(
437 mir_screencast_callback callback, void* context);
438
439- mir::client::rpc::DisplayServer& server;
440- MirConnection* connection;
441- mir::geometry::Size const output_size;
442+ std::mutex mutable mutex;
443+ mir::client::rpc::DisplayServer* const server{nullptr};
444+ MirConnection* const connection{nullptr};
445 std::shared_ptr<mir::client::ClientBufferStream> buffer_stream;
446
447- std::unique_ptr<mir::protobuf::Screencast> protobuf_screencast;
448- std::unique_ptr<mir::protobuf::Void> protobuf_void;
449+ std::unique_ptr<mir::protobuf::Screencast> const protobuf_screencast;
450+ std::unique_ptr<mir::protobuf::Void> const protobuf_void;
451
452 MirWaitHandle create_screencast_wait_handle;
453 MirWaitHandle release_wait_handle;
454+
455+ std::string const empty_error_message;
456 };
457
458 #endif /* MIR_CLIENT_MIR_SCREENCAST_H_ */
459
460=== modified file 'src/client/mir_screencast_api.cpp'
461--- src/client/mir_screencast_api.cpp 2015-06-18 02:46:16 +0000
462+++ src/client/mir_screencast_api.cpp 2016-03-28 14:29:53 +0000
463@@ -1,5 +1,5 @@
464 /*
465- * Copyright © 2014 Canonical Ltd.
466+ * Copyright © 2014,2016 Canonical Ltd.
467 *
468 * This program is free software: you can redistribute it and/or modify it
469 * under the terms of the GNU Lesser General Public License version 3,
470@@ -22,7 +22,7 @@
471 #include "mir_screencast.h"
472 #include "mir_connection.h"
473 #include "mir/raii.h"
474-
475+#include "mir/require.h"
476 #include "mir/uncaught.h"
477
478 #include <stdexcept>
479@@ -31,53 +31,78 @@
480 namespace
481 {
482 void null_callback(MirScreencast*, void*) {}
483-}
484+MirScreencast* create_screencast(MirScreencastSpec* spec)
485+{
486+ auto& server = spec->connection->display_server();
487+ auto screencast = std::make_unique<MirScreencast>(*spec, server, null_callback, nullptr);
488+ screencast->creation_wait_handle()->wait_for_all();
489+
490+ auto raw_screencast = screencast.get();
491+ screencast.release();
492+ return raw_screencast;
493+}
494+}
495+
496+MirScreencastSpec* mir_create_screencast_spec(MirConnection* connection)
497+{
498+ mir::require(mir_connection_is_valid(connection));
499+ return new MirScreencastSpec{connection};
500+}
501+
502+void mir_screencast_spec_set_width(MirScreencastSpec* spec, unsigned width)
503+{
504+ spec->width = width;
505+}
506+
507+void mir_screencast_spec_set_height(MirScreencastSpec* spec, unsigned height)
508+{
509+ spec->height = height;
510+}
511+
512+void mir_screencast_spec_set_pixel_format(MirScreencastSpec* spec, MirPixelFormat format)
513+{
514+ spec->pixel_format = format;
515+}
516+
517+void mir_screencast_spec_set_capture_region(MirScreencastSpec* spec, MirRectangle const* region)
518+{
519+ spec->capture_region = *region;
520+}
521+
522+void mir_screencast_spec_release(MirScreencastSpec* spec)
523+{
524+ delete spec;
525+}
526+
527+MirScreencast* mir_screencast_create_sync(MirScreencastSpec* spec)
528+try
529+{
530+ return create_screencast(spec);
531+}
532+catch (std::exception const& ex)
533+{
534+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
535+ return new MirScreencast(ex.what());
536+}
537+
538+bool mir_screencast_is_valid(MirScreencast *screencast)
539+{
540+ return screencast && screencast->valid();
541+}
542+
543+char const *mir_screencast_get_error_message(MirScreencast *screencast)
544+{
545+ return screencast->get_error_message();
546+}
547+
548
549 MirScreencast* mir_connection_create_screencast_sync(
550 MirConnection* connection,
551 MirScreencastParameters* parameters)
552 {
553- if (!MirConnection::is_valid(connection))
554- return nullptr;
555-
556- MirScreencast* screencast = nullptr;
557-
558- try
559- {
560- auto const config = mir::raii::deleter_for(
561- mir_connection_create_display_config(connection),
562- &mir_display_config_destroy);
563-
564- mir::geometry::Rectangle const region{
565- {parameters->region.left, parameters->region.top},
566- {parameters->region.width, parameters->region.height}
567- };
568- mir::geometry::Size const size{parameters->width, parameters->height};
569-
570- std::unique_ptr<MirScreencast> screencast_uptr{
571- new MirScreencast{
572- region,
573- size,
574- parameters->pixel_format,
575- connection->display_server(),
576- connection,
577- null_callback, nullptr}};
578-
579- screencast_uptr->creation_wait_handle()->wait_for_all();
580-
581- if (screencast_uptr->valid())
582- {
583- screencast = screencast_uptr.get();
584- screencast_uptr.release();
585- }
586- }
587- catch (std::exception const& ex)
588- {
589- MIR_LOG_UNCAUGHT_EXCEPTION(ex);
590- return nullptr;
591- }
592-
593- return screencast;
594+ mir::require(mir_connection_is_valid(connection));
595+ MirScreencastSpec spec{connection, *parameters};
596+ return mir_screencast_create_sync(&spec);
597 }
598
599 void mir_screencast_release_sync(MirScreencast* screencast)
600
601=== modified file 'src/client/symbols.map'
602--- src/client/symbols.map 2016-03-26 00:19:29 +0000
603+++ src/client/symbols.map 2016-03-28 14:29:53 +0000
604@@ -272,6 +272,7 @@
605 global:
606 mir_connection_confirm_base_display_configuration;
607 mir_connection_preview_base_display_configuration;
608+ mir_create_screencast_spec;
609 mir_display_config_get_mutable_output;
610 mir_output_disable;
611 mir_output_enable;
612@@ -280,6 +281,14 @@
613 mir_output_set_pixel_format;
614 mir_output_set_position;
615 mir_output_set_power_mode;
616+ mir_screencast_create_sync;
617+ mir_screencast_get_error_message;
618+ mir_screencast_is_valid;
619+ mir_screencast_spec_release;
620+ mir_screencast_spec_set_capture_region;
621+ mir_screencast_spec_set_height;
622+ mir_screencast_spec_set_pixel_format;
623+ mir_screencast_spec_set_width;
624 } MIR_CLIENT_0.21;
625
626 MIR_CLIENT_DETAIL_9 {
627
628=== modified file 'tests/acceptance-tests/test_client_screencast.cpp'
629--- tests/acceptance-tests/test_client_screencast.cpp 2015-06-25 03:00:08 +0000
630+++ tests/acceptance-tests/test_client_screencast.cpp 2016-03-28 14:29:53 +0000
631@@ -59,14 +59,6 @@
632
633 // TODO test case(s) showing screencast works. lp:1396681
634
635-TEST_F(Screencast, with_invalid_connection_fails)
636-{
637- using namespace testing;
638-
639- auto screencast = mir_connection_create_screencast_sync(nullptr, &default_screencast_params);
640- ASSERT_EQ(nullptr, screencast);
641-}
642-
643 TEST_F(Screencast, with_invalid_params_fails)
644 {
645 using namespace testing;
646@@ -79,19 +71,24 @@
647 MirScreencastParameters params = default_screencast_params;
648 params.width = params.height = 0;
649 auto screencast = mir_connection_create_screencast_sync(connection, &params);
650- ASSERT_EQ(nullptr, screencast);
651+ EXPECT_FALSE(mir_screencast_is_valid(screencast));
652+
653+ mir_screencast_release_sync(screencast);
654
655 params = default_screencast_params;
656 params.region.width = params.region.height = 0;
657 screencast = mir_connection_create_screencast_sync(connection, &params);
658- ASSERT_EQ(nullptr, screencast);
659+ EXPECT_FALSE(mir_screencast_is_valid(screencast));
660+
661+ mir_screencast_release_sync(screencast);
662
663 params = default_screencast_params;
664 params.pixel_format = mir_pixel_format_invalid;
665
666 screencast = mir_connection_create_screencast_sync(connection, &params);
667- ASSERT_EQ(nullptr, screencast);
668+ EXPECT_FALSE(mir_screencast_is_valid(screencast));
669
670+ mir_screencast_release_sync(screencast);
671 mir_connection_release(connection);
672 }
673
674@@ -105,7 +102,8 @@
675 auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
676
677 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
678- ASSERT_EQ(nullptr, screencast);
679+ EXPECT_FALSE(mir_screencast_is_valid(screencast));
680
681+ mir_screencast_release_sync(screencast);
682 mir_connection_release(connection);
683 }
684
685=== modified file 'tests/acceptance-tests/throwback/test_client_library_errors.cpp'
686--- tests/acceptance-tests/throwback/test_client_library_errors.cpp 2016-03-23 06:39:56 +0000
687+++ tests/acceptance-tests/throwback/test_client_library_errors.cpp 2016-03-28 14:29:53 +0000
688@@ -17,6 +17,7 @@
689 */
690
691 #include "mir_toolkit/mir_client_library.h"
692+#include "mir_toolkit/mir_screencast.h"
693 #include "mir_toolkit/debug/surface.h"
694
695 #include "src/include/client/mir/client_platform_factory.h"
696@@ -377,3 +378,9 @@
697 mir_persistent_id_release(id);
698 mir_connection_release(connection);
699 }
700+
701+TEST_F(ClientLibraryErrorsDeathTest, creating_screencast_with_invalid_connection)
702+{
703+ MirScreencastParameters params{{0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888};
704+ EXPECT_DEATH(mir_connection_create_screencast_sync(nullptr, &params), "");
705+}
706
707=== modified file 'tests/integration-tests/test_client_screencast.cpp'
708--- tests/integration-tests/test_client_screencast.cpp 2016-01-29 08:18:22 +0000
709+++ tests/integration-tests/test_client_screencast.cpp 2016-03-28 14:29:53 +0000
710@@ -41,6 +41,14 @@
711 namespace
712 {
713
714+MirRectangle as_mir_rect(mir::geometry::Rectangle const& rect)
715+{
716+ return {rect.top_left.x.as_int(),
717+ rect.top_left.y.as_int(),
718+ rect.size.width.as_uint32_t(),
719+ rect.size.height.as_uint32_t()};
720+}
721+
722 class StubChanger : public mtd::NullDisplayChanger
723 {
724 public:
725@@ -109,6 +117,8 @@
726
727 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
728 ASSERT_NE(nullptr, screencast);
729+ ASSERT_TRUE(mir_screencast_is_valid(screencast));
730+
731 mir_screencast_release_sync(screencast);
732 }
733
734@@ -137,6 +147,7 @@
735
736 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
737 ASSERT_NE(nullptr, screencast);
738+ ASSERT_TRUE(mir_screencast_is_valid(screencast));
739
740 mir_screencast_release_sync(screencast);
741 }
742@@ -156,6 +167,7 @@
743
744 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
745 ASSERT_NE(nullptr, screencast);
746+ ASSERT_TRUE(mir_screencast_is_valid(screencast));
747
748 auto egl_native_window =
749 mir_buffer_stream_get_egl_native_window(mir_screencast_get_buffer_stream(screencast));
750@@ -167,10 +179,54 @@
751 TEST_F(Screencast, fails_on_client_when_server_request_fails)
752 {
753 using namespace testing;
754-
755+ std::string const an_error_message{"boring error message"};
756 EXPECT_CALL(mock_screencast(), create_session(_, _, _))
757- .WillOnce(Throw(std::runtime_error("")));
758+ .WillOnce(Throw(std::runtime_error(an_error_message)));
759
760 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
761- ASSERT_EQ(nullptr, screencast);
762+ ASSERT_NE(nullptr, screencast);
763+ ASSERT_FALSE(mir_screencast_is_valid(screencast));
764+
765+ EXPECT_THAT(mir_screencast_get_error_message(screencast), HasSubstr(an_error_message));
766+ mir_screencast_release_sync(screencast);
767+}
768+
769+TEST_F(Screencast, uses_provided_spec_parameters)
770+{
771+ using namespace testing;
772+
773+ mf::ScreencastSessionId const screencast_session_id{99};
774+
775+ geom::Size const size{default_screencast_params.width, default_screencast_params.height};
776+ geom::Rectangle const region {
777+ {default_screencast_params.region.left, default_screencast_params.region.top},
778+ {default_screencast_params.region.width, default_screencast_params.region.height}};
779+ MirPixelFormat const pixel_format {default_screencast_params.pixel_format};
780+
781+ InSequence seq;
782+
783+ EXPECT_CALL(mock_screencast(),
784+ create_session(region, size, pixel_format))
785+ .WillOnce(Return(screencast_session_id));
786+
787+ EXPECT_CALL(mock_screencast(), capture(_))
788+ .WillOnce(Return(std::make_shared<mtd::StubBuffer>()));
789+
790+ EXPECT_CALL(mock_screencast(), destroy_session(_));
791+
792+ auto spec = mir_create_screencast_spec(connection);
793+
794+ mir_screencast_spec_set_width(spec, size.width.as_int());
795+ mir_screencast_spec_set_height(spec, size.height.as_int());
796+ mir_screencast_spec_set_pixel_format(spec, pixel_format);
797+ MirRectangle const capture_region = as_mir_rect(region);
798+ mir_screencast_spec_set_capture_region(spec, &capture_region);
799+
800+ auto screencast = mir_screencast_create_sync(spec);
801+ ASSERT_NE(nullptr, screencast);
802+ ASSERT_TRUE(mir_screencast_is_valid(screencast));
803+ EXPECT_STREQ(mir_screencast_get_error_message(screencast), "");
804+
805+ mir_screencast_spec_release(spec);
806+ mir_screencast_release_sync(screencast);
807 }
808
809=== modified file 'tests/unit-tests/client/test_mir_screencast.cpp'
810--- tests/unit-tests/client/test_mir_screencast.cpp 2016-01-29 08:18:22 +0000
811+++ tests/unit-tests/client/test_mir_screencast.cpp 2016-03-28 14:29:53 +0000
812@@ -150,6 +150,13 @@
813 {
814 }
815
816+MirRectangle as_mir_rect(mir::geometry::Rectangle const& rect)
817+{
818+ return {rect.top_left.x.as_int(),
819+ rect.top_left.y.as_int(),
820+ rect.size.width.as_uint32_t(),
821+ rect.size.height.as_uint32_t()};
822+}
823
824
825 class MirScreencastTest : public testing::Test
826@@ -160,6 +167,10 @@
827 default_region{{0, 0}, {1, 1}},
828 default_pixel_format{mir_pixel_format_xbgr_8888}
829 {
830+ default_spec.width = default_size.width.as_uint32_t();
831+ default_spec.height = default_size.height.as_uint32_t();
832+ default_spec.pixel_format = default_pixel_format;
833+ default_spec.capture_region = as_mir_rect(default_region);
834 }
835
836 testing::NiceMock<MockProtobufServer> mock_server;
837@@ -167,6 +178,7 @@
838 mir::geometry::Size default_size;
839 mir::geometry::Rectangle default_region;
840 MirPixelFormat default_pixel_format;
841+ MirScreencastSpec default_spec;
842 mtd::MockClientBufferStream mock_bs;
843 };
844
845@@ -180,12 +192,7 @@
846 create_screencast(WithParams(default_region, default_size, default_pixel_format),_,_))
847 .WillOnce(RunClosure());
848
849- MirScreencast screencast{
850- default_region,
851- default_size,
852- default_pixel_format, mock_server,
853- nullptr,
854- null_callback_func, nullptr};
855+ MirScreencast screencast{default_spec, mock_server, null_callback_func, nullptr};
856 }
857
858 TEST_F(MirScreencastTest, releases_screencast_on_release)
859@@ -204,13 +211,7 @@
860 release_screencast(WithScreencastId(screencast_id),_,_))
861 .WillOnce(RunClosure());
862
863- MirScreencast screencast{
864- default_region,
865- default_size,
866- default_pixel_format,
867- mock_server,
868- nullptr,
869- null_callback_func, nullptr};
870+ MirScreencast screencast{default_spec, mock_server, null_callback_func, nullptr};
871
872 screencast.release(null_callback_func, nullptr);
873 }
874@@ -222,12 +223,7 @@
875 MockCallback mock_cb;
876 EXPECT_CALL(mock_cb, call(_, &mock_cb));
877
878- MirScreencast screencast{
879- default_region,
880- default_size,
881- default_pixel_format, stub_server,
882- nullptr,
883- mock_callback_func, &mock_cb};
884+ MirScreencast screencast{default_spec, stub_server, mock_callback_func, &mock_cb};
885
886 screencast.creation_wait_handle()->wait_for_all();
887 }
888@@ -236,12 +232,7 @@
889 {
890 using namespace testing;
891
892- MirScreencast screencast{
893- default_region,
894- default_size,
895- default_pixel_format, stub_server,
896- nullptr,
897- null_callback_func, nullptr};
898+ MirScreencast screencast{default_spec, stub_server, null_callback_func, nullptr};
899
900 screencast.creation_wait_handle()->wait_for_all();
901
902@@ -258,30 +249,22 @@
903 mir::geometry::Rectangle const invalid_region{{0, 0}, {0, 0}};
904
905 EXPECT_THROW({
906- MirScreencast screencast(
907- default_region,
908- invalid_size,
909- default_pixel_format, stub_server,
910- nullptr,
911- null_callback_func, nullptr);
912- }, std::runtime_error);
913-
914- EXPECT_THROW({
915- MirScreencast screencast(
916- invalid_region,
917- default_size,
918- default_pixel_format, stub_server,
919- nullptr,
920- null_callback_func, nullptr);
921- }, std::runtime_error);
922-
923- EXPECT_THROW({
924- MirScreencast screencast(
925- default_region,
926- default_size,
927- mir_pixel_format_invalid, stub_server,
928- nullptr,
929- null_callback_func, nullptr);
930+ MirScreencastSpec spec{default_spec};
931+ spec.width = invalid_size.width.as_int();
932+ spec.height = invalid_size.height.as_int();
933+ MirScreencast screencast(spec, stub_server, null_callback_func, nullptr);
934+ }, std::runtime_error);
935+
936+ EXPECT_THROW({
937+ MirScreencastSpec spec{default_spec};
938+ spec.capture_region = as_mir_rect(invalid_region);
939+ MirScreencast screencast(spec, stub_server, null_callback_func, nullptr);
940+ }, std::runtime_error);
941+
942+ EXPECT_THROW({
943+ MirScreencastSpec spec{default_spec};
944+ spec.pixel_format = mir_pixel_format_invalid;
945+ MirScreencast screencast(spec, stub_server, null_callback_func, nullptr);
946 }, std::runtime_error);
947 }
948
949@@ -292,12 +275,7 @@
950 EXPECT_CALL(mock_server, create_screencast(_,_,_))
951 .WillOnce(DoAll(SetCreateError(), RunClosure()));
952
953- MirScreencast screencast{
954- default_region,
955- default_size,
956- default_pixel_format, mock_server,
957- nullptr,
958- null_callback_func, nullptr};
959+ MirScreencast screencast{default_spec, mock_server, null_callback_func, nullptr};
960
961 screencast.creation_wait_handle()->wait_for_all();
962
963@@ -313,14 +291,26 @@
964 .WillOnce(DoAll(SetCreateError(), RunClosure()));
965 EXPECT_CALL(mock_cb, call(_,&mock_cb));
966
967- MirScreencast screencast{
968- default_region,
969- default_size,
970- default_pixel_format, mock_server,
971- nullptr,
972- mock_callback_func, &mock_cb};
973-
974- screencast.creation_wait_handle()->wait_for_all();
975-
976- EXPECT_FALSE(screencast.valid());
977+ MirScreencast screencast{default_spec, mock_server, mock_callback_func, &mock_cb};
978+
979+ screencast.creation_wait_handle()->wait_for_all();
980+
981+ EXPECT_FALSE(screencast.valid());
982+}
983+
984+TEST_F(MirScreencastTest, release_callsback_even_if_invalid)
985+{
986+ using namespace testing;
987+
988+ EXPECT_CALL(mock_server, create_screencast(_,_,_))
989+ .WillOnce(DoAll(SetCreateError(), RunClosure()));
990+
991+ MirScreencast screencast{default_spec, mock_server, null_callback_func, nullptr};
992+ screencast.creation_wait_handle()->wait_for_all();
993+ EXPECT_FALSE(screencast.valid());
994+
995+ MockCallback mock_cb;
996+ EXPECT_CALL(mock_cb, call(_,&mock_cb));
997+
998+ screencast.release(mock_callback_func, &mock_cb);
999 }

Subscribers

People subscribed via source and target branches