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