Merge "[MediaController] Adding, updating and sending item." into tizen
[platform/core/api/webapi-plugins.git] / src / mediacontroller / mediacontroller_client.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "mediacontroller/mediacontroller_client.h"
18
19 #include <bundle.h>
20 #include <bundle_internal.h>
21 #include <memory>
22
23 #include "common/logger.h"
24 #include "common/scope_exit.h"
25 #include "common/tools.h"
26
27 #include "mediacontroller/mediacontroller_types.h"
28
29 namespace extension {
30 namespace mediacontroller {
31
32 using common::PlatformResult;
33 using common::ErrorCode;
34 using common::tools::ReportError;
35 using common::tools::ReportSuccess;
36
37 MediaControllerClient::MediaControllerClient() : handle_(nullptr) {
38   ScopeLogger();
39 }
40
41 MediaControllerClient::~MediaControllerClient() {
42   ScopeLogger();
43
44   int ret = mc_client_unset_cmd_reply_received_cb(handle_);
45   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
46     LoggerE("Failed to unset cmd reply callback. Error code: %d; Error message: %s", ret,
47             get_error_message(ret));
48   }
49
50   if (nullptr != server_status_listener_ && !UnsetServerStatusChangeListener()) {
51     LoggerE("Failed to unset server status change listener");
52   }
53
54   if (nullptr != playback_info_listener_ && !UnsetPlaybackInfoListener()) {
55     LoggerE("Failed to unset playback info listener");
56   }
57
58   if (nullptr != handle_ && MEDIA_CONTROLLER_ERROR_NONE != mc_client_destroy(handle_)) {
59     LoggerE("Unable to destroy media controller client");
60   }
61 }
62
63 PlatformResult MediaControllerClient::Init() {
64   ScopeLogger();
65   int ret = mc_client_create(&handle_);
66   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
67     return LogAndCreateResult(
68         ErrorCode::UNKNOWN_ERR, "Unable to create media controller client",
69         ("mc_client_create() error: %d, message: %s", ret, get_error_message(ret)));
70   }
71
72   ret = mc_client_set_cmd_reply_received_cb(handle_, OnCommandReply, this);
73   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
74     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR,
75                               "Unable to register cmd reply received callback",
76                               ("mc_client_set_cmd_reply_received_cb() error: %d, message: %s", ret,
77                                get_error_message(ret)));
78   }
79
80   return PlatformResult(ErrorCode::NO_ERROR);
81 }
82
83 PlatformResult MediaControllerClient::FindServers(picojson::array* servers) {
84   ScopeLogger();
85   int ret;
86
87   ret = mc_client_foreach_server(handle_, FindServersCallback, servers);
88   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
89     return LogAndCreateResult(
90         ErrorCode::UNKNOWN_ERR, "Unable to fetch active servers, error",
91         ("mc_client_foreach_server() error: %d, message: %s", ret, get_error_message(ret)));
92   }
93
94   // check latest server state - if exist
95   picojson::value latest_server = picojson::value();
96   PlatformResult result = GetLatestServerInfo(&latest_server);
97   if (!result) {
98     LoggerE("GetLatestServerInfo failed, error: %s", result.message().c_str());
99     return result;
100   }
101
102   if (latest_server.is<picojson::null>()) {
103     LoggerD("No latest server available");
104     return PlatformResult(ErrorCode::NO_ERROR);
105   }
106
107   const std::string& latest_name = latest_server.get("name").get<std::string>();
108
109   // update current server state in list
110   for (auto& it : *servers) {
111     picojson::object& server = it.get<picojson::object>();
112     if (server["name"].get<std::string>() == latest_name) {
113       server["state"] = latest_server.get("state");
114       break;
115     }
116   }
117
118   return PlatformResult(ErrorCode::NO_ERROR);
119 }
120
121 bool MediaControllerClient::FindServersCallback(const char* server_name, void* user_data) {
122   ScopeLogger();
123   picojson::array* servers = static_cast<picojson::array*>(user_data);
124
125   picojson::value server = picojson::value(picojson::object());
126   picojson::object& server_o = server.get<picojson::object>();
127   server_o["name"] = picojson::value(std::string(server_name));
128   // active by default in CAPI
129   server_o["state"] = picojson::value(std::string("ACTIVE"));
130
131   servers->push_back(server);
132
133   return true;
134 }
135
136 PlatformResult MediaControllerClient::GetLatestServerInfo(picojson::value* server_info) {
137   ScopeLogger();
138   int ret;
139
140   char* name = nullptr;
141   SCOPE_EXIT {
142     free(name);
143   };
144   mc_server_state_e state;
145   ret = mc_client_get_latest_server_info(handle_, &name, &state);
146   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
147     return LogAndCreateResult(
148         ErrorCode::UNKNOWN_ERR, "Error getting latest server info",
149         ("mc_client_get_latest_server_info() error: %d, message: %s", ret, get_error_message(ret)));
150   }
151
152   if (!name) {
153     LoggerD("No active server available");
154     return PlatformResult(ErrorCode::NO_ERROR);
155   }
156
157   std::string state_str;
158   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
159                                                       static_cast<int>(state), &state_str);
160   if (!result) {
161     LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
162     return result;
163   }
164
165   *server_info = picojson::value(picojson::object());
166   picojson::object& obj = server_info->get<picojson::object>();
167   obj["name"] = picojson::value(std::string(name));
168   obj["state"] = picojson::value(state_str);
169
170   return PlatformResult(ErrorCode::NO_ERROR);
171 }
172
173 PlatformResult MediaControllerClient::GetPlaybackInfo(const std::string& server_name,
174                                                       picojson::object* playback_info) {
175   ScopeLogger();
176   int ret;
177
178   mc_playback_h playback_h;
179   ret = mc_client_get_server_playback_info(handle_, server_name.c_str(), &playback_h);
180   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
181     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting playback info",
182                               ("mc_client_get_server_playback_info() error: %d, message: %s", ret,
183                                get_error_message(ret)));
184   }
185
186   SCOPE_EXIT {
187     mc_client_destroy_playback(playback_h);
188   };
189
190   // playback state
191   std::string state;
192   PlatformResult result = Types::ConvertPlaybackState(playback_h, &state);
193   if (!result) {
194     LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
195     return result;
196   }
197
198   // playback position
199   double position;
200   result = Types::ConvertPlaybackPosition(playback_h, &position);
201   if (!result) {
202     LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
203     return result;
204   }
205
206   // content age rating
207   std::string rating;
208   result = Types::ConvertContentAgeRating(playback_h, &rating);
209   if (!result) {
210     LoggerE("ConvertContentAgeRating failed, error: %s", result.message().c_str());
211     return result;
212   }
213
214   // shuffle mode
215   mc_shuffle_mode_e shuffle;
216   ret = mc_client_get_server_shuffle_mode(handle_, server_name.c_str(), &shuffle);
217   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
218     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting shuffle mode",
219                               ("mc_client_get_server_shuffle_mode() error: %d, message: %s", ret,
220                                get_error_message(ret)));
221   }
222
223   // repeat mode
224   mc_repeat_mode_e repeat;
225   ret = mc_client_get_server_repeat_mode(handle_, server_name.c_str(), &repeat);
226   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
227     return LogAndCreateResult(
228         ErrorCode::UNKNOWN_ERR, "Error getting repeat mode",
229         ("mc_client_get_server_repeat_mode() error: %d, message: %s", ret, get_error_message(ret)));
230   }
231
232   // metadata
233   picojson::value metadata = picojson::value(picojson::object());
234   result = GetMetadata(server_name, &metadata.get<picojson::object>());
235   if (!result) {
236     return result;
237   }
238
239   // fill return object
240   (*playback_info)["state"] = picojson::value(state);
241   (*playback_info)["position"] = picojson::value(position);
242   (*playback_info)["ageRating"] = picojson::value(rating);
243   (*playback_info)["shuffleMode"] = picojson::value(shuffle == MC_SHUFFLE_MODE_ON);
244   (*playback_info)["repeatMode"] = picojson::value(repeat == MC_REPEAT_MODE_ON);
245   (*playback_info)["metadata"] = metadata;
246
247   return PlatformResult(ErrorCode::NO_ERROR);
248 }
249
250 PlatformResult MediaControllerClient::GetMetadata(const std::string& server_name,
251                                                   picojson::object* metadata) {
252   ScopeLogger();
253   int ret;
254
255   mc_metadata_h metadata_h = nullptr;
256   ret = mc_client_get_server_metadata(handle_, server_name.c_str(), &metadata_h);
257   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
258     return LogAndCreateResult(
259         ErrorCode::UNKNOWN_ERR, "Error getting server metadata",
260         ("mc_client_get_server_metadata() error: %d, message: %s", ret, get_error_message(ret)));
261   }
262
263   SCOPE_EXIT {
264     mc_metadata_destroy(metadata_h);
265   };
266
267   PlatformResult result = Types::ConvertMetadata(metadata_h, metadata);
268   if (!result) {
269     return result;
270   }
271
272   return PlatformResult(ErrorCode::NO_ERROR);
273 }
274
275 PlatformResult MediaControllerClient::SetServerStatusChangeListener(const JsonCallback& callback) {
276   ScopeLogger();
277
278   int ret = mc_client_set_server_updated_cb(handle_, OnServerStatusUpdate, this);
279   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
280     return LogAndCreateResult(
281         ErrorCode::UNKNOWN_ERR, "Unable to set server status listener",
282         ("mc_client_set_server_updated_cb() error: %d, message: %s", ret, get_error_message(ret)));
283   }
284
285   server_status_listener_ = callback;
286
287   return PlatformResult(ErrorCode::NO_ERROR);
288 }
289
290 PlatformResult MediaControllerClient::UnsetServerStatusChangeListener() {
291   ScopeLogger();
292   int ret = mc_client_unset_server_updated_cb(handle_);
293   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
294     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset server status listener",
295                               ("mc_client_unset_server_updated_cb() error: %d, message: %s", ret,
296                                get_error_message(ret)));
297   }
298   server_status_listener_ = nullptr;
299   return PlatformResult(ErrorCode::NO_ERROR);
300 }
301
302 void MediaControllerClient::OnServerStatusUpdate(const char* server_name, mc_server_state_e state,
303                                                  void* user_data) {
304   ScopeLogger();
305   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
306
307   // server state
308   std::string state_str;
309   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerServerState,
310                                                       static_cast<int>(state), &state_str);
311   if (!result) {
312     LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
313     return;
314   }
315
316   picojson::value data = picojson::value(picojson::object());
317   picojson::object& data_o = data.get<picojson::object>();
318
319   data_o["state"] = picojson::value(state_str);
320   data_o["name"] = picojson::value(server_name);
321
322   client->server_status_listener_(&data);
323 }
324
325 PlatformResult MediaControllerClient::SetPlaybackInfoListener(const JsonCallback& callback) {
326   ScopeLogger();
327   int failed_setter = 0;
328   SCOPE_EXIT {
329     // Lambda function used to clean all set listeners (in case of failure of
330     // SetPlaybackInfoListener method).
331     // The purpose of this lambda is to unset as many setters as we can in case of failure.
332
333     int (*unsetters[])(mc_client_h) = {
334         mc_client_unset_playback_updated_cb, mc_client_unset_shuffle_mode_updated_cb,
335         mc_client_unset_repeat_mode_updated_cb,
336         /*mc_client_unset_metadata_updated_cb the last unsetter will never be used*/};
337
338     // This loop is no-op in case of success.
339     for (int i = 0; i < failed_setter; ++i) {
340       auto ret = unsetters[i](handle_);
341       if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
342         LoggerE("Fail (%d) returned by the [%d] unsetter", ret, i);
343       }
344     }
345   };
346
347   int ret = mc_client_set_playback_updated_cb(handle_, OnPlaybackUpdate, this);
348   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
349     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register playback listener",
350                               ("mc_client_set_playback_updated_cb() error: %d, message: %s", ret,
351                                get_error_message(ret)));
352   }
353
354   ret = mc_client_set_shuffle_mode_updated_cb(handle_, OnShuffleModeUpdate, this);
355   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
356     failed_setter = 1;
357     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register shuffle mode listener",
358                               ("mc_client_set_shuffle_mode_updated_cb() error: %d, message: %s",
359                                ret, get_error_message(ret)));
360   }
361
362   ret = mc_client_set_repeat_mode_updated_cb(handle_, OnRepeatModeUpdate, this);
363   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
364     failed_setter = 2;
365     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register repeat mode listener",
366                               ("mc_client_set_repeat_mode_updated_cb() error: %d, message: %s", ret,
367                                get_error_message(ret)));
368   }
369
370   ret = mc_client_set_metadata_updated_cb(handle_, OnMetadataUpdate, this);
371   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
372     failed_setter = 3;
373     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to register metadata listener",
374                               ("mc_client_set_metadata_updated_cb() error: %d, message: %s", ret,
375                                get_error_message(ret)));
376   }
377
378   playback_info_listener_ = callback;
379
380   return PlatformResult(ErrorCode::NO_ERROR);
381 }
382
383 PlatformResult MediaControllerClient::UnsetPlaybackInfoListener() {
384   ScopeLogger();
385   // Even though if one of below functions fails, let's try to unset as much listeners as we can.
386   // In the Javascript layer, the removePlaybackInfoChangeListener() method always succeeds, so we
387   // do not need to catch the returned value.
388
389   mc_client_unset_playback_updated_cb(handle_);
390   mc_client_unset_shuffle_mode_updated_cb(handle_);
391   mc_client_unset_repeat_mode_updated_cb(handle_);
392   mc_client_unset_metadata_updated_cb(handle_);
393
394   playback_info_listener_ = nullptr;
395
396   return PlatformResult(ErrorCode::NO_ERROR);
397 }
398
399 void MediaControllerClient::OnPlaybackUpdate(const char* server_name, mc_playback_h playback,
400                                              void* user_data) {
401   ScopeLogger();
402   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
403
404   // playback state
405   std::string state;
406   PlatformResult result = Types::ConvertPlaybackState(playback, &state);
407   if (!result) {
408     LoggerE("ConvertPlaybackState failed, error: %s", result.message().c_str());
409     return;
410   }
411
412   // playback position
413   double position;
414   result = Types::ConvertPlaybackPosition(playback, &position);
415   if (!result) {
416     LoggerE("ConvertPlaybackPosition failed, error: %s", result.message().c_str());
417     return;
418   }
419
420   picojson::value data = picojson::value(picojson::object());
421   picojson::object& data_o = data.get<picojson::object>();
422
423   data_o["action"] = picojson::value(std::string("onplaybackchanged"));
424   data_o["state"] = picojson::value(state);
425   data_o["position"] = picojson::value(position);
426   data_o["name"] = picojson::value(server_name);
427
428   client->playback_info_listener_(&data);
429 }
430
431 void MediaControllerClient::OnShuffleModeUpdate(const char* server_name, mc_shuffle_mode_e mode,
432                                                 void* user_data) {
433   ScopeLogger();
434   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
435
436   picojson::value data = picojson::value(picojson::object());
437   picojson::object& data_o = data.get<picojson::object>();
438
439   data_o["action"] = picojson::value(std::string("onshufflemodechanged"));
440   data_o["mode"] = picojson::value(mode == MC_SHUFFLE_MODE_ON);
441   data_o["name"] = picojson::value(server_name);
442
443   client->playback_info_listener_(&data);
444 }
445
446 void MediaControllerClient::OnRepeatModeUpdate(const char* server_name, mc_repeat_mode_e mode,
447                                                void* user_data) {
448   ScopeLogger();
449   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
450
451   picojson::value data = picojson::value(picojson::object());
452   picojson::object& data_o = data.get<picojson::object>();
453
454   data_o["name"] = picojson::value(server_name);
455   if (MC_REPEAT_MODE_ONE_MEDIA != mode) {
456     // The onrepeatmodechanged event may be reported only with mode equal to true/false. The 3rd
457     // mode is not supported by this event.
458     common::tools::PrintDeprecationWarningFor("onrepeatmodechanged", "onrepeatstatechanged");
459     data_o["action"] = picojson::value(std::string("onrepeatmodechanged"));
460     data_o["mode"] = picojson::value(mode == MC_REPEAT_MODE_ON);
461     client->playback_info_listener_(&data);
462   }
463   std::string state{};
464   PlatformResult result = Types::PlatformEnumToString(Types::kMediaControllerRepeatState,
465                                                       static_cast<int>(mode), &state);
466   if (!result) {
467     LoggerE("PlatformEnumToString failed, error: %s", result.message().c_str());
468     return;
469   }
470   data_o["action"] = picojson::value(std::string("onrepeatstatechanged"));
471   data_o["state"] = picojson::value(state);
472
473   client->playback_info_listener_(&data);
474 }
475
476 void MediaControllerClient::OnMetadataUpdate(const char* server_name, mc_metadata_h metadata_h,
477                                              void* user_data) {
478   ScopeLogger();
479   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
480
481   picojson::value data = picojson::value(picojson::object());
482   picojson::object& data_o = data.get<picojson::object>();
483
484   picojson::value metadata = picojson::value(picojson::object());
485   PlatformResult result = Types::ConvertMetadata(metadata_h, &metadata.get<picojson::object>());
486   if (!result) {
487     LoggerE("ConvertMetadata failed, error: %s", result.message().c_str());
488     return;
489   }
490
491   data_o["action"] = picojson::value(std::string("onmetadatachanged"));
492   data_o["metadata"] = metadata;
493   data_o["name"] = picojson::value(server_name);
494
495   client->playback_info_listener_(&data);
496 }
497
498 PlatformResult MediaControllerClient::SendCommand(const std::string& server_name,
499                                                   const std::string& command,
500                                                   const picojson::value& data,
501                                                   const JsonCallback& reply_cb, char** request_id) {
502   ScopeLogger();
503   bundle* bundle = bundle_create();
504   SCOPE_EXIT {
505     bundle_free(bundle);
506   };
507
508   int ret;
509   ret = bundle_add(bundle, "data", data.serialize().c_str());
510   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
511     return LogAndCreateResult(
512         ErrorCode::UNKNOWN_ERR, "Unable to add data to bundle",
513         ("bundle_add(data) error: %d, message: %s", ret, get_error_message(ret)));
514   }
515
516   ret =
517       mc_client_send_custom_cmd(handle_, server_name.c_str(), command.c_str(), bundle, request_id);
518   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
519     return LogAndCreateResult(
520         ErrorCode::UNKNOWN_ERR, "Error sending custom command",
521         ("mc_client_send_custom_cmd() error: %d, message: %s", ret, get_error_message(ret)));
522   }
523
524   command_reply_callback_ = reply_cb;
525
526   return PlatformResult(ErrorCode::NO_ERROR);
527 }
528
529 void MediaControllerClient::OnCommandReply(const char* server_name, const char* request_id,
530                                            int result_code, bundle* bundle, void* user_data) {
531   ScopeLogger();
532   MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
533
534   picojson::value out = picojson::value(picojson::object());
535   picojson::object& out_o = out.get<picojson::object>();
536   picojson::value reply = picojson::value(picojson::object());
537   picojson::object& reply_o = reply.get<picojson::object>();
538
539   int ret;
540   char* data_str = nullptr;
541   SCOPE_EXIT {
542     free(data_str);
543   };
544
545   ret = bundle_get_str(bundle, "data", &data_str);
546   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
547     LoggerE("bundle_get_str(data) failed, error: %d", ret);
548     ReportError(out_o);
549     client->command_reply_callback_(&out);
550     return;
551   }
552
553   picojson::value data;
554   std::string err;
555   picojson::parse(data, data_str, data_str + strlen(data_str), &err);
556   if (!err.empty()) {
557     LoggerE("Failed to parse bundle data: %s", err.c_str());
558     ReportError(out_o);
559     client->command_reply_callback_(&out);
560     return;
561   }
562   reply_o["data"] = data;
563   reply_o["name"] = picojson::value(server_name);
564
565   if (nullptr == request_id) {
566     LoggerE("Request id is null.");
567     ReportError(out_o);
568     client->command_reply_callback_(&out);
569     return;
570   }
571   out_o["requestId"] = picojson::value(std::string(request_id));
572
573   ReportSuccess(reply, out_o);
574   client->command_reply_callback_(&out);
575 }
576
577 PlatformResult MediaControllerClient::SendPlaybackState(const std::string& server_name,
578                                                         const std::string& state) {
579   ScopeLogger();
580   int state_e;
581   // In Native API, since Tizen 5.0 an action instead of a state is sent to change the state of a
582   // server. In Web API the names were not refactored.
583   PlatformResult result =
584       Types::StringToPlatformEnum(Types::kMediaControllerPlaybackAction, state, &state_e);
585   if (!result) {
586     return result;
587   }
588
589   /* TODO: Prepare an ACR and propose use case for request_id.
590   char* request_id = nullptr;
591   SCOPE_EXIT {
592     free(request_id);
593   };*/
594   int ret;
595   ret = mc_client_send_playback_action_cmd(handle_, server_name.c_str(),
596                                            static_cast<mc_playback_action_e>(state_e),
597                                            /*&request_id*/ nullptr);
598   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
599     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error sending playback state",
600                               ("mc_client_send_playback_action_cmd() error: %d, message: %s", ret,
601                                get_error_message(ret)));
602   }
603
604   return PlatformResult(ErrorCode::NO_ERROR);
605 }
606
607 PlatformResult MediaControllerClient::SendPlaybackPosition(const std::string& server_name,
608                                                            double position) {
609   ScopeLogger();
610   /* TODO: Prepare an ACR and propose use case for request_id.
611   char* request_id = nullptr;
612   SCOPE_EXIT {
613     free(request_id);
614   };*/
615   int ret = mc_client_send_playback_position_cmd(handle_, server_name.c_str(),
616                                                  static_cast<unsigned long long>(position),
617                                                  /*&request_id*/ nullptr);
618   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
619     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error sending playback position",
620                               ("mc_client_send_playback_position_cmd() error: %d, message: %s", ret,
621                                get_error_message(ret)));
622   }
623
624   return PlatformResult(ErrorCode::NO_ERROR);
625 }
626
627 PlatformResult MediaControllerClient::SendShuffleMode(const std::string& server_name, bool mode) {
628   ScopeLogger();
629   /* TODO: Prepare an ACR and propose use case for request_id.
630   char* request_id = nullptr;
631   SCOPE_EXIT {
632     free(request_id);
633   };*/
634   int ret = mc_client_send_shuffle_mode_cmd(handle_, server_name.c_str(),
635                                             mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF,
636                                             /*&request_id*/ nullptr);
637   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
638     return LogAndCreateResult(
639         ErrorCode::UNKNOWN_ERR, "Error sending shuffle mode",
640         ("mc_client_send_shuffle_mode_cmd() error: %d, message: %s", ret, get_error_message(ret)));
641   }
642
643   return PlatformResult(ErrorCode::NO_ERROR);
644 }
645
646 PlatformResult MediaControllerClient::SendRepeatMode(const std::string& server_name, bool mode) {
647   ScopeLogger();
648   /* TODO: Prepare an ACR and propose use case for request_id.
649   char* request_id = nullptr;
650   SCOPE_EXIT {
651     free(request_id);
652   };*/
653   int ret = mc_client_send_repeat_mode_cmd(handle_, server_name.c_str(),
654                                            mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF,
655                                            /*&request_id*/ nullptr);
656   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
657     return LogAndCreateResult(
658         ErrorCode::UNKNOWN_ERR, "Error sending repeat mode",
659         ("mc_client_send_repeat_mode_cmd() error: %d, message: %s", ret, get_error_message(ret)));
660   }
661
662   return PlatformResult(ErrorCode::NO_ERROR);
663 }
664
665 PlatformResult MediaControllerClient::SendRepeatState(const std::string& server_name,
666                                                       const std::string& state) {
667   ScopeLogger();
668   /* TODO: Prepare an ACR and propose use case for request_id.
669   char* request_id = nullptr;
670   SCOPE_EXIT {
671     free(request_id);
672   };*/
673   int state_e;
674   PlatformResult result =
675       Types::StringToPlatformEnum(Types::kMediaControllerRepeatState, state, &state_e);
676   if (!result) {
677     return result;
678   }
679   int ret = mc_client_send_repeat_mode_cmd(handle_, server_name.c_str(),
680                                            static_cast<mc_repeat_mode_e>(state_e),
681                                            /*&request_id*/ nullptr);
682   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
683     return LogAndCreateResult(
684         ErrorCode::UNKNOWN_ERR, "Error sending repeat state",
685         ("mc_client_send_repeat_mode_cmd() error: %d, message: %s", ret, get_error_message(ret)));
686   }
687
688   return PlatformResult(ErrorCode::NO_ERROR);
689 }
690
691 PlatformResult MediaControllerClient::SendPlaybackItem(const std::string& name,
692                                                        const std::string& playlist_name,
693                                                        const std::string& index,
694                                                        const std::string& state, double position) {
695   ScopeLogger();
696
697   int state_e;
698   // In Native API, since Tizen 5.0 an action instead of a state is sent to change the state of a
699   // server. In Web API the names were not refactored.
700   PlatformResult result =
701       Types::StringToPlatformEnum(Types::kMediaControllerPlaybackAction, state, &state_e);
702
703   if (!result) {
704     return result;
705   }
706
707   int ret = mc_client_send_playlist_cmd(handle_, name.c_str(), playlist_name.c_str(), index.c_str(),
708                                         static_cast<mc_playback_action_e>(state_e),
709                                         static_cast<unsigned long long>(position), nullptr);
710
711   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
712     return LogAndCreateResult(
713         ErrorCode::UNKNOWN_ERR, "Error sending playlist item",
714         ("mc_client_send_playlist_cmd() error: %d, message: %s", ret, get_error_message(ret)));
715   }
716
717   return PlatformResult(ErrorCode::NO_ERROR);
718 }
719
720 }  // namespace mediacontroller
721 }  // namespace extension