summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeongmo Yang <jm80.yang@samsung.com>2016-08-09 16:00:40 +0900
committerJeongmo Yang <jm80.yang@samsung.com>2016-08-09 16:00:40 +0900
commit3b9b49d27a189a7e20fa499b546f77296daba281 (patch)
tree93f27e87290e900a164db6ad965770dabf3826fd
parentb99fb331c65df7c0d20773f8e9cd8027b84753c8 (diff)
downloadcamera-3b9b49d27a189a7e20fa499b546f77296daba281.tar.gz
camera-3b9b49d27a189a7e20fa499b546f77296daba281.tar.bz2
camera-3b9b49d27a189a7e20fa499b546f77296daba281.zip
[Release version 0.2.66] Add sub threads for 2.4 API compatibility
Change-Id: If6728e5132b3ce0418bf5fe27a64d51db7c0dfe8 Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
-rw-r--r--include/camera_private.h38
-rw-r--r--packaging/capi-media-camera.spec2
-rw-r--r--src/camera.c301
3 files changed, 204 insertions, 137 deletions
diff --git a/include/camera_private.h b/include/camera_private.h
index 56e8ad5..32257f1 100644
--- a/include/camera_private.h
+++ b/include/camera_private.h
@@ -42,6 +42,11 @@ extern "C" {
#define SET_PREVIEW_CB_TYPE(cb_info, cb_type) ((cb_info)->preview_cb_flag |= cb_type)
#define UNSET_PREVIEW_CB_TYPE(cb_info, cb_type) ((cb_info)->preview_cb_flag &= ~cb_type)
+enum {
+ CAMERA_MESSAGE_HANDLER_TYPE_GENERAL,
+ CAMERA_MESSAGE_HANDLER_TYPE_PREVIEW_CB,
+ CAMERA_MESSAGE_HANDLER_TYPE_CAPTURE_CB
+};
typedef struct _camera_stream_data_s {
union {
@@ -81,15 +86,32 @@ typedef struct _camera_stream_data_s {
int elevation[BUFFER_MAX_PLANE_NUM]; /**< Elevation of each plane */
} camera_stream_data_s;
+typedef struct _camera_msg_handler_info_s {
+ int type;
+ void *cb_info;
+ int running;
+ GCond cond;
+ GMutex mutex;
+ GQueue *queue;
+ GThread *thread;
+} camera_msg_handler_info_s;
+
typedef struct _camera_cb_info_s {
gint fd;
+
+ /* message receive thread */
GThread *msg_recv_thread;
- GThread *msg_handler_thread;
gint msg_recv_running;
- gint msg_handler_running;
- GCond msg_handler_cond;
- GMutex msg_handler_mutex;
- GQueue *msg_queue;
+
+ /* general message handler info */
+ camera_msg_handler_info_s msg_handler_info;
+
+ /* preview cb message handler info */
+ camera_msg_handler_info_s preview_cb_info;
+
+ /* capture cb message handler info */
+ camera_msg_handler_info_s capture_cb_info;
+
GList *idle_event_list;
GCond idle_event_cond;
GMutex idle_event_mutex;
@@ -98,8 +120,8 @@ typedef struct _camera_cb_info_s {
gchar recv_msg[MUSE_CAMERA_MSG_MAX_LENGTH];
GCond api_cond[MUSE_CAMERA_API_MAX];
GMutex api_mutex[MUSE_CAMERA_API_MAX];
- gint *api_activating;
- gint *api_ret;
+ gint api_activating[MUSE_CAMERA_API_MAX];
+ gint api_ret[MUSE_CAMERA_API_MAX];
tbm_bufmgr bufmgr;
media_format_h pkt_fmt;
int preview_cb_flag;
@@ -114,6 +136,8 @@ typedef struct _camera_cb_info_s {
typedef struct _camera_message_s {
gchar recv_msg[MUSE_CAMERA_MSG_MAX_LENGTH];
muse_camera_api_e api;
+ muse_camera_event_e event;
+ muse_camera_event_class_e event_class;
} camera_message_s;
typedef struct _camera_idle_event_s {
diff --git a/packaging/capi-media-camera.spec b/packaging/capi-media-camera.spec
index 38a3cac..2bf72be 100644
--- a/packaging/capi-media-camera.spec
+++ b/packaging/capi-media-camera.spec
@@ -1,6 +1,6 @@
Name: capi-media-camera
Summary: A Camera API
-Version: 0.2.65
+Version: 0.2.66
Release: 0
Group: Multimedia/API
License: Apache-2.0
diff --git a/src/camera.c b/src/camera.c
index 16620f2..402a45c 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -291,7 +291,6 @@ static int _client_wait_for_cb_return(muse_camera_api_e api, camera_cb_info_s *c
/*LOGD("return value : 0x%x", ret);*/
} else {
ret = CAMERA_ERROR_INVALID_OPERATION;
-
LOGE("api %d was TIMED OUT!", api);
}
} else {
@@ -1467,94 +1466,84 @@ IDLE_EVENT_CALLBACK_DONE:
static void *_camera_msg_handler_func(gpointer data)
{
- int ret = 0;
int api = 0;
- int event = 0;
- int event_class = 0;
+ int type = 0;
camera_message_s *cam_msg = NULL;
camera_idle_event_s *cam_idle_event = NULL;
- camera_cb_info_s *cb_info = (camera_cb_info_s *)data;
+ camera_msg_handler_info_s *handler_info = (camera_msg_handler_info_s *)data;
+ camera_cb_info_s *cb_info = NULL;
- if (cb_info == NULL) {
- LOGE("cb_info NULL");
+ if (!handler_info || !handler_info->cb_info) {
+ LOGE("t:%d NULL handler %p", type, handler_info);
return NULL;
}
- LOGD("start");
+ cb_info = (camera_cb_info_s *)handler_info->cb_info;
+ type = handler_info->type;
- g_mutex_lock(&cb_info->msg_handler_mutex);
+ LOGD("t:%d start", type);
- while (g_atomic_int_get(&cb_info->msg_handler_running)) {
- if (g_queue_is_empty(cb_info->msg_queue)) {
- /*LOGD("signal wait...");*/
- g_cond_wait(&cb_info->msg_handler_cond, &cb_info->msg_handler_mutex);
- /*LOGD("signal received");*/
+ g_mutex_lock(&handler_info->mutex);
- if (g_atomic_int_get(&cb_info->msg_handler_running) == 0) {
- LOGD("stop event thread");
+ while (g_atomic_int_get(&handler_info->running)) {
+ if (g_queue_is_empty(handler_info->queue)) {
+ /*LOGD("t:%d signal wait...", type);*/
+ g_cond_wait(&handler_info->cond, &handler_info->mutex);
+ /*LOGD("t:%d signal received", type);*/
+
+ if (g_atomic_int_get(&handler_info->running) == 0) {
+ LOGD("t:%d stop event thread", type);
break;
}
}
- cam_msg = (camera_message_s *)g_queue_pop_head(cb_info->msg_queue);
+ cam_msg = (camera_message_s *)g_queue_pop_head(handler_info->queue);
- g_mutex_unlock(&cb_info->msg_handler_mutex);
+ g_mutex_unlock(&handler_info->mutex);
if (cam_msg == NULL) {
- LOGE("NULL message");
- g_mutex_lock(&cb_info->msg_handler_mutex);
+ LOGE("t:%d NULL message", type);
+ g_mutex_lock(&handler_info->mutex);
continue;
}
api = cam_msg->api;
if (api < MUSE_CAMERA_API_MAX) {
+ int ret = 0;
+
g_mutex_lock(&cb_info->api_mutex[api]);
if (muse_camera_msg_get(ret, cam_msg->recv_msg)) {
cb_info->api_ret[api] = ret;
cb_info->api_activating[api] = 1;
- /*LOGD("camera api %d - return 0x%x", ret);*/
+ /*LOGD("t:%d camera api %d - return 0x%x", type, ret);*/
g_cond_signal(&cb_info->api_cond[api]);
} else {
- LOGE("failed to get camera ret for api %d, msg %s", api, cam_msg->recv_msg);
+ LOGE("t:%d failed to get camera ret for api %d, msg %s", type, api, cam_msg->recv_msg);
}
g_mutex_unlock(&cb_info->api_mutex[api]);
} else if (api == MUSE_CAMERA_CB_EVENT) {
- event = -1;
- event_class = -1;
-
- if (!muse_camera_msg_get(event, cam_msg->recv_msg) ||
- !muse_camera_msg_get(event_class, cam_msg->recv_msg)) {
- LOGE("failed to get camera event %d, class %d", event, event_class);
-
- g_free(cam_msg);
- cam_msg = NULL;
-
- g_mutex_lock(&cb_info->msg_handler_mutex);
- continue;
- }
-
- switch (event_class) {
+ switch (cam_msg->event_class) {
case MUSE_CAMERA_EVENT_CLASS_THREAD_SUB:
- _client_user_callback(cb_info, cam_msg->recv_msg, event);
+ _client_user_callback(cb_info, cam_msg->recv_msg, cam_msg->event);
break;
case MUSE_CAMERA_EVENT_CLASS_THREAD_MAIN:
cam_idle_event = g_new0(camera_idle_event_s, 1);
if (cam_idle_event == NULL) {
- LOGE("cam_idle_event alloc failed");
+ LOGE("t:%d cam_idle_event alloc failed", type);
break;
}
- cam_idle_event->event = event;
+ cam_idle_event->event = cam_msg->event;
cam_idle_event->cb_info = cb_info;
g_mutex_init(&cam_idle_event->event_mutex);
memcpy(cam_idle_event->recv_msg, cam_msg->recv_msg, sizeof(cam_idle_event->recv_msg));
- /*LOGD("add camera event[%d, %p] to IDLE", event, cam_idle_event);*/
+ /*LOGD("t:%d add camera event[%d, %p] to IDLE", type, event, cam_idle_event);*/
g_mutex_lock(&cb_info->idle_event_mutex);
cb_info->idle_event_list = g_list_append(cb_info->idle_event_list, (gpointer)cam_idle_event);
@@ -1566,38 +1555,39 @@ static void *_camera_msg_handler_func(gpointer data)
NULL);
break;
default:
- LOGE("unknown camera event class %d", event_class);
+ LOGE("t:%d not handled event class %d", type, cam_msg->event_class);
break;
}
} else {
- LOGE("unknown camera api[%d] message[%s]", api, cam_msg->recv_msg);
+ LOGE("t:%d unknown camera api[%d] message[%s]", type, api, cam_msg->recv_msg);
}
g_free(cam_msg);
cam_msg = NULL;
- g_mutex_lock(&cb_info->msg_handler_mutex);
+ g_mutex_lock(&handler_info->mutex);
}
/* remove remained event */
- while (!g_queue_is_empty(cb_info->msg_queue)) {
- cam_msg = (camera_message_s *)g_queue_pop_head(cb_info->msg_queue);
+ while (!g_queue_is_empty(handler_info->queue)) {
+ cam_msg = (camera_message_s *)g_queue_pop_head(handler_info->queue);
if (cam_msg) {
- LOGD("remove camera message %p", cam_msg);
+ LOGD("t:%d remove camera message %p", type, cam_msg);
free(cam_msg);
cam_msg = NULL;
} else {
- LOGW("NULL camera message");
+ LOGW("t:%d NULL camera message", type);
}
}
- g_mutex_unlock(&cb_info->msg_handler_mutex);
+ g_mutex_unlock(&handler_info->mutex);
- LOGD("return");
+ LOGD("t:%d return", type);
return NULL;
}
+
static void _camera_remove_idle_event_all(camera_cb_info_s *cb_info)
{
camera_idle_event_s *cam_idle_event = NULL;
@@ -1674,6 +1664,8 @@ static void *_camera_msg_recv_func(gpointer data)
int ret = 0;
int api = 0;
int api_class = 0;
+ int event = 0;
+ int event_class = 0;
int num_token = 0;
int str_pos = 0;
int prev_pos = 0;
@@ -1739,15 +1731,23 @@ static void *_camera_msg_recv_func(gpointer data)
api = -1;
api_class = -1;
+ event = -1;
+ event_class = -1;
if (!muse_camera_msg_get(api, parse_str[i])) {
LOGE("failed to get camera api");
continue;
}
- if (api != MUSE_CAMERA_CB_EVENT) {
+ if (api == MUSE_CAMERA_CB_EVENT) {
+ if (!muse_camera_msg_get(event, parse_str[i]) ||
+ !muse_camera_msg_get(event_class, parse_str[i])) {
+ LOGE("failed to get camera event or event_class [%s]", parse_str[i]);
+ continue;
+ }
+ } else {
if (!muse_camera_msg_get(api_class, parse_str[i])) {
- LOGE("failed to get camera api_class");
+ LOGE("failed to get camera api_class [%s]", parse_str[i]);
continue;
}
}
@@ -1791,14 +1791,29 @@ static void *_camera_msg_recv_func(gpointer data)
}
cam_msg->api = api;
- memcpy(cam_msg->recv_msg, parse_str[i], sizeof(cam_msg->recv_msg));
+ cam_msg->event = event;
+ cam_msg->event_class = event_class;
- /*LOGD("add camera message to queue : api %d", api);*/
+ memcpy(cam_msg->recv_msg, parse_str[i], sizeof(cam_msg->recv_msg));
- g_mutex_lock(&cb_info->msg_handler_mutex);
- g_queue_push_tail(cb_info->msg_queue, (gpointer)cam_msg);
- g_cond_signal(&cb_info->msg_handler_cond);
- g_mutex_unlock(&cb_info->msg_handler_mutex);
+ /*LOGD("add camera message to queue : api %d, event %d, event_class %d", api, event, event_class);*/
+
+ if (event == MUSE_CAMERA_EVENT_TYPE_PREVIEW) {
+ g_mutex_lock(&cb_info->preview_cb_info.mutex);
+ g_queue_push_tail(cb_info->preview_cb_info.queue, (gpointer)cam_msg);
+ g_cond_signal(&cb_info->preview_cb_info.cond);
+ g_mutex_unlock(&cb_info->preview_cb_info.mutex);
+ } else if (event == MUSE_CAMERA_EVENT_TYPE_CAPTURE) {
+ g_mutex_lock(&cb_info->capture_cb_info.mutex);
+ g_queue_push_tail(cb_info->capture_cb_info.queue, (gpointer)cam_msg);
+ g_cond_signal(&cb_info->capture_cb_info.cond);
+ g_mutex_unlock(&cb_info->capture_cb_info.mutex);
+ } else {
+ g_mutex_lock(&cb_info->msg_handler_info.mutex);
+ g_queue_push_tail(cb_info->msg_handler_info.queue, (gpointer)cam_msg);
+ g_cond_signal(&cb_info->msg_handler_info.cond);
+ g_mutex_unlock(&cb_info->msg_handler_info.mutex);
+ }
} else {
LOGW("unknown camera api %d and api_class %d", api, api_class);
}
@@ -1824,11 +1839,88 @@ CB_HANDLER_EXIT:
return NULL;
}
+
+static bool __create_msg_handler_thread(camera_msg_handler_info_s *handler_info,
+ int type, const char *thread_name, camera_cb_info_s *cb_info)
+{
+ if (!handler_info || !thread_name || !cb_info) {
+ LOGE("t:%d NULL %p %p %p",
+ type, handler_info, thread_name, cb_info);
+ return false;
+ }
+
+ LOGD("t:%d", type);
+
+ handler_info->type = type;
+ handler_info->queue = g_queue_new();
+ if (handler_info->queue == NULL) {
+ LOGE("t:%d queue failed", type);
+ return false;
+ }
+
+ g_mutex_init(&handler_info->mutex);
+ g_cond_init(&handler_info->cond);
+
+ handler_info->cb_info = (void *)cb_info;
+ g_atomic_int_set(&handler_info->running, 1);
+
+ handler_info->thread = g_thread_try_new(thread_name,
+ _camera_msg_handler_func, (gpointer)handler_info, NULL);
+ if (handler_info->thread == NULL) {
+ LOGE("t:%d thread failed", type);
+
+ g_mutex_clear(&handler_info->mutex);
+ g_cond_clear(&handler_info->cond);
+ g_queue_free(handler_info->queue);
+ handler_info->queue = NULL;
+
+ return false;
+ }
+
+ LOGD("t:%d done", type);
+
+ return true;
+}
+
+
+static void __destroy_msg_handler_thread(camera_msg_handler_info_s *handler_info)
+{
+ int type = 0;
+
+ if (!handler_info) {
+ LOGE("NULL handler");
+ return;
+ }
+
+ type = handler_info->type;
+
+ LOGD("t:%d thread %p", type, handler_info->thread);
+
+ if (handler_info->thread) {
+ g_mutex_lock(&handler_info->mutex);
+ g_atomic_int_set(&handler_info->running, 0);
+ g_cond_signal(&handler_info->cond);
+ g_mutex_unlock(&handler_info->mutex);
+
+ g_thread_join(handler_info->thread);
+ g_thread_unref(handler_info->thread);
+ handler_info->thread = NULL;
+
+ g_mutex_clear(&handler_info->mutex);
+ g_cond_clear(&handler_info->cond);
+ g_queue_free(handler_info->queue);
+ handler_info->queue = NULL;
+ }
+
+ LOGD("t:%d done", type);
+
+ return;
+}
+
+
static camera_cb_info_s *_client_callback_new(gint sockfd)
{
camera_cb_info_s *cb_info = NULL;
- gint *tmp_activating = NULL;
- gint *tmp_ret = NULL;
gint i = 0;
g_return_val_if_fail(sockfd > 0, NULL);
@@ -1839,8 +1931,6 @@ static camera_cb_info_s *_client_callback_new(gint sockfd)
goto ErrorExit;
}
- g_mutex_init(&cb_info->msg_handler_mutex);
- g_cond_init(&cb_info->msg_handler_cond);
g_mutex_init(&cb_info->idle_event_mutex);
g_cond_init(&cb_info->idle_event_cond);
g_mutex_init(&cb_info->mp_data_mutex);
@@ -1853,40 +1943,34 @@ static camera_cb_info_s *_client_callback_new(gint sockfd)
g_cond_init(&cb_info->api_cond[i]);
}
- tmp_activating = g_new0(gint, MUSE_CAMERA_API_MAX);
- if (tmp_activating == NULL) {
- LOGE("tmp_activating failed");
- goto ErrorExit;
- }
-
- tmp_ret = g_new0(gint, MUSE_CAMERA_API_MAX);
- if (tmp_ret == NULL) {
- LOGE("tmp_ret failed");
+ /* message handler thread */
+ if (!__create_msg_handler_thread(&cb_info->msg_handler_info,
+ CAMERA_MESSAGE_HANDLER_TYPE_GENERAL, "camera_msg_handler", cb_info)) {
+ LOGE("msg_handler_info failed");
goto ErrorExit;
}
- cb_info->msg_queue = g_queue_new();
- if (cb_info->msg_queue == NULL) {
- LOGE("msg_queue new failed");
+ /* message handler thread for preview callback */
+ if (!__create_msg_handler_thread(&cb_info->preview_cb_info,
+ CAMERA_MESSAGE_HANDLER_TYPE_PREVIEW_CB, "camera_msg_handler:preview_cb", cb_info)) {
+ LOGE("preview_cb_info failed");
goto ErrorExit;
}
- g_atomic_int_set(&cb_info->msg_handler_running, 1);
- cb_info->msg_handler_thread = g_thread_try_new("camera_msg_handler",
- _camera_msg_handler_func, (gpointer)cb_info, NULL);
- if (cb_info->msg_handler_thread == NULL) {
- LOGE("message handler thread creation failed");
+ /* message handler thread for capture callback */
+ if (!__create_msg_handler_thread(&cb_info->capture_cb_info,
+ CAMERA_MESSAGE_HANDLER_TYPE_CAPTURE_CB, "camera_msg_handler:capture_cb", cb_info)) {
+ LOGE("capture_cb_info failed");
goto ErrorExit;
}
cb_info->fd = sockfd;
- cb_info->api_activating = tmp_activating;
- cb_info->api_ret = tmp_ret;
cb_info->preview_cb_flag = 0;
#ifdef TIZEN_FEATURE_EVAS_RENDERER
cb_info->evas_info = NULL;
#endif /* TIZEN_FEATURE_EVAS_RENDERER */
+ /* message receive thread */
g_atomic_int_set(&cb_info->msg_recv_running, 1);
cb_info->msg_recv_thread = g_thread_try_new("camera_msg_recv",
_camera_msg_recv_func, (gpointer)cb_info, NULL);
@@ -1899,24 +1983,15 @@ static camera_cb_info_s *_client_callback_new(gint sockfd)
ErrorExit:
if (cb_info) {
- if (cb_info->msg_handler_thread) {
- g_mutex_lock(&cb_info->msg_handler_mutex);
- g_atomic_int_set(&cb_info->msg_handler_running, 0);
- g_cond_signal(&cb_info->msg_handler_cond);
- g_mutex_unlock(&cb_info->msg_handler_mutex);
-
- g_thread_join(cb_info->msg_handler_thread);
- g_thread_unref(cb_info->msg_handler_thread);
- cb_info->msg_handler_thread = NULL;
- }
+ __destroy_msg_handler_thread(&cb_info->msg_handler_info);
+ __destroy_msg_handler_thread(&cb_info->preview_cb_info);
+ __destroy_msg_handler_thread(&cb_info->capture_cb_info);
for (i = 0 ; i < MUSE_CAMERA_API_MAX ; i++) {
g_mutex_clear(&cb_info->api_mutex[i]);
g_cond_clear(&cb_info->api_cond[i]);
}
- g_mutex_clear(&cb_info->msg_handler_mutex);
- g_cond_clear(&cb_info->msg_handler_cond);
g_mutex_clear(&cb_info->idle_event_mutex);
g_cond_clear(&cb_info->idle_event_cond);
g_mutex_clear(&cb_info->mp_data_mutex);
@@ -1924,24 +1999,10 @@ ErrorExit:
g_mutex_clear(&cb_info->evas_mutex);
#endif /* TIZEN_FEATURE_EVAS_RENDERER */
- if (cb_info->msg_queue) {
- g_queue_free(cb_info->msg_queue);
- cb_info->msg_queue = NULL;
- }
-
g_free(cb_info);
cb_info = NULL;
}
- if (tmp_activating) {
- g_free(tmp_activating);
- tmp_activating = NULL;
- }
- if (tmp_ret) {
- g_free(tmp_ret);
- tmp_ret = NULL;
- }
-
return NULL;
}
@@ -1959,25 +2020,16 @@ static void _client_callback_destroy(camera_cb_info_s *cb_info)
LOGD("msg thread removed");
- g_mutex_lock(&cb_info->msg_handler_mutex);
- g_atomic_int_set(&cb_info->msg_handler_running, 0);
- g_cond_signal(&cb_info->msg_handler_cond);
- g_mutex_unlock(&cb_info->msg_handler_mutex);
-
- g_thread_join(cb_info->msg_handler_thread);
- g_thread_unref(cb_info->msg_handler_thread);
- cb_info->msg_handler_thread = NULL;
-
- g_queue_free(cb_info->msg_queue);
- cb_info->msg_queue = NULL;
+ /* destroy msg handler threads */
+ __destroy_msg_handler_thread(&cb_info->msg_handler_info);
+ __destroy_msg_handler_thread(&cb_info->preview_cb_info);
+ __destroy_msg_handler_thread(&cb_info->capture_cb_info);
for (i = 0 ; i < MUSE_CAMERA_API_MAX ; i++) {
g_mutex_clear(&cb_info->api_mutex[i]);
g_cond_clear(&cb_info->api_cond[i]);
}
- g_mutex_clear(&cb_info->msg_handler_mutex);
- g_cond_clear(&cb_info->msg_handler_cond);
g_mutex_clear(&cb_info->idle_event_mutex);
g_cond_clear(&cb_info->idle_event_cond);
g_mutex_clear(&cb_info->mp_data_mutex);
@@ -1996,14 +2048,6 @@ static void _client_callback_destroy(camera_cb_info_s *cb_info)
tbm_bufmgr_deinit(cb_info->bufmgr);
cb_info->bufmgr = NULL;
}
- if (cb_info->api_activating) {
- g_free(cb_info->api_activating);
- cb_info->api_activating = NULL;
- }
- if (cb_info->api_ret) {
- g_free(cb_info->api_ret);
- cb_info->api_ret = NULL;
- }
if (cb_info->pkt_fmt) {
media_format_unref(cb_info->pkt_fmt);
cb_info->pkt_fmt = NULL;
@@ -5377,7 +5421,6 @@ Exit:
/* release resources */
if (pc) {
g_atomic_int_set(&pc->cb_info->msg_recv_running, 0);
- g_atomic_int_set(&pc->cb_info->msg_handler_running, 0);
_client_callback_destroy(pc->cb_info);
pc->cb_info = NULL;
g_free(pc);