From fd0fd0a0b88355398d7f57c34e30b47a94c8329f Mon Sep 17 00:00:00 2001 From: Farshid Monhaseri Date: Mon, 3 Feb 2020 17:38:27 +0330 Subject: mediascanner: Clustered media-list & Code unification Bug-AGL: SPEC-3100 - Add clustered media-list view as an option when the user requests it with 'view':'clustered' ARGS on event subscription or 'media_result' verb call. If no ARGS passed, the scanner has its default media-list view. - Unify event scans & verb-call scans codes as much as possible. Now scan operation has single & transparent control flow. - Add 'ScanFilter_t' data structure and a few other modifications so managing new features and filters will be easier and clear. - Fix a few bugs. - Extract precise error messages from deeper functions and log & reply fail message to the client. Signed-off-by: Farshid Monhaseri Change-Id: Ia3629af75614359260eb7af0c0331d6ef9f3bcbe --- binding/media-api.c | 253 ++++++++++++++++++++++++++++++++++++------------ binding/media-manager.c | 166 ++++++++++++++++++++----------- binding/media-manager.h | 102 +++++++++++-------- 3 files changed, 361 insertions(+), 160 deletions(-) diff --git a/binding/media-api.c b/binding/media-api.c index 0365b49..bd0f7db 100644 --- a/binding/media-api.c +++ b/binding/media-api.c @@ -31,7 +31,7 @@ static afb_event_t media_removed_event; static gint get_scan_type(afb_req_t request, json_object *jtype) { gint ret = 0; - const *stype = NULL; + const char *stype = NULL; if(!json_object_is_type(jtype,json_type_string)) { afb_req_fail(request,"failed", "invalid scan-type type"); return ret; @@ -64,9 +64,9 @@ static gint get_scan_types(afb_req_t request) { if(!json_object_object_get_ex(afb_req_json(request),"types",&jtypes)) { /* - * Considering 'audio' & 'video' scan types as default - * if the user doesn't provide 'types' property, - * for sake of compability with previeus versions + * Considered 'audio' & 'video' scan types as default types, + * if the user doesn't provide 'types' property. + * (for sake of backward compatibility) */ ret = (LMS_AUDIO_SCAN | LMS_VIDEO_SCAN); return ret; @@ -83,18 +83,46 @@ static gint get_scan_types(afb_req_t request) { for(i=0; ilist; + const char *scan_type = mlist->scan_type_str; for (l = list; l; l = l->next) { - struct Media_Item *item = l->data; + MediaItem_t *item = l->data; json_object *jdict = json_object_new_object(); jstring = json_object_new_string(item->path); json_object_object_add(jdict, "path", jstring); - - jstring = json_object_new_string(item->type); - json_object_object_add(jdict, "type", jstring); + if(view == MEDIA_LIST_VIEW_DEFAULT) { + jstring = json_object_new_string(scan_type); + json_object_object_add(jdict, "type", jstring); + } if (item->metadata.title) { jstring = json_object_new_string(item->metadata.title); @@ -210,59 +247,153 @@ static json_object *new_json_object_from_device(GList *list) } json_object_array_add(jarray, jdict); + num++; } if (jstring == NULL) + return -1; + + return num; +} + +static json_object* media_device_scan(ScanFilter_t *filter, gchar **error) +{ + json_object *jresp = NULL; + json_object *jlist = NULL; + MediaList_t *mlist = NULL; + MediaDevice_t *mdev = NULL; + gint res = -1; + gint num = 0; + gint i; + + if(!filter){ + *error = g_strdup("NULL filter!"); + return NULL; + } + if(!filter->scan_types) + return NULL; + + mdev = g_malloc0(sizeof(*mdev)); + if(!mdev){ + *error = g_strdup("Cannot allocate memory."); + return NULL; + } + + for( i = LMS_MIN_ID; i < LMS_SCAN_COUNT; ++i) + { + if(filter->scan_types & (1 << i)) + { + mdev->lists[i] = g_malloc0(sizeof(MediaList_t)); + if(!mdev->lists[i]){ + media_device_free(mdev); + *error = g_strdup("Cannot allocate memory to media-list object"); + return NULL; + } + } + } + mdev->filters = filter; + + res = media_lists_get(mdev,error); + if(res < 0) + { + media_device_free(mdev); return NULL; + } - json_object_object_add(jresp, "Media", jarray); + if(filter->listview_type == MEDIA_LIST_VIEW_CLUSTERD) + { + jlist = json_object_new_object(); + for(i = LMS_MIN_ID; i < LMS_SCAN_COUNT; ++i) + { + json_object *typed_arr = json_object_new_array(); + mlist = mdev->lists[i]; + if(mlist != NULL) + { + res = media_jlist_from_media_list(mlist,MEDIA_LIST_VIEW_CLUSTERD,typed_arr); + if(res < 0) + { + *error = g_strdup("media parsing error"); + media_device_free(mdev); + json_object_put(jlist); + return NULL; + } + json_object_object_add(jlist,lms_scan_types[i],typed_arr); + num += res; + } + } + } + else + { + jlist = json_object_new_array(); + for(i = LMS_MIN_ID; i < LMS_SCAN_COUNT; ++i) + { + mlist = mdev->lists[i]; + if(mlist != NULL) + { + res = media_jlist_from_media_list(mlist,MEDIA_LIST_VIEW_DEFAULT,jlist); + if(res < 0) + { + *error = g_strdup("media parsing error"); + media_device_free(mdev); + json_object_put(jlist); + return NULL; + } + num += res; + } + } + } + media_device_free(mdev); + jresp = json_object_new_object(); + json_object_object_add(jresp, "Media", jlist); return jresp; } static void media_results_get (afb_req_t request) { - GList *list = NULL; json_object *jresp = NULL; - gint scan_type = 0; - - scan_type = get_scan_types(request); - if(scan_type < 0) return; + gchar *error = NULL; + gint scan_types = 0; + ScanFilter_t filter; - ListLock(); - - if(scan_type & LMS_AUDIO_SCAN) - list = media_lightmediascanner_scan(list, NULL, LMS_AUDIO_SCAN); - if(scan_type & LMS_VIDEO_SCAN) - list = media_lightmediascanner_scan(list, NULL, LMS_VIDEO_SCAN); - if(scan_type & LMS_IMAGE_SCAN) - list = media_lightmediascanner_scan(list, NULL, LMS_IMAGE_SCAN); - - if (list == NULL) { - afb_req_fail(request, "failed", "media scan error"); - ListUnlock(); + filter.scan_types = get_scan_types(request); + if(filter.scan_types < 0) return; - } + filter.listview_type = get_scan_view(request); + filter.scan_uri = SCAN_URI_DEFAULT; - jresp = new_json_object_from_device(list); - g_list_free_full(list,free_media_item); + ListLock(); + jresp = media_device_scan(&filter,&error); ListUnlock(); - if (jresp == NULL) { - afb_req_fail(request, "failed", "media parsing error"); + if (jresp == NULL) + { + afb_req_fail(request, "failed", error); + LOGE(" %s",error); + g_free(error); return; } afb_req_success(request, jresp, "Media Results Displayed"); } -static void media_broadcast_device_added (GList *list) +static void media_broadcast_device_added (ScanFilter_t *filters) { - json_object *jresp = new_json_object_from_device(list); + json_object *jresp = NULL; + gchar *error = NULL; - if (jresp != NULL) { - afb_event_push(media_added_event, jresp); + ListLock(); + jresp = media_device_scan(filters,&error); + ListUnlock(); + + if (jresp == NULL) + { + LOGE("ERROR:%s\n",error); + g_free(error); + return; } + + afb_event_push(media_added_event, jresp); } static void media_broadcast_device_removed (const char *obj_path) diff --git a/binding/media-manager.c b/binding/media-manager.c index 283692c..8e1ac69 100644 --- a/binding/media-manager.c +++ b/binding/media-manager.c @@ -48,6 +48,7 @@ static stMediaPlayerManage MediaPlayerManage = { 0 }; static scannerDB scanDB = { 0 }; /* ------ LOCAL FUNCTIONS --------- */ + void ListLock() { g_mutex_lock(&(MediaPlayerManage.m)); } @@ -95,59 +96,67 @@ void DebugTraceSendMsg(int level, gchar* message) } -GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) +static void media_item_free(gpointer data) +{ + MediaItem_t *item = data; + + g_free(item->metadata.title); + g_free(item->metadata.artist); + g_free(item->metadata.album); + g_free(item->metadata.genre); + g_free(item->path); + g_free(item); +} + +gint media_lightmediascanner_scan(MediaList_t *mlist, gchar* uri, gchar **error) { - sqlite3 *conn; sqlite3_stmt *res; const char *tail; const gchar *db_path; gchar *query; - gchar *media_type; int ret = 0; + gint num = 0; if(!scanDB.is_open) { db_path = scanner1_get_data_base_path(MediaPlayerManage.lms_proxy); ret = sqlite3_open(db_path, &scanDB.db); if (ret != SQLITE_OK) { - LOGE("Cannot open SQLITE database: '%s'\n", db_path); + LOGD("Cannot open SQLITE database: '%s'\n", db_path); scanDB.is_open = FALSE; - g_list_free_full(list,free_media_item); - return NULL; + g_list_free_full(mlist,media_item_free); + return -1; } scanDB.is_open = TRUE; } - switch (scan_type) { - case LMS_VIDEO_SCAN: + switch (mlist->scan_type_id) { + case LMS_VIDEO_ID: query = g_strdup_printf(VIDEO_SQL_QUERY, uri ? uri : ""); - media_type = lms_scan_types[LMS_VIDEO_ID]; break; - case LMS_IMAGE_SCAN: + case LMS_IMAGE_ID: query = g_strdup_printf(IMAGE_SQL_QUERY, uri ? uri : ""); - media_type = lms_scan_types[LMS_IMAGE_ID]; break; - case LMS_AUDIO_SCAN: + case LMS_AUDIO_ID: default: query = g_strdup_printf(AUDIO_SQL_QUERY, uri ? uri : ""); - media_type = lms_scan_types[LMS_AUDIO_ID]; } if (!query) { - LOGE("Cannot allocate memory for query\n"); - return NULL; + *error = g_strdup_printf("Cannot allocate memory for query"); + return -1; } ret = sqlite3_prepare_v2(scanDB.db, query, (int) strlen(query), &res, &tail); if (ret) { - LOGE("Cannot execute query '%s'\n", query); + *error = g_strdup("Cannot execute query"); g_free(query); - return NULL; + return -1; } while (sqlite3_step(res) == SQLITE_ROW) { struct stat buf; - struct Media_Item *item; + MediaItem_t *item = NULL; const char *path = (const char *) sqlite3_column_text(res, 0); gchar *tmp; @@ -155,35 +164,42 @@ GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) if (ret) continue; - //We may check the allocation result ... but It may be a bit expensive in such a loop + //We may check the allocation result ... but It maybe a bit expensive in such a loop item = g_malloc0(sizeof(*item)); + tmp = g_uri_escape_string(path, "/", TRUE); item->path = g_strdup_printf("file://%s", tmp); g_free(tmp); - item->type = media_type; item->metadata.title = g_strdup((gchar *) sqlite3_column_text(res, 1)); item->metadata.artist = g_strdup((gchar *) sqlite3_column_text(res, 2)); item->metadata.album = g_strdup((gchar *) sqlite3_column_text(res, 3)); item->metadata.genre = g_strdup((gchar *) sqlite3_column_text(res, 4)); item->metadata.duration = sqlite3_column_int(res, 5) * 1000; - list = g_list_append(list, item); + mlist->list = g_list_append(mlist->list, item); + num++; } g_free(query); - return list; + return num; } -void free_media_item(void *data) +void media_device_free(MediaDevice_t *mdev) { - struct Media_Item *item = data; + gint i; - g_free(item->metadata.title); - g_free(item->metadata.artist); - g_free(item->metadata.album); - g_free(item->metadata.genre); - g_free(item->path); - g_free(item); + if(mdev){ + for(i = LMS_MIN_ID; i < LMS_SCAN_COUNT; ++i) + { + if(mdev->lists[i] != NULL) { + g_list_free_full(mdev->lists[i]->list,media_item_free); + g_free(mdev->lists[i]); + } + } + g_free(mdev->filters->scan_uri); + mdev->filters->scan_uri = NULL; + g_free(mdev); + } } static void @@ -191,15 +207,13 @@ on_interface_proxy_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, const gchar* const *invalidated_properties) { - if(!(MediaPlayerManage.type_filter & LMS_ALL_SCAN)) - return; - GVariantIter iter; gchar *key = NULL; GVariant *subValue = NULL; - gchar *pInterface = NULL; - GList *list = NULL; + const gchar *pInterface; + ScanFilter_t *filter = &MediaPlayerManage.filters; gboolean br = FALSE; + pInterface = g_dbus_proxy_get_interface_name (proxy); if (0 != g_strcmp0(pInterface, LIGHTMEDIASCANNER_INTERFACE)) @@ -219,33 +233,20 @@ on_interface_proxy_properties_changed (GDBusProxy *proxy, br = TRUE; } } - if(br) return; - ListLock(); - if(MediaPlayerManage.type_filter & LMS_AUDIO_SCAN) - list = media_lightmediascanner_scan(list, MediaPlayerManage.uri_filter, LMS_AUDIO_SCAN); - if(MediaPlayerManage.type_filter & LMS_VIDEO_SCAN) - list = media_lightmediascanner_scan(list, MediaPlayerManage.uri_filter, LMS_VIDEO_SCAN); - if(MediaPlayerManage.type_filter & LMS_IMAGE_SCAN) - list = media_lightmediascanner_scan(list, MediaPlayerManage.uri_filter, LMS_IMAGE_SCAN); - - g_free(MediaPlayerManage.uri_filter); - MediaPlayerManage.uri_filter = NULL; - - if (list != NULL && g_RegisterCallback.binding_device_added) - g_RegisterCallback.binding_device_added(list); - - g_list_free_full(list, free_media_item); - - ListUnlock(); + if (filter->scan_types && + filter->scan_uri && + g_RegisterCallback.binding_device_added) + g_RegisterCallback.binding_device_added(filter); } static int MediaPlayerDBusInit(void) { GError *error = NULL; + MediaPlayerManage.lms_proxy = NULL; MediaPlayerManage.lms_proxy = scanner1_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, LIGHTMEDIASCANNER_SERVICE, LIGHTMEDIASCANNER_PATH, NULL, &error); @@ -288,7 +289,6 @@ unmount_cb (GFileMonitor *mon, gint ret = 0; ListLock(); - if (g_RegisterCallback.binding_device_removed && event == G_FILE_MONITOR_EVENT_DELETED) { @@ -309,7 +309,7 @@ unmount_cb (GFileMonitor *mon, } g_free(path); } else if (event == G_FILE_MONITOR_EVENT_CREATED) { - MediaPlayerManage.uri_filter = path; + MediaPlayerManage.filters.scan_uri = path; } else { g_free(path); } @@ -348,7 +348,6 @@ int MediaPlayerManagerInit() { ret = MediaPlayerDBusInit(); if (ret == 0) pthread_create(&thread_id, NULL, media_event_loop_thread, NULL); - return ret; } @@ -373,13 +372,62 @@ void BindingAPIRegister(const Binding_RegisterCallback_t* pstRegisterCallback) } } +void setAPIMediaListView(gint view) { + MediaPlayerManage.filters.listview_type = view; +} + gint ScanTypeAppend(gint type) { - return MediaPlayerManage.type_filter |= (type & LMS_ALL_SCAN); + return MediaPlayerManage.filters.scan_types |= (type & LMS_ALL_SCAN); } gint ScanTypeRemove(gint type) { - MediaPlayerManage.type_filter = (MediaPlayerManage.type_filter & (~type)) & LMS_ALL_SCAN; - return MediaPlayerManage.type_filter; + MediaPlayerManage.filters.scan_types = + ( MediaPlayerManage.filters.scan_types & (~type)) & LMS_ALL_SCAN; + return MediaPlayerManage.filters.scan_types; +} + +gint media_lists_get(MediaDevice_t* mdev, gchar **error) +{ + MediaList_t *mlist = NULL; + ScanFilter_t *filters = NULL; + gint ret = -1; + gint scaned_media = 0; + gint i = 0; + + if(!mdev) + { + *error = g_strdup("'MediaDevice' object is NULL!"); + return -1; + } + filters = mdev->filters; + + for( i = LMS_MIN_ID; i < LMS_SCAN_COUNT; ++i) + { + if(filters->scan_types & (1 << i)) + { + mlist = mdev->lists[i]; + mlist->scan_type_str = lms_scan_types[i]; + mlist->scan_type_id = i; + + ret = media_lightmediascanner_scan(mlist,filters->scan_uri,error); + if(ret < 0){ + return ret; + } else if(ret == 0){ + free(mdev->lists[i]); + mdev->lists[i] = NULL; + } else { + scaned_media += ret; + } + } + } + + if(scaned_media == 0) + { + *error = g_strdup("No media found!"); + return -1; + } + LOGD("\n\tscanned media: %d\n",scaned_media); + return scaned_media; } \ No newline at end of file diff --git a/binding/media-manager.h b/binding/media-manager.h index 65ee831..864e552 100644 --- a/binding/media-manager.h +++ b/binding/media-manager.h @@ -105,64 +105,86 @@ void DebugTraceSendMsg(int level, gchar* message); "ORDER BY " \ "images.title" +enum { + LMS_MIN_ID = 0, + LMS_AUDIO_ID = 0, + LMS_VIDEO_ID, + LMS_IMAGE_ID, + LMS_SCAN_COUNT +}; + +#define MEDIA_LIST_VIEW_DEFAULT 1u +#define MEDIA_LIST_VIEW_CLUSTERD 2u + +#define LMS_AUDIO_SCAN (1 << LMS_AUDIO_ID) +#define LMS_VIDEO_SCAN (1 << LMS_VIDEO_ID) +#define LMS_IMAGE_SCAN (1 << LMS_IMAGE_ID) + +#define LMS_ALL_SCAN ( LMS_AUDIO_SCAN | LMS_VIDEO_SCAN | LMS_IMAGE_SCAN ) + +#define MEDIA_AUDIO "audio" +#define MEDIA_VIDEO "video" +#define MEDIA_IMAGE "image" +#define MEDIA_ALL "all" + +extern const char *lms_scan_types[LMS_SCAN_COUNT]; + +#define SCAN_URI_DEFAULT NULL + typedef struct { - GList *list; - gchar *uri_filter; - gint type_filter; + gint listview_type; + gint scan_types; + gchar *scan_uri; +}ScanFilter_t; + +typedef struct { + ScanFilter_t filters; GMutex m; - Scanner1 *lms_proxy; GFileMonitor *mon; + Scanner1 *lms_proxy; } stMediaPlayerManage; + +typedef struct { + gchar *path; + struct { + gchar *title; + gchar *artist; + gchar *album; + gchar *genre; + gint duration; + } metadata; +}MediaItem_t; + +typedef struct { + GList *list; + gchar* scan_type_str; + gint scan_type_id; +} MediaList_t; + +typedef struct { + MediaList_t *lists[LMS_SCAN_COUNT]; + ScanFilter_t *filters; +} MediaDevice_t; + typedef struct tagBinding_RegisterCallback { - void (*binding_device_added)(GList *list); + void (*binding_device_added)(ScanFilter_t *filters); void (*binding_device_removed)(const char *obj_path); } Binding_RegisterCallback_t; /* ------ PUBLIC PLUGIN FUNCTIONS --------- */ -void free_media_item(void *data); void BindingAPIRegister(const Binding_RegisterCallback_t* pstRegisterCallback); int MediaPlayerManagerInit(void); gint ScanTypeAppend(gint); gint ScanTypeRemove(gint); +void setAPIMediaListView(gint view); void ListLock(); void ListUnlock(); -GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type); - -struct Media_Item { - gchar *path; - gchar *type; - struct { - gchar *title; - gchar *artist; - gchar *album; - gchar *genre; - gint duration; - } metadata; -}; - -enum { - LMS_AUDIO_ID, - LMS_VIDEO_ID, - LMS_IMAGE_ID, - LMS_SCAN_COUNT -}; - -#define LMS_AUDIO_SCAN (1 << LMS_AUDIO_ID) -#define LMS_VIDEO_SCAN (1 << LMS_VIDEO_ID) -#define LMS_IMAGE_SCAN (1 << LMS_IMAGE_ID) - -#define LMS_ALL_SCAN ( LMS_AUDIO_SCAN | LMS_VIDEO_SCAN | LMS_IMAGE_SCAN ) +gint media_lists_get(MediaDevice_t* mdev, gchar **error); +void media_device_free(MediaDevice_t *mdev); -#define MEDIA_AUDIO "audio" -#define MEDIA_VIDEO "video" -#define MEDIA_IMAGE "image" -#define MEDIA_ALL "all" - -extern const char *lms_scan_types[LMS_SCAN_COUNT]; - -#endif +#endif \ No newline at end of file -- cgit 1.2.3-korg