Add sample application[phone]
[staging/soundmanager.git] / sample / phone / telephony-binding / telephony-binding.c
1 /*
2  * Copyright (C) 2017 Konsulko Group
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 #define _GNU_SOURCE
18
19 #include <glib.h>
20 #include <json-c/json.h>
21
22 #include <afb/afb-binding.h>
23 #include <afb/afb-service-itf.h>
24
25 #include "ofono_manager.h"
26 #include "ofono_voicecallmanager.h"
27 #include "ofono_voicecall.h"
28
29 static const struct afb_binding_interface *interface;
30
31 static OrgOfonoVoiceCallManager *vcm;
32 static OrgOfonoVoiceCall *incoming_call, *voice_call;
33
34 static void dial(struct afb_req request)
35 {
36         struct json_object *query, *val;
37         const char *number;
38
39         query = afb_req_json(request);
40         json_object_object_get_ex(query, "value", &val);
41         if (json_object_is_type(val, json_type_string)) {
42                 number = json_object_get_string(val);
43                 if (voice_call) {
44                         ERROR(interface, "dial: cannot dial with active call");
45                         afb_req_fail(request, "active call", NULL);
46                 } else {
47                         DEBUG(interface, "dial: %s...\n", number);
48                         if (ofono_voicecallmanager_dial(vcm, (gchar *)number, "")) {
49                                 afb_req_success(request, NULL, NULL);
50                         } else {
51                                 ERROR(interface, "dial: failed to dial number\n");
52                                 afb_req_fail(request, "failed dial", NULL);
53                         }
54                 }
55         } else {
56                 ERROR(interface, "dial: no phone number parameter\n");
57                 afb_req_fail(request, "no number", NULL);
58         }
59 }
60
61 static void hangup(struct afb_req request)
62 {
63         if (voice_call) {
64                 DEBUG(interface, "Hangup voice call\n");
65                 ofono_voicecall_hangup(voice_call);
66                 afb_req_success(request, NULL, NULL);
67         } else if (incoming_call) {
68                 DEBUG(interface, "Reject incoming call\n");
69                 ofono_voicecall_hangup(incoming_call);
70                 afb_req_success(request, NULL, NULL);
71         } else {
72                 ERROR(interface, "Hangup: no active call");
73                 afb_req_fail(request, "failed hangup", NULL);
74         }
75 }
76
77 static void answer(struct afb_req request)
78 {
79         if (incoming_call) {
80                 DEBUG(interface, "Answer voice call\n");
81                 voice_call = incoming_call;
82                 ofono_voicecall_answer(voice_call);
83         } else {
84                 ERROR(interface, "Answer: no incoming call");
85         }
86 }
87
88 static void call_state_changed_cb(OrgOfonoVoiceCall *vc, gchar *state)
89 {
90         struct json_object *call_state;
91         call_state = json_object_new_object();
92         json_object_object_add(call_state, "state", json_object_new_string(state));
93         afb_daemon_broadcast_event(interface->daemon, "callStateChanged", call_state);
94 }
95
96 static void incoming_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar *clip)
97 {
98         struct json_object *call_info;
99
100         call_info = json_object_new_object();
101         json_object_object_add(call_info, "clip", json_object_new_string(clip));
102         afb_daemon_broadcast_event(interface->daemon, "incomingCall", call_info);
103         incoming_call = ofono_voicecall_new(interface, op, call_state_changed_cb);
104 }
105
106 static void dialing_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op, gchar *colp)
107 {
108         struct json_object *call_info;
109
110         call_info = json_object_new_object();
111         json_object_object_add(call_info, "colp", json_object_new_string(colp));
112         afb_daemon_broadcast_event(interface->daemon, "dialingCall", call_info);
113         voice_call = ofono_voicecall_new(interface, op, call_state_changed_cb);
114 }
115
116 static void terminated_call_cb(OrgOfonoVoiceCallManager *manager, gchar *op)
117 {
118         if (incoming_call) {
119                 ofono_voicecall_free(incoming_call);
120                 incoming_call = NULL;
121         } else if (voice_call) {
122                 ofono_voicecall_free(voice_call);
123         }
124         voice_call = NULL;
125
126         afb_daemon_broadcast_event(interface->daemon, "terminatedCall", NULL);
127 }
128
129 static void *main_loop_thread(void *unused)
130 {
131         GMainLoop *loop = g_main_loop_new(NULL, FALSE);
132         g_main_loop_run(loop);
133         return NULL;
134 }
135
136 static int ofono_init(void)
137 {
138         pthread_t tid;
139         int ret = 0;
140
141         /* Start the main loop thread */
142         pthread_create(&tid, NULL, main_loop_thread, NULL);
143
144         ret = ofono_manager_init(interface);
145         if (ret == 0) {
146                 const gchar *modem_path = ofono_manager_get_default_modem_path();
147                 if (modem_path) {
148                         DEBUG(interface, "modem_path: %s\n", modem_path);
149                         vcm = ofono_voicecallmanager_init(interface, modem_path,
150                                         incoming_call_cb,
151                                         dialing_call_cb,
152                                         terminated_call_cb);
153                         if (!vcm) {
154                                 ERROR(interface, "[telephony] failed to initialize voice call manager\n");
155                                 ret = -1;
156                         }
157                 } else {
158                         ERROR(interface, "[telephony] default modem not set\n");
159                         ret = -1;
160                 }
161         } else {
162                 ERROR(interface, "[telephony] failed to initialize ofono manager: " \
163                                  "HFP device not connected or Bluetooth disabled\n");
164         }
165
166         return ret;
167 }
168
169 static const struct afb_verb_desc_v1 verbs[]= {
170         {
171                 .name           = "dial",
172                 .session        = AFB_SESSION_NONE,
173                 .callback       = dial,
174                 .info           = "Dial phone"
175         },
176         {
177                 .name           = "hangup",
178                 .session        = AFB_SESSION_NONE,
179                 .callback       = hangup,
180                 .info           = "Hangup phone"
181         },
182         {
183                 .name           = "answer",
184                 .session        = AFB_SESSION_NONE,
185                 .callback       = answer,
186                 .info           = "Answer phone"
187         },
188         {NULL}
189 };
190
191 static const struct afb_binding binding_desc = {
192         .type = AFB_BINDING_VERSION_1,
193         .v1 = {
194                 .info = "telephony service",
195                 .prefix = "telephony",
196                 .verbs = verbs
197         }
198 };
199
200 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
201 {
202         interface = itf;
203
204         return &binding_desc;
205 }
206
207 int afbBindingV1ServiceInit(struct afb_service service)
208 {
209         DEBUG(interface, "Initializing telephony service\n");
210
211         return ofono_init();
212 }