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