[Content] Add listeners and events support
[platform/framework/web/tizen-extensions-crosswalk.git] / content / content_instance.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/content_instance.h"
6 #include "content/content_filter.h"
7
8 #include <media_content.h>
9 #include <media_filter.h>
10
11 #include <assert.h>
12
13 #include <iostream>
14 #include <fstream>
15 #include <string>
16 #include "common/picojson.h"
17
18 namespace {
19 const std::string STR_FILTER("filter");
20 const std::string STR_CONTENT_URI("contentURI");
21 const std::string STR_EVENT_TYPE("eventType");
22
23 std::string createUriFromLocalPath(const std::string path) {
24   static std::string fileScheme("file://");
25
26   return fileScheme + path;
27 }
28
29 std::string getUriPath(const std::string uri) {
30   static std::string fileScheme("file://");
31   std::string _fileScheme = uri.substr(0, fileScheme.size());
32
33   if (_fileScheme == fileScheme)
34     return uri.substr(fileScheme.size());
35   else
36     return "";
37 }
38 }  // namespace
39
40 unsigned ContentInstance::m_instanceCount = 0;
41
42 ContentInstance::ContentInstance() {
43   ++m_instanceCount;
44   if (media_content_connect() != MEDIA_CONTENT_ERROR_NONE) {
45     std::cerr << "media_content_connect: DB connection error" << std::endl;
46     return;
47   }
48 }
49
50 ContentInstance::~ContentInstance() {
51   assert(m_instanceCount > 0);
52   if (--m_instanceCount > 0)
53     return;
54   if (media_content_disconnect() != MEDIA_CONTENT_ERROR_NONE)
55     std::cerr << "media_discontent_connect: error\n";
56 }
57
58 void ContentInstance::HandleMessage(const char* message) {
59   picojson::value v;
60   picojson::value::object o;
61
62   std::string err;
63   picojson::parse(v, message, message + strlen(message), &err);
64   if (!err.empty()) {
65     std::cerr << "Ignoring message.\n";
66     return;
67   }
68 #ifdef DEBUG_JSON_CMD
69   std::cout << "HandleMessage: " << message << std::endl;
70 #endif
71   std::string cmd = v.get("cmd").to_str();
72   if (cmd == "ContentManager.getDirectories") {
73     HandleGetDirectoriesRequest(v);
74   } else if (cmd == "ContentManager.find") {
75     HandleFindRequest(v);
76   } else if (cmd == "ContentManager.scanFile") {
77     HandleScanFileRequest(v);
78   } else {
79     std::cerr << "Message " + cmd + " is not supported.\n";
80   }
81 }
82
83 void ContentInstance::PostAsyncErrorReply(const picojson::value& msg,
84     WebApiAPIErrors error_code) {
85   picojson::value::object o;
86   o["isError"] = picojson::value(true);
87   o["errorCode"] = picojson::value(static_cast<double>(error_code));
88   o["replyId"] = picojson::value(msg.get("replyId").get<double>());
89
90   picojson::value v(o);
91   PostMessage(v.serialize().c_str());
92 }
93
94 void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg,
95     picojson::value::object& reply) {
96   reply["isError"] = picojson::value(false);
97   reply["replyId"] = picojson::value(msg.get("replyId").get<double>());
98   if (msg.contains(STR_EVENT_TYPE))
99     reply[STR_EVENT_TYPE] = picojson::value(msg.get(STR_EVENT_TYPE));
100 #ifdef DEBUG_JSON_CMD
101   std::cout << "reply: " << msg.serialize().c_str() << std::endl;
102 #endif
103   picojson::value v(reply);
104   PostMessage(v.serialize().c_str());
105 }
106
107 void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg) {
108   picojson::value::object reply;
109   PostAsyncSuccessReply(msg, reply);
110 }
111
112 void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg,
113     picojson::value& value) {
114   picojson::value::object reply;
115   reply["value"] = value;
116   PostAsyncSuccessReply(msg, reply);
117 }
118
119 void ContentInstance::HandleSyncMessage(const char* message) {
120   picojson::value v;
121   picojson::value::object o;
122
123   std::string err;
124   picojson::parse(v, message, message + strlen(message), &err);
125   if (!err.empty()) {
126     std::cerr << "Ignoring message.\n";
127     return;
128   }
129 #ifdef DEBUG_JSON_CMD
130   std::cout << "HandleSyncMessage: " << message << std::endl;
131 #endif
132   std::string cmd = v.get("cmd").to_str();
133   int rc = MEDIA_CONTENT_ERROR_INVALID_OPERATION;
134
135   if (cmd == "ContentManager.setChangeListener") {
136     rc = media_content_set_db_updated_cb(MediaContentChangeCallback, this);
137   } else if (cmd == "ContentManager.unsetChangeListener") {
138     rc = media_content_unset_db_updated_cb();
139   } else {
140     std::cerr << "Message " + cmd + " is not supported.\n";
141   }
142
143   if (rc != MEDIA_CONTENT_ERROR_NONE)
144     std::cerr << "error " << cmd << std::endl;
145
146 #ifdef DEBUG_JSON_CMD
147   std::cout << "Reply: " << v.serialize().c_str() << std::endl;
148 #endif
149   SendSyncReply(v.serialize().c_str());
150 }
151
152 void ContentInstance::HandleGetDirectoriesRequest(const picojson::value& msg) {
153   ContentFolderList folderList;
154   if (media_folder_foreach_folder_from_db(NULL,
155           MediaFolderCallback,
156           reinterpret_cast<void*>(&folderList)) != MEDIA_CONTENT_ERROR_NONE) {
157     std::cerr << "media_folder_foreach_folder_from_db: error" << std::endl;
158   } else {
159     HandleGetDirectoriesReply(msg, &folderList);
160   }
161 }
162
163 void ContentInstance::HandleGetDirectoriesReply(const picojson::value& msg,
164     ContentFolderList* folderList) {
165   const std::vector<ContentFolder*>& results = folderList->getAllItems();
166   picojson::value::array folders;
167
168   for (unsigned i = 0; i < results.size(); i++) {
169     ContentFolder* folder = results[i];
170
171     picojson::value::object o;
172
173     o["id"] = picojson::value(folder->id());
174     o["directoryURI"] = picojson::value(folder->directoryURI());
175     o["title"] = picojson::value(folder->title());
176     o["storageType"] = picojson::value(folder->storageType());
177     o["modifiedDate"] = picojson::value(folder->modifiedDate());
178
179     folders.push_back(picojson::value(o));
180   }
181   picojson::value value(folders);
182   PostAsyncSuccessReply(msg, value);
183 }
184
185 bool ContentInstance::MediaFolderCallback(media_folder_h handle,
186     void* user_data) {
187   if (!user_data)
188     return false;
189
190   ContentFolderList* folderList =
191     reinterpret_cast<ContentFolderList*>(user_data);
192
193   ContentFolder* folder = new ContentFolder;
194   folder->init(handle);
195   folderList->addFolder(folder);
196 #ifdef DEBUG_ITEM
197   folder->print();
198 #endif
199   return true;
200 }
201
202 void ContentInstance::HandleFindRequest(const picojson::value& msg) {
203   ContentItemList itemList;
204   filter_h filterHandle = NULL;
205
206   ContentFilter& filter = ContentFilter::instance();
207   if (msg.contains(STR_FILTER)) {
208     picojson::value filterValue = msg.get(STR_FILTER);
209     if (!filterValue.is<picojson::null>() &&
210         filterValue.is<picojson::object>()) {
211       std::string condition = filter.convert(msg.get(STR_FILTER));
212       if (media_filter_create(&filterHandle) == MEDIA_CONTENT_ERROR_NONE)
213         media_filter_set_condition(filterHandle,
214             condition.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
215     }
216   }
217
218   if (media_info_foreach_media_from_db(filterHandle,
219       MediaInfoCallback,
220       reinterpret_cast<ContentFolderList*>(&itemList))
221       != MEDIA_CONTENT_ERROR_NONE) {
222     std::cerr << "media_info_foreach_media_from_db: error" << std::endl;
223   } else {
224     HandleFindReply(msg, &itemList);
225   }
226
227   if (filterHandle != NULL && media_filter_destroy(filterHandle)
228       != MEDIA_CONTENT_ERROR_NONE)
229     std::cerr << "media_filter_destroy failed" << std::endl;
230 }
231
232 void ContentInstance::HandleFindReply(
233     const picojson::value& msg,
234     ContentItemList* itemList) {
235   const std::vector<ContentItem*> &results = itemList->getAllItems();
236
237   picojson::value::array items;
238
239   for (unsigned i = 0; i < results.size(); i++) {
240     ContentItem* item = results[i];
241
242     picojson::value::object o;
243
244     o["id"] = picojson::value(item->id());
245     o["name"] = picojson::value(item->name());
246     o["type"] = picojson::value(item->type());
247     o["mimeType"] = picojson::value(item->mimeType());
248     o["title"] = picojson::value(item->title());
249     o["contentURI"] = picojson::value(item->contentURI());
250     picojson::value::array uris;
251     uris.push_back(picojson::value(item->thumbnailURIs()));
252     o["thumbnailURIs"] = picojson::value(uris);
253     o["releaseDate"] = picojson::value(item->releaseDate());
254     o["modifiedDate"] =
255       picojson::value(item->modifiedDate());
256     o["size"] = picojson::value(static_cast<double>(item->size()));
257     o["description"] = picojson::value(item->description());
258     o["rating"] = picojson::value(static_cast<double>(item->rating()));
259
260     if (item->type() == "AUDIO") {
261       o["album"] = picojson::value(item->album());
262       picojson::value::array genres;
263       genres.push_back(picojson::value(item->genres()));
264       o["genres"] = picojson::value(genres);
265       picojson::value::array artists;
266       artists.push_back(picojson::value(item->artists()));
267       o["artists"] = picojson::value(artists);
268       picojson::value::array composers;
269       composers.push_back(picojson::value(item->composer()));
270       o["composers"] = picojson::value(composers);
271       o["copyright"] = picojson::value(item->copyright());
272       o["bitrate"] = picojson::value(static_cast<double>(item->bitrate()));
273       o["trackNumber"] = picojson::value(
274           static_cast<double>(item->trackNumber()));
275       o["duration"] = picojson::value(static_cast<double>(item->duration()));
276     } else if (item->type() == "IMAGE") {
277       o["width"] = picojson::value(static_cast<double>(item->width()));
278       o["height"] = picojson::value(static_cast<double>(item->height()));
279       o["orientation"] = picojson::value(item->orientation());
280     } else if (item->type() == "VIDEO") {
281       o["album"] = picojson::value(item->album());
282       picojson::value::array artists;
283       artists.push_back(picojson::value(item->artists()));
284       o["artists"] = picojson::value(artists);
285       o["duration"] = picojson::value(static_cast<double>(item->duration()));
286       o["width"] = picojson::value(static_cast<double>(item->width()));
287       o["height"] = picojson::value(static_cast<double>(item->height()));
288     }
289
290     picojson::value v(o);
291
292     items.push_back(picojson::value(o));
293   }
294   picojson::value value(items);
295 #ifdef DEBUG_JSON_REPLY
296   std::cout << "JSON reply: " << std::endl <<
297      value.serialize().c_str() << std::endl;
298 #endif
299   PostAsyncSuccessReply(msg, value);
300 }
301
302 bool ContentInstance::MediaInfoCallback(media_info_h handle, void* user_data) {
303   if (!user_data)
304     return false;
305
306   ContentItemList* itemList = reinterpret_cast<ContentItemList*>(user_data);
307
308   ContentItem* item = new ContentItem;
309   item->init(handle);
310   itemList->addItem(item);
311 #ifdef DEBUG_ITEM
312   item->print();
313 #endif
314   return true;
315 }
316
317 void ContentInstance::MediaContentChangeCallback(
318     media_content_error_e error,
319     int pid,
320     media_content_db_update_item_type_e update_item,
321     media_content_db_update_type_e update_type,
322     media_content_type_e media_type,
323     char* uuid,
324     char* path,
325     char* mime_type,
326     void* user_data) {
327 #ifdef DEBUG_ITEM
328   std::cout << "MediaContentChangeCallback: error=" << error <<
329       ", item=" << update_item << ", type=" << update_type << ", " <<
330       uuid << ", " << path << std::endl;
331 #endif
332   if (!user_data)
333     return;
334
335   ContentInstance* self =
336       reinterpret_cast<ContentInstance*>(user_data);
337
338   picojson::value::object om;
339   om["replyId"] = picojson::value(static_cast<double>(0));
340   const std::string type = (update_type == MEDIA_CONTENT_INSERT ?
341       "INSERT" : (update_type == MEDIA_CONTENT_DELETE ? "DELETE" : "UPDATE"));
342   om[STR_EVENT_TYPE] = picojson::value(type);
343   picojson::value::object ov;
344   ov["type"] = picojson::value(static_cast<double>(media_type));
345
346   if (uuid)
347     ov["id"] = picojson::value(uuid);
348
349   if (path)
350     ov["contentURI"] = picojson::value(path);
351
352   if (mime_type)
353     ov["mimeType"] = picojson::value(mime_type);
354
355   picojson::value msg(om);
356   picojson::value value(ov);
357 #ifdef DEBUG_JSON_REPLY
358   std::cout << "JSON event msg: " << msg.serialize().c_str() << std::endl;
359   std::cout << "JSON event val: " << value.serialize().c_str() << std::endl;
360 #endif
361
362   self->PostAsyncSuccessReply(msg, value);
363 }
364
365 void ContentFolder::init(media_folder_h handle) {
366   char* str = NULL;
367   time_t date;
368   media_content_storage_e storageType;
369
370   if (media_folder_get_folder_id(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
371     setID(str);
372     free(str);
373   }
374
375   if (media_folder_get_path(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
376     setDirectoryURI(createUriFromLocalPath(str));
377     free(str);
378   }
379
380   if (media_folder_get_name(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
381     setTitle(str);
382     free(str);
383   }
384
385   if (media_folder_get_storage_type(
386       handle, &storageType) == MEDIA_CONTENT_ERROR_NONE) {
387     std::string type;
388     if (storageType == MEDIA_CONTENT_STORAGE_INTERNAL) {
389       type = "INTERNAL";
390     } else if (storageType == MEDIA_CONTENT_STORAGE_EXTERNAL) {
391       type = "EXTERNAL";
392     } else {
393       type = "UNKNOWN";
394     }
395     setStorageType(type);
396   }
397
398   if (media_folder_get_modified_time(
399       handle, &date) == MEDIA_CONTENT_ERROR_NONE) {
400     char tmp[26];
401     ctime_r(&date, tmp);
402     setModifiedDate(tmp);
403   }
404 }
405
406 #ifdef DEBUG_ITEM
407 void ContentFolder::print(void) {
408   std::cout << "ID: " << id() << std::endl;
409   std::cout << "URI: " << directoryURI() << std::endl;
410   std::cout << "Title: " << title() << std::endl;
411   std::cout << "Type: " << storageType() << std::endl;
412   std::cout << "Date: " << modifiedDate() << std::endl;
413 }
414 #endif
415
416 void ContentItem::init(media_info_h handle) {
417   char* pc = NULL;
418
419   // NOTE: the Tizen CAPI media_info_* functions assumes
420   // the caller frees the char**. The CAPI can also return NULL char**
421   // even the return code is MEDIA_CONTENT_ERROR_NONE.
422
423   if (media_info_get_media_id(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
424     setID(pc);
425     free(pc);
426   }
427
428   if (media_info_get_mime_type(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
429     setMimeType(pc);
430     free(pc);
431   }
432
433   if (media_info_get_title(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
434     setTitle(pc);
435     free(pc);
436   }
437
438   if (media_info_get_display_name(handle,
439       &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
440     setName(pc);
441     free(pc);
442   }
443
444   if (media_info_get_file_path(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
445     setContentURI(createUriFromLocalPath(pc));
446     free(pc);
447   }
448
449   if (media_info_get_thumbnail_path(handle,
450       &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
451     setThumbnailURIs(createUriFromLocalPath(pc));
452     free(pc);
453   }
454
455   if (media_info_get_description(handle,
456       &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
457     setDescription(pc);
458     free(pc);
459   }
460
461   time_t date;
462   if (media_info_get_modified_time(handle, &date) == MEDIA_CONTENT_ERROR_NONE) {
463     char tmp[26];
464     ctime_r(&date, tmp);
465     setModifiedDate(tmp);
466   }
467
468   int i = 0;
469   if (media_info_get_rating(handle, &i) == MEDIA_CONTENT_ERROR_NONE)
470     setRating(i);
471
472   unsigned long long ll; // NOLINT
473   if (media_info_get_size(handle, &ll) == MEDIA_CONTENT_ERROR_NONE)
474     setSize(ll);
475
476   media_content_type_e type;
477   if (media_info_get_media_type(handle, &type) == MEDIA_CONTENT_ERROR_NONE) {
478     if (type == MEDIA_CONTENT_TYPE_IMAGE) {
479       setType("IMAGE");
480
481       image_meta_h image;
482       if (media_info_get_image(handle, &image) == MEDIA_CONTENT_ERROR_NONE) {
483         if (image_meta_get_width(image, &i) == MEDIA_CONTENT_ERROR_NONE)
484           setWidth(i);
485
486         if (image_meta_get_height(image, &i) == MEDIA_CONTENT_ERROR_NONE)
487           setHeight(i);
488
489         // TODO(spoussa): coordinates do not return sensible values...
490         double d;
491         if (media_info_get_latitude(handle, &d) == MEDIA_CONTENT_ERROR_NONE)
492           setLatitude(d);
493
494        if (media_info_get_longitude(handle, &d) == MEDIA_CONTENT_ERROR_NONE)
495           setLongitude(d);
496
497         media_content_orientation_e orientation;
498         if (image_meta_get_orientation(image, &orientation)
499             == MEDIA_CONTENT_ERROR_NONE) {
500           std::string result("");
501
502           switch (orientation) {
503             case 0:
504             case 1: result = "NORMAL"; break;
505             case 2: result = "FLIP_HORIZONTAL"; break;
506             case 3: result = "ROTATE_180"; break;
507             case 4: result = "FLIP_VERTICAL"; break;
508             case 5: result = "TRANSPOSE"; break;
509             case 6: result = "ROTATE_90"; break;
510             case 7: result = "TRANSVERSE"; break;
511             case 8: result = "ROTATE_270"; break;
512             default: result = "Unknown"; break;
513           }
514           setOrientation(result);
515         }
516         image_meta_destroy(image);
517       }
518     } else if (type == MEDIA_CONTENT_TYPE_VIDEO) {
519       setType("VIDEO");
520
521       video_meta_h video;
522       if (media_info_get_video(handle, &video) == MEDIA_CONTENT_ERROR_NONE) {
523         if (video_meta_get_recorded_date(video,
524             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
525           setReleaseDate(pc);
526           free(pc);
527         }
528
529         if (video_meta_get_album(video,
530             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
531           setAlbum(pc);
532           free(pc);
533         }
534
535         if (video_meta_get_artist(video,
536             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
537           setArtists(pc);
538           free(pc);
539         }
540
541         if (video_meta_get_width(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
542           setWidth(i);
543         }
544
545         if (video_meta_get_height(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
546           setHeight(i);
547         }
548
549         if (video_meta_get_duration(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
550           setDuration(i);
551         }
552
553         video_meta_destroy(video);
554       }
555     } else if (type == MEDIA_CONTENT_TYPE_MUSIC) {
556       setType("AUDIO");
557
558       audio_meta_h audio;
559       if (media_info_get_audio(handle, &audio) == MEDIA_CONTENT_ERROR_NONE) {
560         if (audio_meta_get_recorded_date(audio,
561             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
562           setReleaseDate(pc);
563           free(pc);
564         }
565
566         if (audio_meta_get_album(audio,
567             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
568           setAlbum(pc);
569           free(pc);
570         }
571
572         if (audio_meta_get_artist(audio,
573             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
574           setArtists(pc);
575           free(pc);
576         }
577
578         if (audio_meta_get_composer(audio,
579             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
580           setComposer(pc);
581           free(pc);
582         }
583
584         if (audio_meta_get_duration(audio, &i) == MEDIA_CONTENT_ERROR_NONE)
585           setDuration(i);
586
587         if (audio_meta_get_copyright(audio,
588             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
589           setCopyright(pc);
590           free(pc);
591         }
592
593         if (audio_meta_get_track_num(audio,
594             &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
595           i = atoi(pc);
596           setTrackNumber(i);
597           free(pc);
598         }
599
600         if (audio_meta_get_bit_rate(audio, &i) == MEDIA_CONTENT_ERROR_NONE)
601           setBitrate(i);
602       }
603       audio_meta_destroy(audio);
604     } else if (type == MEDIA_CONTENT_TYPE_OTHERS) {
605       setType("OTHER");
606     }
607   }
608 }
609
610 #ifdef DEBUG_ITEM
611 void ContentItem::print(void) {
612   std::cout << "----" << std::endl;
613   std::cout << "ID: " << id() << std::endl;
614   std::cout << "Name: " << name() << std::endl;
615   std::cout << "Type: " << type() << std::endl;
616   std::cout << "MIME: " << mimeType() << std::endl;
617   std::cout << "Title: " << title() << std::endl;
618   std::cout << "URI: " << contentURI() << std::endl;
619   std::cout << "ThumbnailURIs: " << thumbnailURIs() << std::endl;
620   std::cout << "Modified: " << modifiedDate();
621   std::cout << "Size: " << size() << std::endl;
622   std::cout << "Description: " << description() << std::endl;
623   std::cout << "Rating: " << rating() << std::endl;
624   if (type() == "AUDIO") {
625     std::cout << "Release Date: " << releaseDate() << std::endl;
626     std::cout << "Album: " << album() << std::endl;
627     std::cout << "Genres: " << genres() << std::endl;
628     std::cout << "Artists: " << artists() << std::endl;
629     std::cout << "Composer: " << composer() << std::endl;
630     std::cout << "Copyright: " << copyright() << std::endl;
631     std::cout << "Bitrate: " << bitrate() << std::endl;
632     std::cout << "Track num: " << trackNumber() << std::endl;
633     std::cout << "Duration: " << duration() << std::endl;
634   } else if (type() == "IMAGE") {
635     std::cout << "Width/Height: " << width() << "/" << height() << std::endl;
636     std::cout << "Latitude: " << latitude() << std::endl;
637     std::cout << "Longitude: " << longitude() << std::endl;
638     std::cout << "Orientation: " << orientation() << std::endl;
639   } else if (type() == "VIDEO") {
640     std::cout << "Album: " << album() << std::endl;
641     std::cout << "Artists: " << artists() << std::endl;
642     std::cout << "Duration: " << duration() << std::endl;
643     std::cout << "Width/Height: " << width() << "/" << height() << std::endl;
644   }
645 }
646 #endif
647
648 void ContentInstance::HandleScanFileRequest(const picojson::value& msg) {
649   if (msg.contains(STR_CONTENT_URI)) {
650     picojson::value uriValue = msg.get(STR_CONTENT_URI);
651     if (!uriValue.is<picojson::null>()) {
652       std::string uri = uriValue.to_str();
653       std::string path = getUriPath(uri);
654       if (path.empty())
655         path = uri;
656       int result = media_content_scan_file(path.c_str());
657       if (result == MEDIA_CONTENT_ERROR_NONE) {
658         HandleScanFileReply(msg);
659       } else {
660         std::cerr << "media_content_scan_file error:" << result << std::endl;
661         PostAsyncErrorReply(msg, WebApiAPIErrors::DATABASE_ERR);
662       }
663     }
664   }
665 }
666
667 void ContentInstance::HandleScanFileReply(const picojson::value& msg) {
668   PostAsyncSuccessReply(msg);
669 }