[MediaController] Add locks for variable used in different threads
[platform/core/api/webapi-plugins.git] / src / mediacontroller / mediacontroller_server.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_server.h"
18
19 #include <bundle.h>
20 #include <bundle_internal.h>
21
22 #include "common/logger.h"
23 #include "common/scope_exit.h"
24
25 #include "mediacontroller/mediacontroller_types.h"
26
27 namespace extension {
28 namespace mediacontroller {
29
30 using common::PlatformResult;
31 using common::ErrorCode;
32
33 MediaControllerServer::MediaControllerServer()
34     : handle_(nullptr),
35       playback_state_(MC_PLAYBACK_STATE_STOPPED),
36       position_(0ULL),
37       shuffle_mode_(MC_SHUFFLE_MODE_OFF),
38       repeat_mode_(MC_REPEAT_MODE_OFF),
39       is_shuffle_mode_set_(false),
40       is_repeat_mode_set_(false) {
41   ScopeLogger();
42 }
43
44 MediaControllerServer::~MediaControllerServer() {
45   ScopeLogger();
46
47   if (nullptr != change_request_playback_info_listener_ &&
48       !UnsetChangeRequestPlaybackInfoListener()) {
49     LoggerE("Failed to unset change request playback info listener");
50   }
51
52   if (nullptr != command_listener_ && !UnsetCommandListener()) {
53     LoggerE("Failed to unset command listener");
54   }
55
56   if (nullptr != handle_ && MEDIA_CONTROLLER_ERROR_NONE != mc_server_destroy(handle_)) {
57     LoggerE("Unable to destroy media controller server");
58   }
59   handle_ = nullptr;
60 }
61
62 PlatformResult MediaControllerServer::Init() {
63   ScopeLogger();
64
65   int ret = mc_server_create(&handle_);
66   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
67     return LogAndCreateResult(
68         ErrorCode::UNKNOWN_ERR, "Unable to create media controller server",
69         ("mc_server_create() error: %d, message: %s", ret, get_error_message(ret)));
70   }
71
72   return PlatformResult(ErrorCode::NO_ERROR);
73 }
74
75 PlatformResult MediaControllerServer::SetPlaybackState(const std::string& state) {
76   ScopeLogger();
77
78   mc_playback_states_e state_e;
79   PlatformResult result = types::MediaControllerPlaybackStateEnum.getValue(state, &state_e);
80   if (!result) {
81     return result;
82   }
83
84   if (state_e == playback_state_) {
85     LoggerD("No change in playback state requested, skipping");
86     return PlatformResult(ErrorCode::NO_ERROR);
87   }
88
89   int ret = mc_server_set_playback_state(handle_, state_e);
90   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
91     return LogAndCreateResult(
92         ErrorCode::UNKNOWN_ERR, "Error setting playback state",
93         ("mc_server_set_playback_state() error: %d, message: %s", ret, get_error_message(ret)));
94   }
95
96   playback_state_ = state_e;
97
98   ret = mc_server_update_playback_info(handle_);
99   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
100     return LogAndCreateResult(
101         ErrorCode::UNKNOWN_ERR, "Error updating playback info",
102         ("mc_server_update_playback_info() error: %d, message: %s", ret, get_error_message(ret)));
103   }
104
105   return PlatformResult(ErrorCode::NO_ERROR);
106 }
107
108 PlatformResult MediaControllerServer::SetPlaybackPosition(double position) {
109   ScopeLogger();
110
111   if (static_cast<unsigned long long>(position) == position_) {
112     LoggerD("No change in playback position requested, skipping");
113     return PlatformResult(ErrorCode::NO_ERROR);
114   }
115
116   int ret = mc_server_set_playback_position(handle_, static_cast<unsigned long long>(position));
117   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
118     return LogAndCreateResult(
119         ErrorCode::UNKNOWN_ERR, "Error setting playback position",
120         ("mc_server_set_playback_position() error: %d, message: %s", ret, get_error_message(ret)));
121   }
122
123   position_ = static_cast<unsigned long long>(position);
124
125   ret = mc_server_update_playback_info(handle_);
126   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
127     return LogAndCreateResult(
128         ErrorCode::UNKNOWN_ERR, "Error updating playback info",
129         ("mc_server_update_playback_info() error: %d, message: %s", ret, get_error_message(ret)));
130   }
131
132   return PlatformResult(ErrorCode::NO_ERROR);
133 }
134
135 PlatformResult MediaControllerServer::SetShuffleMode(bool mode) {
136   ScopeLogger();
137
138   mc_shuffle_mode_e shuffle_mode = mode ? MC_SHUFFLE_MODE_ON : MC_SHUFFLE_MODE_OFF;
139   if ((shuffle_mode == shuffle_mode_) && (is_shuffle_mode_set_)) {
140     LoggerD("No change in shuffle mode requested, skipping");
141     return PlatformResult(ErrorCode::NO_ERROR);
142   }
143
144   int ret = mc_server_update_shuffle_mode(handle_, shuffle_mode);
145   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
146     return LogAndCreateResult(
147         ErrorCode::UNKNOWN_ERR, "Error updating shuffle mode",
148         ("mc_server_update_shuffle_mode() error: %d, message: %s", ret, get_error_message(ret)));
149   }
150
151   shuffle_mode_ = shuffle_mode;
152   is_shuffle_mode_set_ = true;
153
154   return PlatformResult(ErrorCode::NO_ERROR);
155 }
156
157 PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
158   ScopeLogger();
159
160   mc_repeat_mode_e repeat_mode = mode ? MC_REPEAT_MODE_ON : MC_REPEAT_MODE_OFF;
161   if ((repeat_mode == repeat_mode_) && (is_repeat_mode_set_)) {
162     LoggerD("No change in repeat mode requested, skipping");
163     return PlatformResult(ErrorCode::NO_ERROR);
164   }
165
166   int ret = mc_server_update_repeat_mode(handle_, repeat_mode);
167   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
168     return LogAndCreateResult(
169         ErrorCode::UNKNOWN_ERR, "Error updating repeat mode",
170         ("mc_server_update_repeat_mode() error: %d, message: %s", ret, get_error_message(ret)));
171   }
172
173   repeat_mode_ = repeat_mode;
174   is_repeat_mode_set_ = true;
175
176   return PlatformResult(ErrorCode::NO_ERROR);
177 }
178
179 PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metadata) {
180   ScopeLogger();
181
182   for (picojson::object::const_iterator i = metadata.begin(); i != metadata.end(); ++i) {
183     mc_meta_e attr_e;
184     PlatformResult result = types::MediaControllerMetadataAttributeEnum.getValue(i->first, &attr_e);
185     if (!result) {
186       return result;
187     }
188
189     int ret = mc_server_set_metadata(handle_, attr_e, i->second.to_str().c_str());
190     if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
191       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error setting metadata",
192                                 ("mc_server_set_metadata(%s) error: %d, message: %s",
193                                  i->first.c_str(), ret, get_error_message(ret)));
194     }
195   }
196
197   int ret = mc_server_update_metadata(handle_);
198   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
199     return LogAndCreateResult(
200         ErrorCode::UNKNOWN_ERR, "Error updating metadata",
201         ("mc_server_update_metadata() error: %d, message: %s", ret, get_error_message(ret)));
202   }
203
204   return PlatformResult(ErrorCode::NO_ERROR);
205 }
206
207 void MediaControllerServer::OnCommandReceived(const char* client_name, const char* request_id,
208                                               const char* command, bundle* bundle,
209                                               void* user_data) {
210   ScopeLogger();
211
212   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
213
214   int ret;
215   char* data_str = nullptr;
216   SCOPE_EXIT {
217     free(data_str);
218   };
219   picojson::value data;
220
221   ret = bundle_get_str(bundle, "data", &data_str);
222   if (BUNDLE_ERROR_NONE != ret || nullptr == data_str) {
223     LoggerE("bundle_get_str(data) failed, error: %d", ret);
224   } else {
225     std::string err;
226     picojson::parse(data, data_str, data_str + strlen(data_str), &err);
227     if (!err.empty()) {
228       LoggerE("Failed to parse bundle data: %s", err.c_str());
229       return;
230     }
231   }
232
233   picojson::value request = picojson::value(picojson::object());
234   picojson::object& request_o = request.get<picojson::object>();
235
236   request_o["clientName"] = picojson::value(std::string(client_name));
237   request_o["command"] = picojson::value(std::string(command));
238   request_o["requestId"] = picojson::value(std::string(request_id));
239   request_o["data"] = data;
240
241   server->command_listener_(&request);
242 }
243
244 PlatformResult MediaControllerServer::CommandReply(const std::string& client_name,
245                                                    const std::string& request_id,
246                                                    const picojson::value& data) {
247   ScopeLogger();
248
249   int ret;
250
251   bundle* bundle = bundle_create();
252   SCOPE_EXIT {
253     bundle_free(bundle);
254   };
255
256   ret = bundle_add(bundle, "data", data.serialize().c_str());
257   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
258     return LogAndCreateResult(
259         ErrorCode::UNKNOWN_ERR, "Unable to add data to bundle",
260         ("bundle_add(data) error: %d, message: %s", ret, get_error_message(ret)));
261   }
262
263   ret = mc_server_send_cmd_reply(handle_, client_name.c_str(), request_id.c_str(), 0, bundle);
264   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
265     return LogAndCreateResult(
266         ErrorCode::UNKNOWN_ERR, "Error sending command reply",
267         ("mc_server_send_cmd_reply() error: %d, message: %s", ret, get_error_message(ret)));
268   }
269
270   return PlatformResult(ErrorCode::NO_ERROR);
271 }
272
273 PlatformResult MediaControllerServer::SetCommandListener(const JsonCallback& callback) {
274   ScopeLogger();
275
276   int ret = mc_server_set_custom_cmd_received_cb(handle_, OnCommandReceived, this);
277   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
278     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set command callback",
279                               ("mc_server_set_custom_cmd_received_cb() error: %d, message: %s", ret,
280                                get_error_message(ret)));
281   }
282   command_listener_ = callback;
283
284   return PlatformResult(ErrorCode::NO_ERROR);
285 }
286
287 PlatformResult MediaControllerServer::UnsetCommandListener() {
288   ScopeLogger();
289
290   int ret = mc_server_unset_custom_cmd_received_cb(handle_);
291   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
292     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset command callback",
293                               ("mc_server_unset_custom_cmd_received_cb() error: %d, message: %s",
294                                ret, get_error_message(ret)));
295   }
296   command_listener_ = nullptr;
297
298   return PlatformResult(ErrorCode::NO_ERROR);
299 }
300
301 PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
302     const JsonCallback& callback) {
303   ScopeLogger();
304   int failed_setter = 0;
305   SCOPE_EXIT {
306     // Lambda function used to clean all set listeners (in case of failure of
307     // SetPlaybackInfoListener method).
308     // The purpose of this lambda is to unset as many setters as we can in case of failure.
309
310     int (*unsetters[])(mc_server_h) = {
311         mc_server_unset_playback_action_cmd_received_cb,
312         mc_server_unset_playback_position_cmd_received_cb,
313         mc_server_unset_shuffle_mode_cmd_received_cb,
314         /*mc_server_unset_repeat_mode_cmd_received_cb the last unsetter will never be used*/};
315
316     // This loop is no-op in case of success.
317     for (int i = 0; i < failed_setter; ++i) {
318       auto ret = unsetters[i](handle_);
319       if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
320         LoggerE("Fail (%d) returned by the [%d] unsetter", ret, i);
321       }
322     }
323   };
324
325   // In Native API, since Tizen 5.0 an action instead of a state is sent to change the state of a
326   // server. In Web API the names were not refactored.
327   int ret = mc_server_set_playback_action_cmd_received_cb(handle_, OnPlaybackActionCommand, this);
328   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
329     return LogAndCreateResult(
330         ErrorCode::UNKNOWN_ERR, "Unable to set playback state command listener",
331         ("mc_server_set_playback_action_cmd_received_cb() error: %d, message: %s", ret,
332          get_error_message(ret)));
333   }
334
335   ret = mc_server_set_playback_position_cmd_received_cb(handle_, OnPlaybackPositionCommand, this);
336   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
337     failed_setter = 1;
338     return LogAndCreateResult(
339         ErrorCode::UNKNOWN_ERR, "Unable to set playback position command listener",
340         ("mc_server_set_playback_position_cmd_received_cb() error: %d, message: %s", ret,
341          get_error_message(ret)));
342   }
343
344   ret = mc_server_set_shuffle_mode_cmd_received_cb(handle_, OnShuffleModeCommand, this);
345   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
346     failed_setter = 2;
347     return LogAndCreateResult(
348         ErrorCode::UNKNOWN_ERR, "Unable to set shuffle mode command listener",
349         ("mc_server_set_shuffle_mode_cmd_received_cb() error: %d, message: %s", ret,
350          get_error_message(ret)));
351   }
352
353   ret = mc_server_set_repeat_mode_cmd_received_cb(handle_, OnRepeatModeCommand, this);
354   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
355     failed_setter = 3;
356     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set repeat mode command listener",
357                               ("mc_server_set_repeat_mode_cmd_received_cb() error: %d, message: %s",
358                                ret, get_error_message(ret)));
359   }
360
361   change_request_playback_info_listener_ = callback;
362
363   return PlatformResult(ErrorCode::NO_ERROR);
364 }
365
366 PlatformResult MediaControllerServer::UnsetChangeRequestPlaybackInfoListener() {
367   ScopeLogger();
368
369   int ret = mc_server_unset_playback_action_cmd_received_cb(handle_);
370   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
371     return LogAndCreateResult(
372         ErrorCode::UNKNOWN_ERR, "Unable to unset playback state command listener",
373         ("mc_server_unset_playback_action_cmd_received_cb() error: %d, message: %s", ret,
374          get_error_message(ret)));
375   }
376
377   ret = mc_server_unset_playback_position_cmd_received_cb(handle_);
378   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
379     return LogAndCreateResult(
380         ErrorCode::UNKNOWN_ERR, "Unable to unset playback position command listener",
381         ("mc_server_unset_playback_position_cmd_received_cb() error: %d, message: %s", ret,
382          get_error_message(ret)));
383   }
384
385   ret = mc_server_unset_shuffle_mode_cmd_received_cb(handle_);
386   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
387     return LogAndCreateResult(
388         ErrorCode::UNKNOWN_ERR, "Unable to unset shuffle mode command listener",
389         ("mc_server_unset_shuffle_mode_cmd_received_cb() error: %d, message: %s", ret,
390          get_error_message(ret)));
391   }
392
393   ret = mc_server_unset_repeat_mode_cmd_received_cb(handle_);
394   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
395     return LogAndCreateResult(
396         ErrorCode::UNKNOWN_ERR, "Unable to unset repeat mode command listener",
397         ("mc_server_unset_repeat_mode_cmd_received_cb() error: %d, message: %s", ret,
398          get_error_message(ret)));
399   }
400
401   change_request_playback_info_listener_ = nullptr;
402
403   return PlatformResult(ErrorCode::NO_ERROR);
404 }
405
406 void MediaControllerServer::OnPlaybackActionCommand(const char* client_name, const char* request_id,
407                                                     mc_playback_action_e action, void* user_data) {
408   ScopeLogger();
409
410   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
411
412   // Here, we need to convert mc_playback_action_e enum to mc_playback_states_e enum.
413   std::string action_str;
414   PlatformResult result = types::MediaControllerPlaybackActionEnum.getName(action, &action_str);
415   if (!result) {
416     LoggerW("MediaControllerPlaybackActionEnum.getName() failed, error: %s",
417             result.message().c_str());
418     return;
419   }
420
421   mc_playback_states_e state_e;
422   result = types::MediaControllerPlaybackStateEnum.getValue(action_str, &state_e);
423   if (!result) {
424     LoggerE("MediaControllerPlaybackStateEnum.getValue() failed, error: %s",
425             result.message().c_str());
426     return;
427   }
428
429   if (server->playback_state_ == state_e) {
430     LoggerD("The media playback state did not change, skipping");
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("onplaybackstaterequest"));
438   data_o["state"] = picojson::value(action_str);
439
440   server->change_request_playback_info_listener_(&data);
441 }
442
443 void MediaControllerServer::OnPlaybackPositionCommand(const char* client_name,
444                                                       const char* request_id,
445                                                       unsigned long long position,
446                                                       void* user_data) {
447   ScopeLogger();
448
449   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
450
451   if (server->position_ == position) {
452     LoggerD("The position did not change, skipping");
453     return;
454   }
455
456   picojson::value data = picojson::value(picojson::object());
457   picojson::object& data_o = data.get<picojson::object>();
458
459   data_o["action"] = picojson::value(std::string("onplaybackpositionrequest"));
460   data_o["position"] = picojson::value(static_cast<double>(position));
461
462   server->change_request_playback_info_listener_(&data);
463 }
464
465 void MediaControllerServer::OnShuffleModeCommand(const char* client_name, const char* request_id,
466                                                  mc_shuffle_mode_e mode, void* user_data) {
467   ScopeLogger();
468
469   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
470
471   if (server->shuffle_mode_ == mode) {
472     LoggerD("The shuffle mode did not change, skipping");
473     return;
474   }
475
476   picojson::value data = picojson::value(picojson::object());
477   picojson::object& data_o = data.get<picojson::object>();
478
479   data_o["action"] = picojson::value(std::string("onshufflemoderequest"));
480   data_o["mode"] = picojson::value(mode == MC_SHUFFLE_MODE_ON);
481
482   server->change_request_playback_info_listener_(&data);
483 }
484
485 void MediaControllerServer::OnRepeatModeCommand(const char* client_name, const char* request_id,
486                                                 mc_repeat_mode_e mode, void* user_data) {
487   ScopeLogger();
488
489   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
490
491   if (server->repeat_mode_ == mode) {
492     LoggerD("The repeat mode did not change, skipping");
493     return;
494   }
495
496   picojson::value data = picojson::value(picojson::object());
497   picojson::object& data_o = data.get<picojson::object>();
498
499   data_o["action"] = picojson::value(std::string("onrepeatmoderequest"));
500   data_o["mode"] = picojson::value(mode == MC_REPEAT_MODE_ON);
501
502   server->change_request_playback_info_listener_(&data);
503 }
504
505 }  // namespace mediacontroller
506 }  // namespace extension