1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <string.h>
9 
10 #include <zephyr/autoconf.h>
11 #include <zephyr/bluetooth/addr.h>
12 #include <zephyr/bluetooth/audio/mcc.h>
13 #include <zephyr/bluetooth/audio/media_proxy.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/services/ots.h>
17 #include <zephyr/sys/printk.h>
18 
19 #include "bstests.h"
20 #include "common.h"
21 
22 #ifdef CONFIG_BT_MCS
23 extern enum bst_result_t bst_result;
24 
25 static uint64_t g_icon_object_id;
26 static uint64_t g_track_segments_object_id;
27 static uint64_t g_current_track_object_id;
28 static uint64_t g_next_track_object_id;
29 static uint64_t g_parent_group_object_id;
30 static uint64_t g_current_group_object_id;
31 static uint64_t g_search_results_object_id;
32 
33 static int32_t  g_pos;
34 static int8_t   g_pb_speed;
35 static uint8_t  g_playing_order;
36 static uint8_t  g_state;
37 static uint8_t  g_command_result;
38 static uint32_t g_commands_supported;
39 static uint8_t  g_search_control_point_result_code;
40 
41 CREATE_FLAG(ble_is_initialized);
42 CREATE_FLAG(local_player_instance);
43 CREATE_FLAG(remote_player_instance);
44 CREATE_FLAG(player_name_read);
45 CREATE_FLAG(icon_object_id_read);
46 CREATE_FLAG(icon_url_read);
47 CREATE_FLAG(track_title_read);
48 CREATE_FLAG(track_duration_read);
49 CREATE_FLAG(track_position);
50 CREATE_FLAG(playback_speed);
51 CREATE_FLAG(seeking_speed_read);
52 CREATE_FLAG(track_segments_object_id_read);
53 CREATE_FLAG(current_track_object_id_read);
54 CREATE_FLAG(next_track_object_id_read);
55 CREATE_FLAG(parent_group_object_id_read);
56 CREATE_FLAG(current_group_object_id_read);
57 CREATE_FLAG(search_results_object_id_read);
58 CREATE_FLAG(playing_order_flag);
59 CREATE_FLAG(playing_orders_supported_read);
60 CREATE_FLAG(ccid_read);
61 CREATE_FLAG(media_state_read);
62 CREATE_FLAG(command_sent_flag);
63 CREATE_FLAG(command_results_flag);
64 CREATE_FLAG(commands_supported);
65 CREATE_FLAG(search_sent_flag);
66 CREATE_FLAG(search_result_code_flag);
67 
68 
69 static struct media_proxy_ctrl_cbs cbs;
70 static struct media_player *local_player;
71 static struct media_player *remote_player;
72 static struct media_player *current_player;
73 
local_player_instance_cb(struct media_player * player,int err)74 static void local_player_instance_cb(struct media_player *player, int err)
75 {
76 	if (err) {
77 		FAIL("Local player instance failed (%d)", err);
78 		return;
79 	}
80 
81 	local_player = player;
82 	SET_FLAG(local_player_instance);
83 }
84 
discover_player_cb(struct media_player * player,int err)85 static void discover_player_cb(struct media_player *player, int err)
86 {
87 	if (err) {
88 		FAIL("Discover player failed (%d)\n", err);
89 		return;
90 	}
91 
92 	remote_player = player;
93 	SET_FLAG(remote_player_instance);
94 }
95 
player_name_cb(struct media_player * plr,int err,const char * name)96 static void player_name_cb(struct media_player *plr, int err, const char *name)
97 {
98 	if (err) {
99 		FAIL("Player Name read failed (%d)\n", err);
100 		return;
101 	}
102 
103 	if (plr != current_player) {
104 		FAIL("Wrong player\n");
105 		return;
106 	}
107 
108 	SET_FLAG(player_name_read);
109 }
110 
icon_id_cb(struct media_player * plr,int err,uint64_t id)111 static void icon_id_cb(struct media_player *plr, int err, uint64_t id)
112 {
113 	if (err) {
114 		FAIL("Icon Object ID read failed (%d)", err);
115 		return;
116 	}
117 
118 	if (plr != current_player) {
119 		FAIL("Wrong player\n");
120 		return;
121 	}
122 
123 	g_icon_object_id = id;
124 	SET_FLAG(icon_object_id_read);
125 }
126 
icon_url_cb(struct media_player * plr,int err,const char * url)127 static void icon_url_cb(struct media_player *plr, int err, const char *url)
128 {
129 	if (err) {
130 		FAIL("Icon URL read failed (%d)", err);
131 		return;
132 	}
133 
134 	if (plr != current_player) {
135 		FAIL("Wrong player\n");
136 	}
137 
138 	SET_FLAG(icon_url_read);
139 }
140 
track_title_cb(struct media_player * plr,int err,const char * title)141 static void track_title_cb(struct media_player *plr, int err, const char *title)
142 {
143 	if (err) {
144 		FAIL("Track title read failed (%d)", err);
145 		return;
146 	}
147 
148 	if (plr != current_player) {
149 		FAIL("Wrong player\n");
150 		return;
151 	}
152 
153 	SET_FLAG(track_title_read);
154 }
155 
track_duration_cb(struct media_player * plr,int err,int32_t duration)156 static void track_duration_cb(struct media_player *plr, int err, int32_t duration)
157 {
158 	if (err) {
159 		FAIL("Track duration read failed (%d)", err);
160 		return;
161 	}
162 
163 	if (plr != current_player) {
164 		FAIL("Wrong player\n");
165 		return;
166 	}
167 
168 	SET_FLAG(track_duration_read);
169 }
170 
track_position_recv_cb(struct media_player * plr,int err,int32_t position)171 static void track_position_recv_cb(struct media_player *plr, int err, int32_t position)
172 {
173 	if (err) {
174 		FAIL("Track position read failed (%d)", err);
175 		return;
176 	}
177 
178 	if (plr != current_player) {
179 		FAIL("Wrong player\n");
180 		return;
181 	}
182 
183 	g_pos = position;
184 	SET_FLAG(track_position);
185 }
186 
track_position_write_cb(struct media_player * plr,int err,int32_t position)187 static void track_position_write_cb(struct media_player *plr, int err, int32_t position)
188 {
189 	if (err) {
190 		FAIL("Track position write failed (%d)", err);
191 		return;
192 	}
193 
194 	if (plr != current_player) {
195 		FAIL("Wrong player\n");
196 		return;
197 	}
198 
199 	g_pos = position;
200 	SET_FLAG(track_position);
201 }
202 
playback_speed_recv_cb(struct media_player * plr,int err,int8_t speed)203 static void playback_speed_recv_cb(struct media_player *plr, int err, int8_t speed)
204 {
205 	if (err) {
206 		FAIL("Playback speed read failed (%d)", err);
207 		return;
208 	}
209 
210 	if (plr != current_player) {
211 		FAIL("Wrong player\n");
212 		return;
213 	}
214 
215 	g_pb_speed = speed;
216 	SET_FLAG(playback_speed);
217 }
218 
playback_speed_write_cb(struct media_player * plr,int err,int8_t speed)219 static void playback_speed_write_cb(struct media_player *plr, int err, int8_t speed)
220 {
221 	if (err) {
222 		FAIL("Playback speed write failed (%d)", err);
223 		return;
224 	}
225 
226 	if (plr != current_player) {
227 		FAIL("Wrong player\n");
228 		return;
229 	}
230 
231 	g_pb_speed = speed;
232 	SET_FLAG(playback_speed);
233 }
234 
seeking_speed_cb(struct media_player * plr,int err,int8_t speed)235 static void seeking_speed_cb(struct media_player *plr, int err, int8_t speed)
236 {
237 	if (err) {
238 		FAIL("Seeking speed read failed (%d)", err);
239 		return;
240 	}
241 
242 	if (plr != current_player) {
243 		FAIL("Wrong player\n");
244 		return;
245 	}
246 
247 	SET_FLAG(seeking_speed_read);
248 }
249 
track_segments_id_cb(struct media_player * plr,int err,uint64_t id)250 static void track_segments_id_cb(struct media_player *plr, int err, uint64_t id)
251 {
252 	if (err) {
253 		FAIL("Track Segments ID read failed (%d)\n", err);
254 		return;
255 	}
256 
257 	if (plr != current_player) {
258 		FAIL("Wrong player\n");
259 		return;
260 	}
261 
262 	g_track_segments_object_id = id;
263 	SET_FLAG(track_segments_object_id_read);
264 }
265 
current_track_id_cb(struct media_player * plr,int err,uint64_t id)266 static void current_track_id_cb(struct media_player *plr, int err, uint64_t id)
267 {
268 	if (err) {
269 		FAIL("Current Track Object ID read failed (%d)\n", err);
270 		return;
271 	}
272 
273 	if (plr != current_player) {
274 		FAIL("Wrong player\n");
275 		return;
276 	}
277 
278 	g_current_track_object_id = id;
279 	SET_FLAG(current_track_object_id_read);
280 }
281 
next_track_id_cb(struct media_player * plr,int err,uint64_t id)282 static void next_track_id_cb(struct media_player *plr, int err, uint64_t id)
283 {
284 	if (err) {
285 		FAIL("Next Track Object ID read failed (%d)\n", err);
286 		return;
287 	}
288 
289 	if (plr != current_player) {
290 		FAIL("Wrong player\n");
291 		return;
292 	}
293 
294 	g_next_track_object_id = id;
295 	SET_FLAG(next_track_object_id_read);
296 }
297 
parent_group_id_cb(struct media_player * plr,int err,uint64_t id)298 static void parent_group_id_cb(struct media_player *plr, int err, uint64_t id)
299 {
300 	if (err) {
301 		FAIL("Parent Group Object ID read failed (%d)\n", err);
302 		return;
303 	}
304 
305 	if (plr != current_player) {
306 		FAIL("Wrong player\n");
307 		return;
308 	}
309 
310 	g_parent_group_object_id = id;
311 	SET_FLAG(parent_group_object_id_read);
312 }
313 
current_group_id_cb(struct media_player * plr,int err,uint64_t id)314 static void current_group_id_cb(struct media_player *plr, int err, uint64_t id)
315 {
316 	if (err) {
317 		FAIL("Current Group Object ID read failed (%d)\n", err);
318 		return;
319 	}
320 
321 	if (plr != current_player) {
322 		FAIL("Wrong player\n");
323 		return;
324 	}
325 
326 	g_current_group_object_id = id;
327 	SET_FLAG(current_group_object_id_read);
328 }
329 
playing_order_recv_cb(struct media_player * plr,int err,uint8_t order)330 static void playing_order_recv_cb(struct media_player *plr, int err, uint8_t order)
331 {
332 	if (err) {
333 		FAIL("Playing order read failed (%d)", err);
334 		return;
335 	}
336 
337 	if (plr != current_player) {
338 		FAIL("Wrong player\n");
339 		return;
340 	}
341 
342 	g_playing_order = order;
343 	SET_FLAG(playing_order_flag);
344 }
345 
playing_order_write_cb(struct media_player * plr,int err,uint8_t order)346 static void playing_order_write_cb(struct media_player *plr, int err, uint8_t order)
347 {
348 	if (err) {
349 		FAIL("Playing order write failed (%d)", err);
350 		return;
351 	}
352 
353 	if (plr != current_player) {
354 		FAIL("Wrong player\n");
355 		return;
356 	}
357 
358 	g_playing_order = order;
359 	SET_FLAG(playing_order_flag);
360 }
361 
playing_orders_supported_cb(struct media_player * plr,int err,uint16_t orders)362 static void playing_orders_supported_cb(struct media_player *plr, int err, uint16_t orders)
363 {
364 	if (err) {
365 		FAIL("Playing orders supported read failed (%d)", err);
366 		return;
367 	}
368 
369 	if (plr != current_player) {
370 		FAIL("Wrong player\n");
371 		return;
372 	}
373 
374 	SET_FLAG(playing_orders_supported_read);
375 }
376 
media_state_cb(struct media_player * plr,int err,uint8_t state)377 static void media_state_cb(struct media_player *plr, int err, uint8_t state)
378 {
379 	if (err) {
380 		FAIL("Media State read failed (%d)", err);
381 		return;
382 	}
383 
384 	if (plr != current_player) {
385 		FAIL("Wrong player\n");
386 		return;
387 	}
388 
389 	g_state = state;
390 	SET_FLAG(media_state_read);
391 }
392 
command_send_cb(struct media_player * plr,int err,const struct mpl_cmd * cmd)393 static void command_send_cb(struct media_player *plr, int err, const struct mpl_cmd *cmd)
394 {
395 	if (err) {
396 		FAIL("Command send failed (%d)", err);
397 		return;
398 	}
399 
400 	if (plr != current_player) {
401 		FAIL("Wrong player\n");
402 		return;
403 	}
404 
405 	SET_FLAG(command_sent_flag);
406 }
407 
command_recv_cb(struct media_player * plr,int err,const struct mpl_cmd_ntf * cmd_ntf)408 static void command_recv_cb(struct media_player *plr, int err, const struct mpl_cmd_ntf *cmd_ntf)
409 {
410 	if (err) {
411 		FAIL("Command failed (%d)", err);
412 		return;
413 	}
414 
415 	if (plr != current_player) {
416 		FAIL("Wrong player\n");
417 		return;
418 	}
419 
420 	g_command_result = cmd_ntf->result_code;
421 	SET_FLAG(command_results_flag);
422 }
423 
commands_supported_cb(struct media_player * plr,int err,uint32_t opcodes)424 static void commands_supported_cb(struct media_player *plr, int err, uint32_t opcodes)
425 {
426 	if (err) {
427 		FAIL("Commands supported failed (%d)", err);
428 		return;
429 	}
430 
431 	if (plr != current_player) {
432 		FAIL("Wrong player\n");
433 		return;
434 	}
435 
436 	g_commands_supported = opcodes;
437 	SET_FLAG(commands_supported);
438 }
439 
440 
441 
search_send_cb(struct media_player * plr,int err,const struct mpl_search * search)442 static void search_send_cb(struct media_player *plr, int err, const struct mpl_search *search)
443 {
444 	if (err) {
445 		FAIL("Search failed (%d)", err);
446 		return;
447 	}
448 
449 	if (plr != current_player) {
450 		FAIL("Wrong player\n");
451 		return;
452 	}
453 
454 	SET_FLAG(search_sent_flag);
455 }
456 
search_recv_cb(struct media_player * plr,int err,uint8_t result_code)457 static void search_recv_cb(struct media_player *plr, int err, uint8_t result_code)
458 {
459 	if (err) {
460 		FAIL("Search failed (%d), result code: %u", err, result_code);
461 		return;
462 	}
463 
464 	if (plr != current_player) {
465 		FAIL("Wrong player\n");
466 		return;
467 	}
468 
469 	g_search_control_point_result_code = result_code;
470 	SET_FLAG(search_result_code_flag);
471 }
472 
search_results_id_cb(struct media_player * plr,int err,uint64_t id)473 static void search_results_id_cb(struct media_player *plr, int err, uint64_t id)
474 {
475 	if (err) {
476 		FAIL("Search Results Object ID read failed (%d)", err);
477 		return;
478 	}
479 
480 	if (plr != current_player) {
481 		FAIL("Wrong player\n");
482 		return;
483 	}
484 
485 	g_search_results_object_id = id;
486 	SET_FLAG(search_results_object_id_read);
487 }
488 
content_ctrl_id_cb(struct media_player * plr,int err,uint8_t ccid)489 static void content_ctrl_id_cb(struct media_player *plr, int err, uint8_t ccid)
490 {
491 	if (err) {
492 		FAIL("Content control ID read failed (%d)", err);
493 		return;
494 	}
495 
496 	if (plr != current_player) {
497 		FAIL("Wrong player\n");
498 		return;
499 	}
500 
501 	SET_FLAG(ccid_read);
502 }
503 
initialize_media(void)504 void initialize_media(void)
505 {
506 	int err = media_proxy_pl_init();  /* TODO: Fix direct call to player */
507 
508 	if (err) {
509 		FAIL("Could not init mpl: %d", err);
510 		return;
511 	}
512 
513 	/* Set up the callback structure */
514 	cbs.local_player_instance         = local_player_instance_cb;
515 	cbs.discover_player               = discover_player_cb;
516 	cbs.player_name_recv              = player_name_cb;
517 	cbs.icon_id_recv                  = icon_id_cb;
518 	cbs.icon_url_recv                 = icon_url_cb;
519 	cbs.track_title_recv              = track_title_cb;
520 	cbs.track_duration_recv           = track_duration_cb;
521 	cbs.track_position_recv           = track_position_recv_cb;
522 	cbs.track_position_write          = track_position_write_cb;
523 	cbs.playback_speed_recv           = playback_speed_recv_cb;
524 	cbs.playback_speed_write          = playback_speed_write_cb;
525 	cbs.seeking_speed_recv            = seeking_speed_cb;
526 #ifdef CONFIG_BT_OTS
527 	cbs.track_segments_id_recv        = track_segments_id_cb;
528 	cbs.current_track_id_recv         = current_track_id_cb;
529 	cbs.next_track_id_recv            = next_track_id_cb;
530 	cbs.parent_group_id_recv          = parent_group_id_cb;
531 	cbs.current_group_id_recv         = current_group_id_cb;
532 #endif /* CONFIG_BT_OTS */
533 	cbs.playing_order_recv            = playing_order_recv_cb;
534 	cbs.playing_order_write           = playing_order_write_cb;
535 	cbs.playing_orders_supported_recv = playing_orders_supported_cb;
536 	cbs.media_state_recv              = media_state_cb;
537 	cbs.command_send                  = command_send_cb;
538 	cbs.command_recv                  = command_recv_cb;
539 	cbs.commands_supported_recv       = commands_supported_cb;
540 #ifdef CONFIG_BT_OTS
541 	cbs.search_send                   = search_send_cb;
542 	cbs.search_recv                   = search_recv_cb;
543 	cbs.search_results_id_recv        = search_results_id_cb;
544 #endif /* CONFIG_BT_OTS */
545 	cbs.content_ctrl_id_recv          = content_ctrl_id_cb;
546 
547 	UNSET_FLAG(local_player_instance);
548 
549 	err = media_proxy_ctrl_register(&cbs);
550 	if (err) {
551 		FAIL("Could not init mpl: %d", err);
552 		return;
553 	}
554 
555 	WAIT_FOR_FLAG(local_player_instance);
556 	printk("media init and local player instance succeeded\n");
557 }
558 
559 /* Callback after Bluetoot initialization attempt */
bt_ready(int err)560 static void bt_ready(int err)
561 {
562 	if (err) {
563 		FAIL("Bluetooth init failed (err %d)\n", err);
564 		return;
565 	}
566 
567 	SET_FLAG(ble_is_initialized);
568 }
569 
570 /* Helper function to read the media state and verify that it is as expected
571  * Will FAIL on error reading the media state
572  * Will FAIL if the state is not as expected
573  *
574  * Returns true if the state is as expected
575  * Returns false in case of errors, or if the state is not as expected
576  */
test_verify_media_state_wait_flags(uint8_t expected_state)577 static bool test_verify_media_state_wait_flags(uint8_t expected_state)
578 {
579 	int err;
580 
581 	UNSET_FLAG(media_state_read);
582 	err = media_proxy_ctrl_get_media_state(current_player);
583 	if (err) {
584 		FAIL("Failed to read media state: %d", err);
585 		return false;
586 	}
587 
588 	WAIT_FOR_FLAG(media_state_read);
589 	if (g_state != expected_state) {
590 		FAIL("Server is not in expected state: %d, expected: %d\n",
591 		     g_state, expected_state);
592 		return false;
593 	}
594 
595 	return true;
596 }
597 
598 /* Helper function to write commands to the control point, including the
599  * flag handling.
600  * Will FAIL on error to send the command.
601  * Will WAIT for the required flags before returning.
602  */
test_send_cmd_wait_flags(struct mpl_cmd * cmd)603 static void test_send_cmd_wait_flags(struct mpl_cmd *cmd)
604 {
605 	int err;
606 
607 	UNSET_FLAG(command_sent_flag);
608 	UNSET_FLAG(command_results_flag);
609 	err = media_proxy_ctrl_send_command(current_player, cmd);
610 	if (err) {
611 		FAIL("Failed to send command: %d, opcode: %u",
612 		     err, cmd->opcode);
613 		return;
614 	}
615 
616 	WAIT_FOR_FLAG(command_sent_flag);
617 	WAIT_FOR_FLAG(command_results_flag);
618 }
619 
test_cp_play(void)620 static void test_cp_play(void)
621 {
622 	struct mpl_cmd cmd;
623 
624 	cmd.opcode = MEDIA_PROXY_OP_PLAY;
625 	cmd.use_param = false;
626 
627 	test_send_cmd_wait_flags(&cmd);
628 
629 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
630 		FAIL("PLAY command failed\n");
631 		return;
632 	}
633 
634 	if (test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_PLAYING)) {
635 		printk("PLAY command succeeded\n");
636 	}
637 }
638 
test_cp_pause(void)639 static void test_cp_pause(void)
640 {
641 	struct mpl_cmd cmd;
642 
643 	cmd.opcode = MEDIA_PROXY_OP_PAUSE;
644 	cmd.use_param = false;
645 
646 	test_send_cmd_wait_flags(&cmd);
647 
648 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
649 		FAIL("PAUSE command failed\n");
650 		return;
651 	}
652 
653 	if (test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_PAUSED)) {
654 		printk("PAUSE command succeeded\n");
655 	}
656 }
657 
test_cp_fast_rewind(void)658 static void test_cp_fast_rewind(void)
659 {
660 	struct mpl_cmd cmd;
661 
662 	cmd.opcode = MEDIA_PROXY_OP_FAST_REWIND;
663 	cmd.use_param = false;
664 
665 	test_send_cmd_wait_flags(&cmd);
666 
667 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
668 		FAIL("FAST REWIND command failed\n");
669 		return;
670 	}
671 
672 	if (test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_SEEKING)) {
673 		printk("FAST REWIND command succeeded\n");
674 	}
675 }
676 
test_cp_fast_forward(void)677 static void test_cp_fast_forward(void)
678 {
679 	struct mpl_cmd cmd;
680 
681 	cmd.opcode = MEDIA_PROXY_OP_FAST_FORWARD;
682 	cmd.use_param = false;
683 
684 	test_send_cmd_wait_flags(&cmd);
685 
686 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
687 		FAIL("FAST FORWARD command failed\n");
688 		return;
689 	}
690 
691 	if (test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_SEEKING)) {
692 		printk("FAST FORWARD command succeeded\n");
693 	}
694 }
695 
test_cp_stop(void)696 static void test_cp_stop(void)
697 {
698 	struct mpl_cmd cmd;
699 
700 	cmd.opcode = MEDIA_PROXY_OP_STOP;
701 	cmd.use_param = false;
702 
703 	test_send_cmd_wait_flags(&cmd);
704 
705 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
706 		FAIL("STOP command failed\n");
707 		return;
708 	}
709 
710 	/* There is no "STOPPED" state in the spec - STOP goes to PAUSED */
711 	if (test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_PAUSED)) {
712 		printk("STOP command succeeded\n");
713 	}
714 }
715 
test_cp_move_relative(void)716 static void test_cp_move_relative(void)
717 {
718 	int err;
719 	struct mpl_cmd cmd;
720 
721 	/* Assumes that the server is in a state where it is  able to change
722 	 * the current track position
723 	 * Also assumes position will not change by itself, which is wrong if
724 	 * if the player is playing.
725 	 */
726 	UNSET_FLAG(track_position);
727 	err = media_proxy_ctrl_get_track_position(current_player);
728 	if (err) {
729 		FAIL("Failed to read track position: %d\n", err);
730 		return;
731 	}
732 
733 	WAIT_FOR_FLAG(track_position);
734 	uint32_t tmp_pos = g_pos;
735 
736 	cmd.opcode = MEDIA_PROXY_OP_MOVE_RELATIVE;
737 	cmd.use_param = true;
738 	cmd.param = 1000;  /* Position change, measured in 1/100 of a second */
739 
740 	test_send_cmd_wait_flags(&cmd);
741 
742 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
743 		FAIL("MOVE RELATIVE command failed\n");
744 		return;
745 	}
746 
747 	UNSET_FLAG(track_position);
748 	err = media_proxy_ctrl_get_track_position(current_player);
749 	if (err) {
750 		FAIL("Failed to read track position: %d\n", err);
751 		return;
752 	}
753 
754 	WAIT_FOR_FLAG(track_position);
755 	if (g_pos == tmp_pos) {
756 		/* Position did not change */
757 		FAIL("Server did not move track position\n");
758 		return;
759 	}
760 
761 	printk("MOVE RELATIVE command succeeded\n");
762 }
763 
test_cp_prev_segment(void)764 static void test_cp_prev_segment(void)
765 {
766 	struct mpl_cmd cmd;
767 
768 	/* Assumes that the server is in a state where there is a current
769 	 * track that has segments, and where the server may switch between
770 	 * these
771 	 */
772 
773 	/* To properly verify track segment changes, the track segments
774 	 * object must be downloaded and parsed.  That is somewhat complex,
775 	 * and is getting close to what the qualification tests do.
776 	 * Alternatively, the track position may be checked, but the server
777 	 * implementation does not set that for segment changes yet.
778 	 * For now, we will settle for seeing that the opcodes are accepted.
779 	 */
780 
781 	cmd.opcode = MEDIA_PROXY_OP_PREV_SEGMENT;
782 	cmd.use_param = false;
783 
784 	test_send_cmd_wait_flags(&cmd);
785 
786 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
787 		FAIL("PREV SEGMENT command failed\n");
788 		return;
789 	}
790 
791 	printk("PREV SEGMENT command succeeded\n");
792 }
793 
test_cp_next_segment(void)794 static void test_cp_next_segment(void)
795 {
796 	struct mpl_cmd cmd;
797 
798 	cmd.opcode = MEDIA_PROXY_OP_NEXT_SEGMENT;
799 	cmd.use_param = false;
800 
801 	test_send_cmd_wait_flags(&cmd);
802 
803 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
804 		FAIL("NEXT SEGMENT command failed\n");
805 		return;
806 	}
807 
808 	printk("NEXT SEGMENT command succeeded\n");
809 }
810 
test_cp_first_segment(void)811 static void test_cp_first_segment(void)
812 {
813 	struct mpl_cmd cmd;
814 
815 	cmd.opcode = MEDIA_PROXY_OP_FIRST_SEGMENT;
816 	cmd.use_param = false;
817 
818 	test_send_cmd_wait_flags(&cmd);
819 
820 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
821 		FAIL("FIRST SEGMENT command failed\n");
822 		return;
823 	}
824 
825 	printk("FIRST SEGMENT command succeeded\n");
826 }
827 
test_cp_last_segment(void)828 static void test_cp_last_segment(void)
829 {
830 	struct mpl_cmd cmd;
831 
832 	cmd.opcode = MEDIA_PROXY_OP_LAST_SEGMENT;
833 	cmd.use_param = false;
834 
835 	test_send_cmd_wait_flags(&cmd);
836 
837 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
838 		FAIL("LAST SEGMENT command failed\n");
839 		return;
840 	}
841 
842 	printk("LAST SEGMENT command succeeded\n");
843 }
844 
test_cp_goto_segment(void)845 static void test_cp_goto_segment(void)
846 {
847 	struct mpl_cmd cmd;
848 
849 	cmd.opcode = MEDIA_PROXY_OP_GOTO_SEGMENT;
850 	cmd.use_param = true;
851 	cmd.param = 2;    /* Second segment - not the first, maybe not last */
852 
853 	test_send_cmd_wait_flags(&cmd);
854 
855 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
856 		FAIL("GOTO SEGMENT command failed\n");
857 		return;
858 	}
859 
860 	printk("GOTO SEGMENT command succeeded\n");
861 }
862 
863 /* Helper function to read the current track object ID, including flag handling
864  * Will FAIL on error reading object ID
865  * Will WAIT until the read is completed (object ID flag read flag is set)
866  */
test_read_current_track_object_id_wait_flags(void)867 static void test_read_current_track_object_id_wait_flags(void)
868 {
869 	int err;
870 
871 	UNSET_FLAG(current_track_object_id_read);
872 	err = media_proxy_ctrl_get_current_track_id(current_player);
873 	if (err) {
874 		FAIL("Failed to read current track object ID: %d", err);
875 		return;
876 	}
877 
878 	WAIT_FOR_FLAG(current_track_object_id_read);
879 }
880 
test_cp_prev_track(void)881 static void test_cp_prev_track(void)
882 {
883 	uint64_t object_id;
884 	struct mpl_cmd cmd;
885 
886 	/* Assumes that the server is in a state where it has multiple tracks
887 	 * and can change between them.
888 	 */
889 
890 	/* To verify that a track change has happened, the test checks that the
891 	 * current track object ID has changed.
892 	 */
893 
894 	cmd.opcode = MEDIA_PROXY_OP_PREV_TRACK;
895 	cmd.use_param = false;
896 
897 	test_read_current_track_object_id_wait_flags();
898 	object_id = g_current_track_object_id;
899 
900 	test_send_cmd_wait_flags(&cmd);
901 
902 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
903 		FAIL("PREV TRACK command failed\n");
904 		return;
905 	}
906 
907 	test_read_current_track_object_id_wait_flags();
908 
909 	if (g_current_track_object_id == object_id) {
910 		/* Track did not change */
911 		FAIL("Server did not change track\n");
912 		return;
913 	}
914 
915 	printk("PREV TRACK command succeeded\n");
916 }
917 
test_cp_next_track(void)918 static void test_cp_next_track(void)
919 {
920 	uint64_t object_id;
921 	struct mpl_cmd cmd;
922 
923 	cmd.opcode = MEDIA_PROXY_OP_NEXT_TRACK;
924 	cmd.use_param = false;
925 
926 	test_read_current_track_object_id_wait_flags();
927 	object_id = g_current_track_object_id;
928 
929 	test_send_cmd_wait_flags(&cmd);
930 
931 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
932 		FAIL("NEXT TRACK command failed\n");
933 		return;
934 	}
935 
936 	test_read_current_track_object_id_wait_flags();
937 
938 	if (g_current_track_object_id == object_id) {
939 		FAIL("Server did not change track\n");
940 		return;
941 	}
942 
943 	printk("NEXT TRACK command succeeded\n");
944 }
945 
test_cp_first_track(void)946 static void test_cp_first_track(void)
947 {
948 	uint64_t object_id;
949 	struct mpl_cmd cmd;
950 
951 	cmd.opcode = MEDIA_PROXY_OP_FIRST_TRACK;
952 	cmd.use_param = false;
953 
954 	test_read_current_track_object_id_wait_flags();
955 	object_id = g_current_track_object_id;
956 
957 	test_send_cmd_wait_flags(&cmd);
958 
959 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
960 		FAIL("FIRST TRACK command failed\n");
961 		return;
962 	}
963 
964 	test_read_current_track_object_id_wait_flags();
965 
966 	if (g_current_track_object_id == object_id) {
967 		FAIL("Server did not change track\n");
968 		return;
969 	}
970 
971 	printk("FIRST TRACK command succeeded\n");
972 }
973 
test_cp_last_track(void)974 static void test_cp_last_track(void)
975 {
976 	uint64_t object_id;
977 	struct mpl_cmd cmd;
978 
979 	cmd.opcode = MEDIA_PROXY_OP_LAST_TRACK;
980 	cmd.use_param = false;
981 
982 	test_read_current_track_object_id_wait_flags();
983 	object_id = g_current_track_object_id;
984 
985 	test_send_cmd_wait_flags(&cmd);
986 
987 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
988 		FAIL("LAST TRACK command failed\n");
989 		return;
990 	}
991 
992 	test_read_current_track_object_id_wait_flags();
993 
994 	if (g_current_track_object_id == object_id) {
995 		FAIL("Server did not change track\n");
996 		return;
997 	}
998 
999 	printk("LAST TRACK command succeeded\n");
1000 }
1001 
test_cp_goto_track(void)1002 static void test_cp_goto_track(void)
1003 {
1004 	uint64_t object_id;
1005 	struct mpl_cmd cmd;
1006 
1007 	cmd.opcode = MEDIA_PROXY_OP_GOTO_TRACK;
1008 	cmd.use_param = true;
1009 	cmd.param = 2; /* Second track, not the first, maybe not the last */
1010 
1011 	test_read_current_track_object_id_wait_flags();
1012 	object_id = g_current_track_object_id;
1013 
1014 	test_send_cmd_wait_flags(&cmd);
1015 
1016 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1017 		FAIL("GOTO TRACK command failed\n");
1018 		return;
1019 	}
1020 
1021 	test_read_current_track_object_id_wait_flags();
1022 
1023 	if (g_current_track_object_id == object_id) {
1024 		FAIL("Server did not change track\n");
1025 		return;
1026 	}
1027 
1028 	printk("GOTO TRACK command succeeded\n");
1029 }
1030 
1031 /* Helper function to read the current group object ID, including flag handling
1032  * Will FAIL on error reading object ID
1033  * Will WAIT until the read is completed (object ID flag read flag is set)
1034  */
test_read_current_group_object_id_wait_flags(void)1035 static void test_read_current_group_object_id_wait_flags(void)
1036 {
1037 	int err;
1038 
1039 	UNSET_FLAG(current_group_object_id_read);
1040 	err = media_proxy_ctrl_get_current_group_id(current_player);
1041 	if (err) {
1042 		FAIL("Failed to read current group object ID: %d", err);
1043 		return;
1044 	}
1045 
1046 	WAIT_FOR_FLAG(current_group_object_id_read);
1047 }
1048 
test_cp_prev_group(void)1049 static void test_cp_prev_group(void)
1050 {
1051 	uint64_t object_id;
1052 	struct mpl_cmd cmd;
1053 
1054 	/* Assumes that the server is in a state where it has multiple groups
1055 	 * and can change between them.
1056 	 */
1057 
1058 	/* To verify that a group change has happened, the test checks that the
1059 	 * current group object ID has changed.
1060 	 */
1061 
1062 	cmd.opcode = MEDIA_PROXY_OP_PREV_GROUP;
1063 	cmd.use_param = false;
1064 
1065 	test_read_current_group_object_id_wait_flags();
1066 	object_id = g_current_group_object_id;
1067 
1068 	test_send_cmd_wait_flags(&cmd);
1069 
1070 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1071 		FAIL("PREV GROUP command failed\n");
1072 		return;
1073 	}
1074 
1075 	test_read_current_group_object_id_wait_flags();
1076 
1077 	if (g_current_group_object_id == object_id) {
1078 		/* Group did not change */
1079 		FAIL("Server did not change group\n");
1080 		return;
1081 	}
1082 
1083 	printk("PREV GROUP command succeeded\n");
1084 }
1085 
test_cp_next_group(void)1086 static void test_cp_next_group(void)
1087 {
1088 	uint64_t object_id;
1089 	struct mpl_cmd cmd;
1090 
1091 	cmd.opcode = MEDIA_PROXY_OP_NEXT_GROUP;
1092 	cmd.use_param = false;
1093 
1094 	test_read_current_group_object_id_wait_flags();
1095 	object_id = g_current_group_object_id;
1096 
1097 	test_send_cmd_wait_flags(&cmd);
1098 
1099 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1100 		FAIL("NEXT GROUP command failed\n");
1101 		return;
1102 	}
1103 
1104 	test_read_current_group_object_id_wait_flags();
1105 
1106 	if (g_current_group_object_id == object_id) {
1107 		FAIL("Server did not change group\n");
1108 		return;
1109 	}
1110 
1111 	printk("NEXT GROUP command succeeded\n");
1112 }
1113 
test_cp_first_group(void)1114 static void test_cp_first_group(void)
1115 {
1116 	uint64_t object_id;
1117 	struct mpl_cmd cmd;
1118 
1119 	cmd.opcode = MEDIA_PROXY_OP_FIRST_GROUP;
1120 	cmd.use_param = false;
1121 
1122 	test_read_current_group_object_id_wait_flags();
1123 	object_id = g_current_group_object_id;
1124 
1125 	test_send_cmd_wait_flags(&cmd);
1126 
1127 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1128 		FAIL("FIRST GROUP command failed\n");
1129 		return;
1130 	}
1131 
1132 	test_read_current_group_object_id_wait_flags();
1133 
1134 	if (g_current_group_object_id == object_id) {
1135 		FAIL("Server did not change group\n");
1136 		return;
1137 	}
1138 
1139 	printk("FIRST GROUP command succeeded\n");
1140 }
1141 
test_cp_last_group(void)1142 static void test_cp_last_group(void)
1143 {
1144 	uint64_t object_id;
1145 	struct mpl_cmd cmd;
1146 
1147 	cmd.opcode = MEDIA_PROXY_OP_LAST_GROUP;
1148 	cmd.use_param = false;
1149 
1150 	test_read_current_group_object_id_wait_flags();
1151 	object_id = g_current_group_object_id;
1152 
1153 	test_send_cmd_wait_flags(&cmd);
1154 
1155 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1156 		FAIL("LAST GROUP command failed\n");
1157 		return;
1158 	}
1159 
1160 	test_read_current_group_object_id_wait_flags();
1161 
1162 	if (g_current_group_object_id == object_id) {
1163 		FAIL("Server did not change group\n");
1164 		return;
1165 	}
1166 
1167 	printk("LAST GROUP command succeeded\n");
1168 }
1169 
test_cp_goto_group(void)1170 static void test_cp_goto_group(void)
1171 {
1172 	uint64_t object_id;
1173 	struct mpl_cmd cmd;
1174 
1175 	cmd.opcode = MEDIA_PROXY_OP_GOTO_GROUP;
1176 	cmd.use_param = true;
1177 	cmd.param = 2; /* Second group, not the first, maybe not the last */
1178 
1179 	test_read_current_group_object_id_wait_flags();
1180 	object_id = g_current_group_object_id;
1181 
1182 	test_send_cmd_wait_flags(&cmd);
1183 
1184 	if (g_command_result != MEDIA_PROXY_CMD_SUCCESS) {
1185 		FAIL("GOTO GROUP command failed\n");
1186 		return;
1187 	}
1188 
1189 	test_read_current_group_object_id_wait_flags();
1190 
1191 	if (g_current_group_object_id == object_id) {
1192 		FAIL("Server did not change group\n");
1193 		return;
1194 	}
1195 
1196 	printk("GOTO GROUP command succeeded\n");
1197 }
1198 
test_scp(void)1199 static void test_scp(void)
1200 {
1201 	struct mpl_search search;
1202 	struct mpl_sci sci = {0};
1203 	int err;
1204 
1205 	/* Test outline:
1206 	 * - verify that the search results object ID is zero before search
1207 	 * - write a search (one search control item) to the search control point,
1208 	 *   get write callback and notification
1209 	 * - verify that the search results object ID is non-zero
1210 	 */
1211 
1212 	UNSET_FLAG(search_results_object_id_read);
1213 	err = media_proxy_ctrl_get_search_results_id(current_player);
1214 
1215 	if (err) {
1216 		FAIL("Failed to read search results object ID: %d", err);
1217 		return;
1218 	}
1219 
1220 	WAIT_FOR_FLAG(search_results_object_id_read);
1221 
1222 	if (g_search_results_object_id != 0) {
1223 		FAIL("Search results object ID not zero before search\n");
1224 		return;
1225 	}
1226 
1227 	/* Set up the search control item, then the search
1228 	 *  Note: As of now, the server implementation only fakes the search,
1229 	 * so it makes no difference what we search for.  The result is the
1230 	 * same anyway.
1231 	 */
1232 	sci.type = MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME;
1233 	strcpy(sci.param, "Some track name");
1234 	/* Length is length of type, plus length of param w/o termination */
1235 	sci.len = sizeof(sci.type) + strlen(sci.param);
1236 
1237 	search.len = 0;
1238 	memcpy(&search.search[search.len], &sci.len, sizeof(sci.len));
1239 	search.len += sizeof(sci.len);
1240 
1241 	memcpy(&search.search[search.len], &sci.type, sizeof(sci.type));
1242 	search.len += sizeof(sci.type);
1243 
1244 	memcpy(&search.search[search.len], &sci.param, strlen(sci.param));
1245 	search.len += strlen(sci.param);
1246 
1247 	UNSET_FLAG(search_sent_flag);
1248 	UNSET_FLAG(search_result_code_flag);
1249 	UNSET_FLAG(search_results_object_id_read);
1250 
1251 	err = media_proxy_ctrl_send_search(current_player, &search);
1252 	if (err) {
1253 		FAIL("Failed to write to search control point\n");
1254 		return;
1255 	}
1256 
1257 	WAIT_FOR_FLAG(search_sent_flag);
1258 	WAIT_FOR_FLAG(search_result_code_flag);
1259 
1260 	if (g_search_control_point_result_code != MEDIA_PROXY_SEARCH_SUCCESS) {
1261 		FAIL("SEARCH operation failed\n");
1262 		return;
1263 	}
1264 
1265 	/* A search results object will have been created and the search
1266 	 * results object ID will have been notified if the search gave results
1267 	 */
1268 	WAIT_FOR_FLAG(search_results_object_id_read);
1269 	if (g_search_results_object_id == 0) {
1270 		FAIL("No search results\n");
1271 		return;
1272 	}
1273 
1274 	printk("SEARCH operation succeeded\n");
1275 }
1276 
1277 /* This function tests all commands in the API in sequence for the provided player.
1278  * (Works by setting the provided player as the "current player".)
1279  *
1280  * The order of the sequence follows the order of the characterstics in the
1281  * Media Control Service specification
1282  */
test_media_controller_player(struct media_player * player)1283 void test_media_controller_player(struct media_player *player)
1284 {
1285 	current_player = player;
1286 	int err;
1287 
1288 	UNSET_FLAG(player_name_read);
1289 	err = media_proxy_ctrl_get_player_name(current_player);
1290 	if (err) {
1291 		FAIL("Failed to read media player name ID: %d", err);
1292 		return;
1293 	}
1294 
1295 	WAIT_FOR_FLAG(player_name_read);
1296 	printk("Player Name read succeeded\n");
1297 
1298 	/* Read icon object id  ******************************************/
1299 	UNSET_FLAG(icon_object_id_read);
1300 	err = media_proxy_ctrl_get_icon_id(current_player);
1301 	if (err) {
1302 		FAIL("Failed to read icon object ID: %d", err);
1303 		return;
1304 	}
1305 
1306 	WAIT_FOR_FLAG(icon_object_id_read);
1307 	printk("Icon Object ID read succeeded\n");
1308 
1309 	/* Read icon url *************************************************/
1310 	UNSET_FLAG(icon_url_read);
1311 	err =  media_proxy_ctrl_get_icon_url(current_player);
1312 	if (err) {
1313 		FAIL("Failed to read icon url: %d", err);
1314 		return;
1315 	}
1316 
1317 	WAIT_FOR_FLAG(icon_url_read);
1318 	printk("Icon URL read succeeded\n");
1319 
1320 	/* Read track_title ******************************************/
1321 	UNSET_FLAG(track_title_read);
1322 	err = media_proxy_ctrl_get_track_title(current_player);
1323 	if (err) {
1324 		FAIL("Failed to read track_title: %d", err);
1325 		return;
1326 	}
1327 
1328 	WAIT_FOR_FLAG(track_title_read);
1329 	printk("Track title read succeeded\n");
1330 
1331 	/* Read track_duration ******************************************/
1332 	UNSET_FLAG(track_duration_read);
1333 	err = media_proxy_ctrl_get_track_duration(current_player);
1334 	if (err) {
1335 		FAIL("Failed to read track_duration: %d", err);
1336 		return;
1337 	}
1338 
1339 	WAIT_FOR_FLAG(track_duration_read);
1340 	printk("Track duration read succeeded\n");
1341 
1342 	/* Read and set track_position *************************************/
1343 	UNSET_FLAG(track_position);
1344 	err = media_proxy_ctrl_get_track_position(current_player);
1345 	if (err) {
1346 		FAIL("Failed to read track position: %d", err);
1347 		return;
1348 	}
1349 
1350 	WAIT_FOR_FLAG(track_position);
1351 	printk("Track position read succeeded\n");
1352 
1353 	int32_t pos = g_pos + 1200; /*12 seconds further into the track */
1354 
1355 	UNSET_FLAG(track_position);
1356 	err = media_proxy_ctrl_set_track_position(current_player, pos);
1357 	if (err) {
1358 		FAIL("Failed to set track position: %d", err);
1359 		return;
1360 	}
1361 
1362 	WAIT_FOR_FLAG(track_position);
1363 	if (g_pos != pos) {
1364 		/* In this controlled case, we expect that the resulting */
1365 		/* position is the position given in the set command */
1366 		FAIL("Track position set failed: Incorrect position\n");
1367 	}
1368 	printk("Track position set succeeded\n");
1369 
1370 	/* Read and set playback speed *************************************/
1371 	UNSET_FLAG(playback_speed);
1372 	err = media_proxy_ctrl_get_playback_speed(current_player);
1373 	if (err) {
1374 		FAIL("Failed to read playback speed: %d", err);
1375 		return;
1376 	}
1377 
1378 	WAIT_FOR_FLAG(playback_speed);
1379 	printk("Playback speed read succeeded\n");
1380 
1381 	int8_t pb_speed = g_pb_speed + 8; /* 2^(8/64) faster than current speed */
1382 
1383 	UNSET_FLAG(playback_speed);
1384 	err = media_proxy_ctrl_set_playback_speed(current_player, pb_speed);
1385 	if (err) {
1386 		FAIL("Failed to set playback speed: %d", err);
1387 		return;
1388 	}
1389 
1390 	WAIT_FOR_FLAG(playback_speed);
1391 	if (g_pb_speed != pb_speed) {
1392 		FAIL("Playback speed failed: Incorrect playback speed\n");
1393 	}
1394 	printk("Playback speed set succeeded\n");
1395 
1396 	/* Read seeking speed *************************************/
1397 	UNSET_FLAG(seeking_speed_read);
1398 	err = media_proxy_ctrl_get_seeking_speed(current_player);
1399 	if (err) {
1400 		FAIL("Failed to read seeking speed: %d", err);
1401 		return;
1402 	}
1403 
1404 	WAIT_FOR_FLAG(seeking_speed_read);
1405 	printk("Seeking speed read succeeded\n");
1406 
1407 	/* Read track segments object *****************************************/
1408 	UNSET_FLAG(track_segments_object_id_read);
1409 	err = media_proxy_ctrl_get_track_segments_id(current_player);
1410 	if (err) {
1411 		FAIL("Failed to read track segments object ID: %d", err);
1412 		return;
1413 	}
1414 
1415 	WAIT_FOR_FLAG(track_segments_object_id_read);
1416 	printk("Track Segments Object ID read succeeded\n");
1417 
1418 	/* Read current track object ******************************************/
1419 	UNSET_FLAG(current_track_object_id_read);
1420 	err = media_proxy_ctrl_get_current_track_id(current_player);
1421 	if (err) {
1422 		FAIL("Failed to read current track object ID: %d", err);
1423 		return;
1424 	}
1425 
1426 	WAIT_FOR_FLAG(current_track_object_id_read);
1427 	printk("Current Track Object ID read succeeded\n");
1428 
1429 	/* Read next track object ******************************************/
1430 	UNSET_FLAG(next_track_object_id_read);
1431 	err = media_proxy_ctrl_get_next_track_id(current_player);
1432 	if (err) {
1433 		FAIL("Failed to read next track object ID: %d", err);
1434 		return;
1435 	}
1436 
1437 	WAIT_FOR_FLAG(next_track_object_id_read);
1438 	printk("Next Track Object ID read succeeded\n");
1439 
1440 	/* Read parent group object ******************************************/
1441 	UNSET_FLAG(parent_group_object_id_read);
1442 	err = media_proxy_ctrl_get_parent_group_id(current_player);
1443 	if (err) {
1444 		FAIL("Failed to read parent group object ID: %d", err);
1445 		return;
1446 	}
1447 
1448 	WAIT_FOR_FLAG(parent_group_object_id_read);
1449 	printk("Parent Group Object ID read succeeded\n");
1450 
1451 	/* Read current group object ******************************************/
1452 	UNSET_FLAG(current_group_object_id_read);
1453 	err = media_proxy_ctrl_get_current_group_id(current_player);
1454 	if (err) {
1455 		FAIL("Failed to read current group object ID: %d", err);
1456 		return;
1457 	}
1458 
1459 	WAIT_FOR_FLAG(current_group_object_id_read);
1460 	printk("Current Group Object ID read succeeded\n");
1461 
1462 	/* Read and set playing order *************************************/
1463 	UNSET_FLAG(playing_order_flag);
1464 	err = media_proxy_ctrl_get_playing_order(current_player);
1465 	if (err) {
1466 		FAIL("Failed to read playing order: %d", err);
1467 		return;
1468 	}
1469 
1470 	WAIT_FOR_FLAG(playing_order_flag);
1471 	printk("Playing order read succeeded\n");
1472 
1473 	uint8_t playing_order;
1474 
1475 	if (g_playing_order != MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE) {
1476 		playing_order = MEDIA_PROXY_PLAYING_ORDER_INORDER_ONCE;
1477 	} else {
1478 		playing_order = MEDIA_PROXY_PLAYING_ORDER_INORDER_REPEAT;
1479 	}
1480 
1481 	UNSET_FLAG(playing_order_flag);
1482 	err = media_proxy_ctrl_set_playing_order(current_player, playing_order);
1483 	if (err) {
1484 		FAIL("Failed to set playing_order: %d", err);
1485 		return;
1486 	}
1487 
1488 	WAIT_FOR_FLAG(playing_order_flag);
1489 	if (g_playing_order != playing_order) {
1490 		FAIL("Playing order set failed: Incorrect playing_order\n");
1491 	}
1492 	printk("Playing order set succeeded\n");
1493 
1494 	/* Read playing orders supported  *************************************/
1495 	UNSET_FLAG(playing_orders_supported_read);
1496 	err = media_proxy_ctrl_get_playing_orders_supported(current_player);
1497 	if (err) {
1498 		FAIL("Failed to read playing orders supported: %d", err);
1499 		return;
1500 	}
1501 
1502 	WAIT_FOR_FLAG(playing_orders_supported_read);
1503 	printk("Playing orders supported read succeeded\n");
1504 
1505 	/* Read media state  ***************************************************/
1506 	UNSET_FLAG(media_state_read);
1507 	err = media_proxy_ctrl_get_media_state(current_player);
1508 	if (err) {
1509 		FAIL("Failed to read media state: %d", err);
1510 		return;
1511 	}
1512 
1513 	WAIT_FOR_FLAG(media_state_read);
1514 	printk("Media state read succeeded\n");
1515 
1516 	/* Read content control ID  *******************************************/
1517 	UNSET_FLAG(ccid_read);
1518 	err = media_proxy_ctrl_get_content_ctrl_id(current_player);
1519 	if (err) {
1520 		FAIL("Failed to read content control ID: %d", err);
1521 		return;
1522 	}
1523 
1524 	WAIT_FOR_FLAG(ccid_read);
1525 	printk("Content control ID read succeeded\n");
1526 
1527 	/* Control point - "state" opcodes */
1528 
1529 	/* This part of the test not only checks that the opcodes are accepted
1530 	 * by the server, but also that they actually do lead to the expected
1531 	 * state changes.  This may lean too much upon knowledge or assumptions,
1532 	 * and therefore be too fragile.
1533 	 * It may be more robust to just give commands and check for the success
1534 	 * code in the control point notifications
1535 	 */
1536 
1537 	/* It is assumed that the server starts the test in the paused state */
1538 	test_verify_media_state_wait_flags(MEDIA_PROXY_STATE_PAUSED);
1539 
1540 	/* The tests are ordered to ensure that each command changes state */
1541 	test_cp_play();
1542 	test_cp_fast_forward();
1543 	test_cp_pause();
1544 	test_cp_fast_rewind();
1545 	test_cp_stop();
1546 
1547 
1548 	/* Control point - move relative opcode */
1549 	test_cp_move_relative();
1550 
1551 	/* Control point - segment change opcodes */
1552 	test_cp_prev_segment();
1553 	test_cp_next_segment();
1554 	test_cp_first_segment();
1555 	test_cp_last_segment();
1556 	test_cp_goto_segment();
1557 
1558 
1559 	/* Control point - track change opcodes */
1560 	/* The tests are ordered to ensure that each command changes track */
1561 	/* Assumes we are not starting on the last track */
1562 	test_cp_next_track();
1563 	test_cp_prev_track();
1564 	test_cp_last_track();
1565 	test_cp_first_track();
1566 	test_cp_goto_track();
1567 
1568 
1569 	/* Control point - group change opcodes *******************************/
1570 	/* The tests are ordered to ensure that each command changes group */
1571 	/* Assumes we are not starting on the last group */
1572 	test_cp_next_group();
1573 	test_cp_prev_group();
1574 	test_cp_last_group();
1575 	test_cp_first_group();
1576 	test_cp_goto_group();
1577 
1578 
1579 	/* Search control point */
1580 	test_scp();
1581 }
1582 
initialize_bluetooth(void)1583 void initialize_bluetooth(void)
1584 {
1585 	int err;
1586 
1587 	UNSET_FLAG(ble_is_initialized);
1588 	err = bt_enable(bt_ready);
1589 	if (err) {
1590 		FAIL("Bluetooth init failed (err %d)\n", err);
1591 		return;
1592 	}
1593 
1594 	WAIT_FOR_FLAG(ble_is_initialized);
1595 	printk("Bluetooth initialized\n");
1596 
1597 	bt_le_scan_cb_register(&common_scan_cb);
1598 }
1599 
scan_and_connect(void)1600 void scan_and_connect(void)
1601 {
1602 	char addr[BT_ADDR_LE_STR_LEN];
1603 	int err;
1604 
1605 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
1606 	if (err) {
1607 		FAIL("Failed to start scanning (err %d\n)", err);
1608 		return;
1609 	}
1610 
1611 	printk("Scanning started successfully\n");
1612 
1613 	WAIT_FOR_FLAG(flag_connected);
1614 
1615 	bt_addr_le_to_str(bt_conn_get_dst(default_conn), addr, sizeof(addr));
1616 	printk("Connected: %s\n", addr);
1617 }
1618 
discover_remote_player(void)1619 void discover_remote_player(void)
1620 {
1621 	int err;
1622 
1623 	UNSET_FLAG(remote_player_instance);
1624 	err = media_proxy_ctrl_discover_player(default_conn);
1625 	if (err) {
1626 		FAIL("Remote player discovery failed (err %d)\n", err);
1627 		return;
1628 	}
1629 
1630 	WAIT_FOR_FLAG(remote_player_instance);
1631 }
1632 
1633 /* BabbleSim entry point for local player test */
test_media_controller_local_player(void)1634 void test_media_controller_local_player(void)
1635 {
1636 	printk("Media Control local player test application.  Board: %s\n", CONFIG_BOARD);
1637 
1638 	initialize_bluetooth();
1639 	initialize_media();  /* Sets local_player global variable */
1640 
1641 	printk("Local player instance: %p\n", local_player);
1642 
1643 	test_media_controller_player(local_player);
1644 
1645 	/* TEST IS COMPLETE */
1646 	PASS("Test media_controller_local_player passed\n");
1647 }
1648 
1649 /* BabbleSim entry point for remote player test */
test_media_controller_remote_player(void)1650 void test_media_controller_remote_player(void)
1651 {
1652 	int err;
1653 	printk("Media Control remote player test application.  Board: %s\n", CONFIG_BOARD);
1654 
1655 	initialize_bluetooth();
1656 	initialize_media();
1657 
1658 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, AD_SIZE, NULL, 0);
1659 	if (err) {
1660 		FAIL("Advertising failed to start (err %d)\n", err);
1661 	}
1662 
1663 	WAIT_FOR_FLAG(flag_connected);
1664 
1665 	discover_remote_player(); /* Sets global variable */
1666 	printk("Remote player instance: %p\n", remote_player);
1667 
1668 	test_media_controller_player(remote_player);
1669 
1670 	/* TEST IS COMPLETE */
1671 	PASS("Test media_controller_remote_player passed\n");
1672 }
1673 
1674 /* BabbleSim entry point for server for remote player test */
test_media_controller_server(void)1675 void test_media_controller_server(void)
1676 {
1677 
1678 	printk("Media Control server test application.  Board: %s\n", CONFIG_BOARD);
1679 
1680 	initialize_bluetooth();
1681 	initialize_media();
1682 
1683 	/* The server side will also get callbacks, from its local player.
1684 	 * And if the current player is not set, the callbacks will fail the test.
1685 	 */
1686 	printk("Local player instance: %p\n", local_player);
1687 	current_player = local_player;
1688 
1689 	scan_and_connect();
1690 
1691 	/* TEST IS COMPLETE */
1692 	PASS("Test media_controller_server passed\n");
1693 }
1694 
1695 static const struct bst_test_instance test_media_controller[] = {
1696 	{
1697 		.test_id = "media_controller_local_player",
1698 		.test_pre_init_f = test_init,
1699 		.test_tick_f = test_tick,
1700 		.test_main_f = test_media_controller_local_player
1701 	},
1702 	{
1703 		.test_id = "media_controller_remote_player",
1704 		.test_pre_init_f = test_init,
1705 		.test_tick_f = test_tick,
1706 		.test_main_f = test_media_controller_remote_player
1707 	},
1708 	{
1709 		.test_id = "media_controller_server",
1710 		.test_pre_init_f = test_init,
1711 		.test_tick_f = test_tick,
1712 		.test_main_f = test_media_controller_server
1713 	},
1714 	BSTEST_END_MARKER
1715 };
1716 
test_media_controller_install(struct bst_test_list * tests)1717 struct bst_test_list *test_media_controller_install(struct bst_test_list *tests)
1718 {
1719 	return bst_add_tests(tests, test_media_controller);
1720 }
1721 
1722 #else
1723 
test_media_controller_install(struct bst_test_list * tests)1724 struct bst_test_list *test_media_controller_install(struct bst_test_list *tests)
1725 {
1726 	return tests;
1727 }
1728 
1729 #endif /* CONFIG_BT_MCS */
1730