Merge lp:~albaguirre/mir/add-mirscreencast-spec into lp:mir
- add-mirscreencast-spec
- Merge into development-branch
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 |
Related bugs: |
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
MirScreencastPa
Instead use a MirScreencastSpec similar to MirSurfaceSpec to specify existing and future options.
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
Kevin DuBois (kdub) wrote : | # |
+MirScreencast* create_
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-
(in the same sort of manner as streams/
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
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-
Yeah I plan to move the construction/
>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.
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3425
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
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 | - ¶meters, |
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, ¶ms); |
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, ¶ms); |
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, ¶ms); |
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, ¶ms), ""); |
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 | } |
PASSED: Continuous integration, rev:3424 /mir-jenkins. ubuntu. com/job/ mir-ci/ 659/ /mir-jenkins. ubuntu. com/job/ build-mir/ 603 /mir-jenkins. ubuntu. com/job/ build-0- fetch/640 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 632 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 632 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 613 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 613/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 613 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 613/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 613 /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 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 613 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 613/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 613 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 613/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 659/rebuild
https:/