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