initial upload
[apps/native/smart-surveillance-camera.git] / src / motion.c
1  /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
18 #include <pthread.h>
19 #include <glib.h>
20 #include "log.h"
21 #include "motion.h"
22
23 #define IDLE_PRIORITY (G_PRIORITY_HIGH_IDLE + 30)
24
25 struct motion_data_s {
26         int state;
27         GHashTable *callback_hash;
28 };
29
30 struct motion_callback_s {
31         motion_state_changed_cb callback;
32         void *cb_data;
33 };
34
35 struct motion_pass_data_s {
36         char *pass_key;
37         int state;
38 };
39
40 static struct motion_data_s *g_motion;
41 static pthread_mutex_t g_motion_mutex;
42
43 static int __free_motion_handle(struct motion_data_s *handle)
44 {
45         if (handle->callback_hash) {
46                 g_hash_table_destroy(handle->callback_hash);
47                 g_hash_table_unref(handle->callback_hash);
48         }
49
50         free(handle);
51         return 0;
52 }
53
54 int motion_initialize(void)
55 {
56         if (g_motion) {
57                 _D("The motion is already initialized!");
58                 return 0;
59         }
60
61         g_motion = malloc(sizeof(struct motion_data_s));
62         retv_if(!g_motion, -1);
63
64         g_motion->callback_hash =
65                 g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
66
67         pthread_mutex_init(&g_motion_mutex, NULL);
68         g_motion->state = 0;
69
70         /* TODO : initialize real motion detector here */
71
72         return 0;
73 }
74
75 int motion_finalize(void)
76 {
77         if (g_motion) {
78                 pthread_mutex_destroy(&g_motion_mutex);
79                 __free_motion_handle(g_motion);
80                 g_motion = NULL;
81         }
82
83         return 0;
84 }
85
86 static void __cb_item_foreach(gpointer key, gpointer value, gpointer user_data)
87 {
88         char *item_name = key;
89         struct motion_callback_s *cb_item = value;
90         struct motion_pass_data_s *pass_item = user_data;
91
92         ret_if(!item_name);
93         ret_if(!cb_item);
94         ret_if(!pass_item);
95
96
97         if (pass_item->pass_key &&
98                 (0 == g_strcmp0(item_name, pass_item->pass_key))) {
99                         // _D("pass item - %s", item_name);
100                         return;
101                 }
102
103         _D("callback called for [%s]", item_name);
104         cb_item->callback(pass_item->state, cb_item->cb_data);
105 }
106
107 static gboolean __call_cb_idle(gpointer data)
108 {
109         struct motion_pass_data_s *pass_item = data;
110
111         g_hash_table_foreach(g_motion->callback_hash, __cb_item_foreach, pass_item);
112         g_free(pass_item->pass_key);
113         g_free(pass_item);
114
115         return G_SOURCE_REMOVE;
116 }
117
118 int motion_state_set(int state, const char *pass_key)
119 {
120         int old_state = 0;
121         retv_if(!g_motion, -1);
122
123         // _D("set state : %d", state);
124
125         pthread_mutex_lock(&g_motion_mutex);
126         old_state = g_motion->state;
127         pthread_mutex_unlock(&g_motion_mutex);
128
129         if (old_state != state) {
130                 /* TODO : handle real motion detector here */
131                 pthread_mutex_lock(&g_motion_mutex);
132                 g_motion->state = state;
133                 pthread_mutex_unlock(&g_motion_mutex);
134
135                 if (g_hash_table_size(g_motion->callback_hash) > 0) {
136                         struct motion_pass_data_s *pass_item = NULL;
137
138                         pass_item = g_new(struct motion_pass_data_s, 1);
139                         pass_item->pass_key = g_strdup(pass_key);
140                         pass_item->state = state;
141                         g_idle_add_full(IDLE_PRIORITY,
142                                 __call_cb_idle, pass_item, NULL);
143                 }
144         }
145         return 0;
146 }
147
148 int motion_state_get(int *state)
149 {
150         retv_if(!g_motion, -1);
151         retv_if(!state, -1);
152
153         pthread_mutex_lock(&g_motion_mutex);
154         *state = g_motion->state;
155         pthread_mutex_unlock(&g_motion_mutex);
156
157         // _D("get state : %d", *state);
158
159         return 0;
160 }
161
162 int motion_state_changed_cb_set(
163         const char *callback_key, motion_state_changed_cb callback, void *cb_data)
164 {
165         retv_if(!g_motion, -1);
166         retv_if(!g_motion->callback_hash, -1);
167         retv_if(!callback_key, -1);
168
169         if (callback) {
170                 struct motion_callback_s *cb_item = NULL;
171                 cb_item = g_try_new(struct motion_callback_s, 1);
172                 retv_if(!cb_item, -1);
173
174                 cb_item->callback = callback;
175                 cb_item->cb_data = cb_data;
176
177                 g_hash_table_insert(g_motion->callback_hash,
178                         g_strdup(callback_key), cb_item);
179         } else {
180                 g_hash_table_remove(g_motion->callback_hash, callback_key);
181         }
182
183         return 0;
184 }