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.
5 #include "content/content_instance.h"
6 #include "content/content_filter.h"
8 #include <media_content.h>
9 #include <media_filter.h>
16 #include "common/picojson.h"
19 const std::string STR_FILTER("filter");
20 const std::string STR_CONTENT_URI("contentURI");
22 std::string createUriFromLocalPath(const std::string path) {
23 static std::string fileScheme("file://");
25 return fileScheme + path;
28 std::string getUriPath(const std::string uri) {
29 static std::string fileScheme("file://");
30 std::string _fileScheme = uri.substr(0, fileScheme.size());
32 if (_fileScheme == fileScheme)
33 return uri.substr(fileScheme.size());
39 unsigned ContentInstance::m_instanceCount = 0;
41 ContentInstance::ContentInstance() {
43 if (media_content_connect() != MEDIA_CONTENT_ERROR_NONE) {
44 std::cerr << "media_content_connect: DB connection error" << std::endl;
49 ContentInstance::~ContentInstance() {
50 assert(m_instanceCount > 0);
51 if (--m_instanceCount > 0)
53 if (media_content_disconnect() != MEDIA_CONTENT_ERROR_NONE)
54 std::cerr << "media_discontent_connect: error\n";
57 void ContentInstance::HandleMessage(const char* message) {
59 picojson::value::object o;
62 picojson::parse(v, message, message + strlen(message), &err);
64 std::cerr << "Ignoring message.\n";
68 std::cout << "HandleMessage: " << message << std::endl;
70 std::string cmd = v.get("cmd").to_str();
71 if (cmd == "ContentManager.getDirectories") {
72 HandleGetDirectoriesRequest(v);
73 } else if (cmd == "ContentManager.find") {
75 } else if (cmd == "ContentManager.scanFile") {
76 HandleScanFileRequest(v);
78 std::cerr << "Message " + cmd + " is not supported.\n";
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>());
90 PostMessage(v.serialize().c_str());
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>());
98 picojson::value v(reply);
99 PostMessage(v.serialize().c_str());
102 void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg) {
103 picojson::value::object reply;
104 PostAsyncSuccessReply(msg, reply);
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);
114 void ContentInstance::HandleSyncMessage(const char* message) {
117 void ContentInstance::HandleGetDirectoriesRequest(const picojson::value& msg) {
118 ContentFolderList folderList;
119 if (media_folder_foreach_folder_from_db(NULL,
121 reinterpret_cast<void*>(&folderList)) != MEDIA_CONTENT_ERROR_NONE) {
122 std::cerr << "media_folder_foreach_folder_from_db: error" << std::endl;
124 HandleGetDirectoriesReply(msg, &folderList);
128 void ContentInstance::HandleGetDirectoriesReply(const picojson::value& msg,
129 ContentFolderList* folderList) {
130 const std::vector<ContentFolder*>& results = folderList->getAllItems();
131 picojson::value::array folders;
133 for (unsigned i = 0; i < results.size(); i++) {
134 ContentFolder* folder = results[i];
136 picojson::value::object o;
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());
144 folders.push_back(picojson::value(o));
146 picojson::value value(folders);
147 PostAsyncSuccessReply(msg, value);
150 bool ContentInstance::mediaFolderCallback(media_folder_h handle,
155 ContentFolderList* folderList =
156 reinterpret_cast<ContentFolderList*>(user_data);
158 ContentFolder* folder = new ContentFolder;
159 folder->init(handle);
160 folderList->addFolder(folder);
167 void ContentInstance::HandleFindRequest(const picojson::value& msg) {
168 ContentItemList itemList;
169 filter_h filterHandle = NULL;
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);
183 if (media_info_foreach_media_from_db(filterHandle,
185 reinterpret_cast<ContentFolderList*>(&itemList))
186 != MEDIA_CONTENT_ERROR_NONE) {
187 std::cerr << "media_info_foreach_media_from_db: error" << std::endl;
189 HandleFindReply(msg, &itemList);
192 if (filterHandle != NULL && media_filter_destroy(filterHandle)
193 != MEDIA_CONTENT_ERROR_NONE)
194 std::cerr << "media_filter_destroy failed" << std::endl;
197 void ContentInstance::HandleFindReply(
198 const picojson::value& msg,
199 ContentItemList* itemList) {
200 const std::vector<ContentItem*> &results = itemList->getAllItems();
202 picojson::value::array items;
204 for (unsigned i = 0; i < results.size(); i++) {
205 ContentItem* item = results[i];
207 picojson::value::object o;
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());
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()));
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()));
255 picojson::value v(o);
257 items.push_back(picojson::value(o));
259 picojson::value value(items);
261 std::cout << "JSON reply: " << std::endl <<
262 value.serialize().c_str() << std::endl;
264 PostAsyncSuccessReply(msg, value);
267 bool ContentInstance::mediaInfoCallback(media_info_h handle, void* user_data) {
271 ContentItemList* itemList = reinterpret_cast<ContentItemList*>(user_data);
273 ContentItem* item = new ContentItem;
275 itemList->addItem(item);
282 void ContentFolder::init(media_folder_h handle) {
285 media_content_storage_e storageType;
287 if (media_folder_get_folder_id(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
292 if (media_folder_get_path(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
293 setDirectoryURI(createUriFromLocalPath(str));
297 if (media_folder_get_name(handle, &str) == MEDIA_CONTENT_ERROR_NONE) {
302 if (media_folder_get_storage_type(
303 handle, &storageType) == MEDIA_CONTENT_ERROR_NONE) {
305 if (storageType == MEDIA_CONTENT_STORAGE_INTERNAL) {
307 } else if (storageType == MEDIA_CONTENT_STORAGE_EXTERNAL) {
312 setStorageType(type);
315 if (media_folder_get_modified_time(
316 handle, &date) == MEDIA_CONTENT_ERROR_NONE) {
319 setModifiedDate(tmp);
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;
333 void ContentItem::init(media_info_h handle) {
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.
340 if (media_info_get_media_id(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
345 if (media_info_get_mime_type(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
350 if (media_info_get_title(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
355 if (media_info_get_display_name(handle,
356 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
361 if (media_info_get_file_path(handle, &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
362 setContentURI(createUriFromLocalPath(pc));
366 if (media_info_get_thumbnail_path(handle,
367 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
368 setThumbnailURIs(createUriFromLocalPath(pc));
372 if (media_info_get_description(handle,
373 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
379 if (media_info_get_modified_time(handle, &date) == MEDIA_CONTENT_ERROR_NONE) {
382 setModifiedDate(tmp);
386 if (media_info_get_rating(handle, &i) == MEDIA_CONTENT_ERROR_NONE)
389 unsigned long long ll; // NOLINT
390 if (media_info_get_size(handle, &ll) == MEDIA_CONTENT_ERROR_NONE)
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) {
399 if (media_info_get_image(handle, &image) == MEDIA_CONTENT_ERROR_NONE) {
400 if (image_meta_get_width(image, &i) == MEDIA_CONTENT_ERROR_NONE)
403 if (image_meta_get_height(image, &i) == MEDIA_CONTENT_ERROR_NONE)
406 // TODO(spoussa): coordinates do not return sensible values...
408 if (media_info_get_latitude(handle, &d) == MEDIA_CONTENT_ERROR_NONE)
411 if (media_info_get_longitude(handle, &d) == MEDIA_CONTENT_ERROR_NONE)
414 media_content_orientation_e orientation;
415 if (image_meta_get_orientation(image, &orientation)
416 == MEDIA_CONTENT_ERROR_NONE) {
417 std::string result("");
419 switch (orientation) {
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;
431 setOrientation(result);
433 image_meta_destroy(image);
435 } else if (type == MEDIA_CONTENT_TYPE_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) {
446 if (video_meta_get_album(video,
447 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
452 if (video_meta_get_artist(video,
453 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
458 if (video_meta_get_width(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
462 if (video_meta_get_height(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
466 if (video_meta_get_duration(video, &i) == MEDIA_CONTENT_ERROR_NONE) {
470 video_meta_destroy(video);
472 } else if (type == MEDIA_CONTENT_TYPE_MUSIC) {
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) {
483 if (audio_meta_get_album(audio,
484 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
489 if (audio_meta_get_artist(audio,
490 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
495 if (audio_meta_get_composer(audio,
496 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
501 if (audio_meta_get_duration(audio, &i) == MEDIA_CONTENT_ERROR_NONE)
504 if (audio_meta_get_copyright(audio,
505 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
510 if (audio_meta_get_track_num(audio,
511 &pc) == MEDIA_CONTENT_ERROR_NONE && pc) {
517 if (audio_meta_get_bit_rate(audio, &i) == MEDIA_CONTENT_ERROR_NONE)
520 audio_meta_destroy(audio);
521 } else if (type == MEDIA_CONTENT_TYPE_OTHERS) {
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;
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);
573 int result = media_content_scan_file(path.c_str());
574 if (result == MEDIA_CONTENT_ERROR_NONE) {
575 HandleScanFileReply(msg);
577 std::cerr << "media_content_scan_file error:" << result << std::endl;
578 PostAsyncErrorReply(msg, WebApiAPIErrors::DATABASE_ERR);
584 void ContentInstance::HandleScanFileReply(const picojson::value& msg) {
585 PostAsyncSuccessReply(msg);