diff options
Diffstat (limited to 'src/conversation/conversation_api_call.c')
-rw-r--r-- | src/conversation/conversation_api_call.c | 743 |
1 files changed, 0 insertions, 743 deletions
diff --git a/src/conversation/conversation_api_call.c b/src/conversation/conversation_api_call.c deleted file mode 100644 index 2be7886fa..000000000 --- a/src/conversation/conversation_api_call.c +++ /dev/null | |||
@@ -1,743 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2013, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file conversation/conversation_api_call.c | ||
23 | * @brief call API to the conversation service | ||
24 | * @author Simon Dieterle | ||
25 | * @author Andreas Fuchs | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_conversation_service.h" | ||
30 | #include "gnunet_gnsrecord_lib.h" | ||
31 | #include "gnunet_gns_service.h" | ||
32 | #include "conversation.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Possible states of the phone. | ||
37 | */ | ||
38 | enum CallState | ||
39 | { | ||
40 | /** | ||
41 | * We still need to lookup the callee. | ||
42 | */ | ||
43 | CS_LOOKUP = 0, | ||
44 | |||
45 | /** | ||
46 | * The call is ringing. | ||
47 | */ | ||
48 | CS_RINGING, | ||
49 | |||
50 | /** | ||
51 | * The call is in an active conversation. | ||
52 | */ | ||
53 | CS_ACTIVE, | ||
54 | |||
55 | /** | ||
56 | * The call is in termination. | ||
57 | */ | ||
58 | CS_SHUTDOWN, | ||
59 | |||
60 | /** | ||
61 | * The call was suspended by the caller. | ||
62 | */ | ||
63 | CS_SUSPENDED_CALLER, | ||
64 | |||
65 | /** | ||
66 | * The call was suspended by the callee. | ||
67 | */ | ||
68 | CS_SUSPENDED_CALLEE, | ||
69 | |||
70 | /** | ||
71 | * The call was suspended by both caller and callee. | ||
72 | */ | ||
73 | CS_SUSPENDED_BOTH | ||
74 | }; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Handle for an outgoing call. | ||
79 | */ | ||
80 | struct GNUNET_CONVERSATION_Call | ||
81 | { | ||
82 | /** | ||
83 | * Our configuration. | ||
84 | */ | ||
85 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
86 | |||
87 | /** | ||
88 | * Our caller identity. | ||
89 | */ | ||
90 | struct GNUNET_IDENTITY_Ego *caller_id; | ||
91 | |||
92 | /** | ||
93 | * Target callee as a GNS address/name. | ||
94 | */ | ||
95 | char *callee; | ||
96 | |||
97 | /** | ||
98 | * Our speaker. | ||
99 | */ | ||
100 | struct GNUNET_SPEAKER_Handle *speaker; | ||
101 | |||
102 | /** | ||
103 | * Our microphone. | ||
104 | */ | ||
105 | struct GNUNET_MICROPHONE_Handle *mic; | ||
106 | |||
107 | /** | ||
108 | * Function to call with events. | ||
109 | */ | ||
110 | GNUNET_CONVERSATION_CallEventHandler event_handler; | ||
111 | |||
112 | /** | ||
113 | * Closure for @e event_handler | ||
114 | */ | ||
115 | void *event_handler_cls; | ||
116 | |||
117 | /** | ||
118 | * Handle for transmitting to the CONVERSATION service. | ||
119 | */ | ||
120 | struct GNUNET_MQ_Handle *mq; | ||
121 | |||
122 | /** | ||
123 | * Connection to GNS (can be NULL). | ||
124 | */ | ||
125 | struct GNUNET_GNS_Handle *gns; | ||
126 | |||
127 | /** | ||
128 | * Active GNS lookup (or NULL). | ||
129 | */ | ||
130 | struct GNUNET_GNS_LookupWithTldRequest *gns_lookup; | ||
131 | |||
132 | /** | ||
133 | * Target phone record, only valid after the lookup is done. | ||
134 | */ | ||
135 | struct GNUNET_CONVERSATION_PhoneRecord phone_record; | ||
136 | |||
137 | /** | ||
138 | * State machine for the call. | ||
139 | */ | ||
140 | enum CallState state; | ||
141 | }; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * The call got disconnected, reconnect to the service. | ||
146 | * | ||
147 | * @param call call to reconnect | ||
148 | */ | ||
149 | static void | ||
150 | fail_call (struct GNUNET_CONVERSATION_Call *call); | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Process recorded audio data. | ||
155 | * | ||
156 | * @param cls closure with the `struct GNUNET_CONVERSATION_Call` | ||
157 | * @param data_size number of bytes in @a data | ||
158 | * @param data audio data to play | ||
159 | */ | ||
160 | static void | ||
161 | transmit_call_audio (void *cls, | ||
162 | size_t data_size, | ||
163 | const void *data) | ||
164 | { | ||
165 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
166 | struct GNUNET_MQ_Envelope *e; | ||
167 | struct ClientAudioMessage *am; | ||
168 | |||
169 | GNUNET_assert (CS_ACTIVE == call->state); | ||
170 | e = GNUNET_MQ_msg_extra (am, | ||
171 | data_size, | ||
172 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO); | ||
173 | GNUNET_memcpy (&am[1], | ||
174 | data, | ||
175 | data_size); | ||
176 | GNUNET_MQ_send (call->mq, | ||
177 | e); | ||
178 | } | ||
179 | |||
180 | |||
181 | /** | ||
182 | * We received a #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND. | ||
183 | * | ||
184 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
185 | * @param msg the message | ||
186 | */ | ||
187 | static void | ||
188 | handle_call_suspend (void *cls, | ||
189 | const struct ClientPhoneSuspendMessage *msg) | ||
190 | { | ||
191 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
192 | |||
193 | (void) msg; | ||
194 | switch (call->state) | ||
195 | { | ||
196 | case CS_LOOKUP: | ||
197 | GNUNET_break (0); | ||
198 | fail_call (call); | ||
199 | break; | ||
200 | |||
201 | case CS_RINGING: | ||
202 | GNUNET_break_op (0); | ||
203 | fail_call (call); | ||
204 | break; | ||
205 | |||
206 | case CS_SUSPENDED_CALLER: | ||
207 | call->state = CS_SUSPENDED_BOTH; | ||
208 | call->event_handler (call->event_handler_cls, | ||
209 | GNUNET_CONVERSATION_EC_CALL_SUSPENDED); | ||
210 | break; | ||
211 | |||
212 | case CS_SUSPENDED_CALLEE: | ||
213 | case CS_SUSPENDED_BOTH: | ||
214 | GNUNET_break_op (0); | ||
215 | break; | ||
216 | |||
217 | case CS_ACTIVE: | ||
218 | call->state = CS_SUSPENDED_CALLEE; | ||
219 | call->speaker->disable_speaker (call->speaker->cls); | ||
220 | call->mic->disable_microphone (call->mic->cls); | ||
221 | call->event_handler (call->event_handler_cls, | ||
222 | GNUNET_CONVERSATION_EC_CALL_SUSPENDED); | ||
223 | break; | ||
224 | |||
225 | case CS_SHUTDOWN: | ||
226 | GNUNET_CONVERSATION_call_stop (call); | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | |||
232 | /** | ||
233 | * We received a #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME. | ||
234 | * | ||
235 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
236 | * @param msg the message | ||
237 | */ | ||
238 | static void | ||
239 | handle_call_resume (void *cls, | ||
240 | const struct ClientPhoneResumeMessage *msg) | ||
241 | { | ||
242 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
243 | |||
244 | (void) msg; | ||
245 | switch (call->state) | ||
246 | { | ||
247 | case CS_LOOKUP: | ||
248 | GNUNET_break (0); | ||
249 | fail_call (call); | ||
250 | break; | ||
251 | |||
252 | case CS_RINGING: | ||
253 | GNUNET_break_op (0); | ||
254 | fail_call (call); | ||
255 | break; | ||
256 | |||
257 | case CS_SUSPENDED_CALLER: | ||
258 | GNUNET_break_op (0); | ||
259 | break; | ||
260 | |||
261 | case CS_SUSPENDED_CALLEE: | ||
262 | call->state = CS_ACTIVE; | ||
263 | call->speaker->enable_speaker (call->speaker->cls); | ||
264 | call->mic->enable_microphone (call->mic->cls, | ||
265 | &transmit_call_audio, | ||
266 | call); | ||
267 | call->event_handler (call->event_handler_cls, | ||
268 | GNUNET_CONVERSATION_EC_CALL_RESUMED); | ||
269 | break; | ||
270 | |||
271 | case CS_SUSPENDED_BOTH: | ||
272 | call->state = CS_SUSPENDED_CALLER; | ||
273 | call->event_handler (call->event_handler_cls, | ||
274 | GNUNET_CONVERSATION_EC_CALL_RESUMED); | ||
275 | break; | ||
276 | |||
277 | case CS_ACTIVE: | ||
278 | GNUNET_break_op (0); | ||
279 | break; | ||
280 | |||
281 | case CS_SHUTDOWN: | ||
282 | GNUNET_CONVERSATION_call_stop (call); | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | |||
288 | /** | ||
289 | * We received a #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP. | ||
290 | * | ||
291 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
292 | * @param msg the message | ||
293 | */ | ||
294 | static void | ||
295 | handle_call_picked_up (void *cls, | ||
296 | const struct ClientPhonePickedupMessage *msg) | ||
297 | { | ||
298 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
299 | |||
300 | (void) msg; | ||
301 | switch (call->state) | ||
302 | { | ||
303 | case CS_LOOKUP: | ||
304 | GNUNET_break (0); | ||
305 | fail_call (call); | ||
306 | break; | ||
307 | |||
308 | case CS_RINGING: | ||
309 | call->state = CS_ACTIVE; | ||
310 | call->speaker->enable_speaker (call->speaker->cls); | ||
311 | call->mic->enable_microphone (call->mic->cls, | ||
312 | &transmit_call_audio, | ||
313 | call); | ||
314 | call->event_handler (call->event_handler_cls, | ||
315 | GNUNET_CONVERSATION_EC_CALL_PICKED_UP); | ||
316 | break; | ||
317 | |||
318 | case CS_SUSPENDED_CALLER: | ||
319 | case CS_SUSPENDED_CALLEE: | ||
320 | case CS_SUSPENDED_BOTH: | ||
321 | case CS_ACTIVE: | ||
322 | GNUNET_break (0); | ||
323 | fail_call (call); | ||
324 | break; | ||
325 | |||
326 | case CS_SHUTDOWN: | ||
327 | GNUNET_CONVERSATION_call_stop (call); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * We received a #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_HANG_UP. | ||
335 | * | ||
336 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
337 | * @param msg the message | ||
338 | */ | ||
339 | static void | ||
340 | handle_call_hangup (void *cls, | ||
341 | const struct ClientPhoneHangupMessage *msg) | ||
342 | { | ||
343 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
344 | GNUNET_CONVERSATION_CallEventHandler eh; | ||
345 | void *eh_cls; | ||
346 | |||
347 | (void) msg; | ||
348 | switch (call->state) | ||
349 | { | ||
350 | case CS_LOOKUP: | ||
351 | GNUNET_break (0); | ||
352 | fail_call (call); | ||
353 | break; | ||
354 | |||
355 | case CS_RINGING: | ||
356 | case CS_SUSPENDED_CALLER: | ||
357 | case CS_SUSPENDED_CALLEE: | ||
358 | case CS_SUSPENDED_BOTH: | ||
359 | case CS_ACTIVE: | ||
360 | eh = call->event_handler; | ||
361 | eh_cls = call->event_handler_cls; | ||
362 | GNUNET_CONVERSATION_call_stop (call); | ||
363 | eh (eh_cls, | ||
364 | GNUNET_CONVERSATION_EC_CALL_HUNG_UP); | ||
365 | return; | ||
366 | |||
367 | case CS_SHUTDOWN: | ||
368 | GNUNET_CONVERSATION_call_stop (call); | ||
369 | break; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | |||
374 | /** | ||
375 | * We received a `struct ClientAudioMessage`, check it is well-formed. | ||
376 | * | ||
377 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
378 | * @param msg the message | ||
379 | * @return #GNUNET_OK (always well-formed) | ||
380 | */ | ||
381 | static int | ||
382 | check_call_audio (void *cls, | ||
383 | const struct ClientAudioMessage *am) | ||
384 | { | ||
385 | (void) cls; | ||
386 | (void) am; | ||
387 | /* any payload is OK */ | ||
388 | return GNUNET_OK; | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * We received a `struct ClientAudioMessage` | ||
394 | * | ||
395 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
396 | * @param msg the message | ||
397 | */ | ||
398 | static void | ||
399 | handle_call_audio (void *cls, | ||
400 | const struct ClientAudioMessage *am) | ||
401 | { | ||
402 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
403 | |||
404 | switch (call->state) | ||
405 | { | ||
406 | case CS_LOOKUP: | ||
407 | GNUNET_break (0); | ||
408 | fail_call (call); | ||
409 | break; | ||
410 | |||
411 | case CS_RINGING: | ||
412 | GNUNET_break (0); | ||
413 | fail_call (call); | ||
414 | break; | ||
415 | |||
416 | case CS_SUSPENDED_CALLER: | ||
417 | /* can happen: we suspended, other peer did not yet | ||
418 | learn about this. */ | ||
419 | break; | ||
420 | |||
421 | case CS_SUSPENDED_CALLEE: | ||
422 | case CS_SUSPENDED_BOTH: | ||
423 | /* can (rarely) also happen: other peer suspended, but cadet might | ||
424 | have had delayed data on the unreliable channel */ | ||
425 | break; | ||
426 | |||
427 | case CS_ACTIVE: | ||
428 | call->speaker->play (call->speaker->cls, | ||
429 | ntohs (am->header.size) - sizeof(struct | ||
430 | ClientAudioMessage), | ||
431 | &am[1]); | ||
432 | break; | ||
433 | |||
434 | case CS_SHUTDOWN: | ||
435 | GNUNET_CONVERSATION_call_stop (call); | ||
436 | break; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Iterator called on obtained result for a GNS lookup. | ||
443 | * | ||
444 | * @param cls closure with the `struct GNUNET_CONVERSATION_Call` | ||
445 | * @param was_gns #GNUNET_NO if name was not a GNS name | ||
446 | * @param rd_count number of records in @a rd | ||
447 | * @param rd the records in reply | ||
448 | */ | ||
449 | static void | ||
450 | handle_gns_response (void *cls, | ||
451 | int was_gns, | ||
452 | uint32_t rd_count, | ||
453 | const struct GNUNET_GNSRECORD_Data *rd) | ||
454 | { | ||
455 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
456 | struct GNUNET_MQ_Envelope *e; | ||
457 | struct ClientCallMessage *ccm; | ||
458 | |||
459 | (void) was_gns; | ||
460 | GNUNET_break (NULL != call->gns_lookup); | ||
461 | GNUNET_break (CS_LOOKUP == call->state); | ||
462 | call->gns_lookup = NULL; | ||
463 | for (uint32_t i = 0; i < rd_count; i++) | ||
464 | { | ||
465 | if (GNUNET_GNSRECORD_TYPE_PHONE == rd[i].record_type) | ||
466 | { | ||
467 | if (rd[i].data_size != sizeof(struct GNUNET_CONVERSATION_PhoneRecord)) | ||
468 | { | ||
469 | GNUNET_break_op (0); | ||
470 | continue; | ||
471 | } | ||
472 | GNUNET_memcpy (&call->phone_record, | ||
473 | rd[i].data, | ||
474 | rd[i].data_size); | ||
475 | e = GNUNET_MQ_msg (ccm, | ||
476 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL); | ||
477 | ccm->line_port = call->phone_record.line_port; | ||
478 | ccm->target = call->phone_record.peer; | ||
479 | ccm->caller_id = *GNUNET_IDENTITY_ego_get_private_key (call->caller_id); | ||
480 | GNUNET_MQ_send (call->mq, | ||
481 | e); | ||
482 | call->state = CS_RINGING; | ||
483 | call->event_handler (call->event_handler_cls, | ||
484 | GNUNET_CONVERSATION_EC_CALL_RINGING); | ||
485 | return; | ||
486 | } | ||
487 | } | ||
488 | /* not found */ | ||
489 | call->event_handler (call->event_handler_cls, | ||
490 | GNUNET_CONVERSATION_EC_CALL_GNS_FAIL); | ||
491 | GNUNET_CONVERSATION_call_stop (call); | ||
492 | } | ||
493 | |||
494 | |||
495 | /** | ||
496 | * We encountered an error talking with the conversation service. | ||
497 | * | ||
498 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
499 | * @param error details about the error | ||
500 | */ | ||
501 | static void | ||
502 | call_error_handler (void *cls, | ||
503 | enum GNUNET_MQ_Error error) | ||
504 | { | ||
505 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
506 | |||
507 | (void) error; | ||
508 | if (CS_SHUTDOWN == call->state) | ||
509 | { | ||
510 | GNUNET_CONVERSATION_call_stop (call); | ||
511 | return; | ||
512 | } | ||
513 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
514 | _ ( | ||
515 | "Connection to conversation service lost, trying to reconnect\n")); | ||
516 | fail_call (call); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * The call got disconnected, destroy the handle. | ||
522 | * | ||
523 | * @param call call to reconnect | ||
524 | */ | ||
525 | static void | ||
526 | fail_call (struct GNUNET_CONVERSATION_Call *call) | ||
527 | { | ||
528 | if (CS_ACTIVE == call->state) | ||
529 | { | ||
530 | call->speaker->disable_speaker (call->speaker->cls); | ||
531 | call->mic->disable_microphone (call->mic->cls); | ||
532 | } | ||
533 | if (NULL != call->mq) | ||
534 | { | ||
535 | GNUNET_MQ_destroy (call->mq); | ||
536 | call->mq = NULL; | ||
537 | } | ||
538 | call->state = CS_SHUTDOWN; | ||
539 | call->event_handler (call->event_handler_cls, | ||
540 | GNUNET_CONVERSATION_EC_CALL_ERROR); | ||
541 | GNUNET_CONVERSATION_call_stop (call); | ||
542 | } | ||
543 | |||
544 | |||
545 | /** | ||
546 | * Call the phone of another user. | ||
547 | * | ||
548 | * @param cfg configuration to use, specifies our phone service | ||
549 | * @param caller_id identity of the caller | ||
550 | * @param callee GNS name of the callee (used to locate the callee's record) | ||
551 | * @param speaker speaker to use (will be used automatically immediately once the | ||
552 | * #GNUNET_CONVERSATION_EC_CALL_PICKED_UP event is generated); we will NOT generate | ||
553 | * a ring tone on the speaker | ||
554 | * @param mic microphone to use (will be used automatically immediately once the | ||
555 | * #GNUNET_CONVERSATION_EC_CALL_PICKED_UP event is generated) | ||
556 | * @param event_handler how to notify the owner of the phone about events | ||
557 | * @param event_handler_cls closure for @a event_handler | ||
558 | * @return handle for the call, NULL on hard errors | ||
559 | */ | ||
560 | struct GNUNET_CONVERSATION_Call * | ||
561 | GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
562 | struct GNUNET_IDENTITY_Ego *caller_id, | ||
563 | const char *callee, | ||
564 | struct GNUNET_SPEAKER_Handle *speaker, | ||
565 | struct GNUNET_MICROPHONE_Handle *mic, | ||
566 | GNUNET_CONVERSATION_CallEventHandler | ||
567 | event_handler, | ||
568 | void *event_handler_cls) | ||
569 | { | ||
570 | struct GNUNET_CONVERSATION_Call *call | ||
571 | = GNUNET_new (struct GNUNET_CONVERSATION_Call); | ||
572 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
573 | GNUNET_MQ_hd_fixed_size (call_suspend, | ||
574 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND, | ||
575 | struct ClientPhoneSuspendMessage, | ||
576 | call), | ||
577 | GNUNET_MQ_hd_fixed_size (call_resume, | ||
578 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME, | ||
579 | struct ClientPhoneResumeMessage, | ||
580 | call), | ||
581 | GNUNET_MQ_hd_fixed_size (call_picked_up, | ||
582 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP, | ||
583 | struct ClientPhonePickedupMessage, | ||
584 | call), | ||
585 | GNUNET_MQ_hd_fixed_size (call_hangup, | ||
586 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, | ||
587 | struct ClientPhoneHangupMessage, | ||
588 | call), | ||
589 | GNUNET_MQ_hd_var_size (call_audio, | ||
590 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, | ||
591 | struct ClientAudioMessage, | ||
592 | call), | ||
593 | GNUNET_MQ_handler_end () | ||
594 | }; | ||
595 | |||
596 | call->mq = GNUNET_CLIENT_connect (cfg, | ||
597 | "conversation", | ||
598 | handlers, | ||
599 | &call_error_handler, | ||
600 | call); | ||
601 | if (NULL == call->mq) | ||
602 | { | ||
603 | GNUNET_break (0); | ||
604 | GNUNET_free (call); | ||
605 | return NULL; | ||
606 | } | ||
607 | call->cfg = cfg; | ||
608 | call->caller_id = caller_id; | ||
609 | call->callee = GNUNET_strdup (callee); | ||
610 | call->speaker = speaker; | ||
611 | call->mic = mic; | ||
612 | call->event_handler = event_handler; | ||
613 | call->event_handler_cls = event_handler_cls; | ||
614 | call->gns = GNUNET_GNS_connect (cfg); | ||
615 | if (NULL == call->gns) | ||
616 | { | ||
617 | GNUNET_CONVERSATION_call_stop (call); | ||
618 | return NULL; | ||
619 | } | ||
620 | call->state = CS_LOOKUP; | ||
621 | call->gns_lookup = GNUNET_GNS_lookup_with_tld (call->gns, | ||
622 | call->callee, | ||
623 | GNUNET_GNSRECORD_TYPE_PHONE, | ||
624 | GNUNET_NO, | ||
625 | &handle_gns_response, | ||
626 | call); | ||
627 | if (NULL == call->gns_lookup) | ||
628 | { | ||
629 | GNUNET_CONVERSATION_call_stop (call); | ||
630 | return NULL; | ||
631 | } | ||
632 | return call; | ||
633 | } | ||
634 | |||
635 | |||
636 | /** | ||
637 | * Terminate a call. The call may be ringing or ready at this time. | ||
638 | * | ||
639 | * @param call call to terminate | ||
640 | */ | ||
641 | void | ||
642 | GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call) | ||
643 | { | ||
644 | if ((NULL != call->speaker) && | ||
645 | (CS_ACTIVE == call->state)) | ||
646 | call->speaker->disable_speaker (call->speaker->cls); | ||
647 | if ((NULL != call->mic) && | ||
648 | (CS_ACTIVE == call->state)) | ||
649 | call->mic->disable_microphone (call->mic->cls); | ||
650 | if (CS_SHUTDOWN != call->state) | ||
651 | { | ||
652 | call->state = CS_SHUTDOWN; | ||
653 | } | ||
654 | if (NULL != call->mq) | ||
655 | { | ||
656 | GNUNET_MQ_destroy (call->mq); | ||
657 | call->mq = NULL; | ||
658 | } | ||
659 | if (NULL != call->gns_lookup) | ||
660 | { | ||
661 | GNUNET_GNS_lookup_with_tld_cancel (call->gns_lookup); | ||
662 | call->gns_lookup = NULL; | ||
663 | } | ||
664 | if (NULL != call->gns) | ||
665 | { | ||
666 | GNUNET_GNS_disconnect (call->gns); | ||
667 | call->gns = NULL; | ||
668 | } | ||
669 | GNUNET_free (call->callee); | ||
670 | GNUNET_free (call); | ||
671 | } | ||
672 | |||
673 | |||
674 | /** | ||
675 | * Pause a call. Temporarily suspends the use of speaker and | ||
676 | * microphone. | ||
677 | * | ||
678 | * @param call call to pause | ||
679 | */ | ||
680 | void | ||
681 | GNUNET_CONVERSATION_call_suspend (struct GNUNET_CONVERSATION_Call *call) | ||
682 | { | ||
683 | struct GNUNET_MQ_Envelope *e; | ||
684 | struct ClientPhoneSuspendMessage *suspend; | ||
685 | |||
686 | GNUNET_assert ((CS_SUSPENDED_CALLEE == call->state) || | ||
687 | (CS_ACTIVE == call->state)); | ||
688 | if (CS_ACTIVE == call->state) | ||
689 | { | ||
690 | call->speaker->disable_speaker (call->speaker->cls); | ||
691 | call->mic->disable_microphone (call->mic->cls); | ||
692 | } | ||
693 | call->speaker = NULL; | ||
694 | call->mic = NULL; | ||
695 | e = GNUNET_MQ_msg (suspend, | ||
696 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND); | ||
697 | GNUNET_MQ_send (call->mq, | ||
698 | e); | ||
699 | if (CS_SUSPENDED_CALLER == call->state) | ||
700 | call->state = CS_SUSPENDED_BOTH; | ||
701 | else | ||
702 | call->state = CS_SUSPENDED_CALLER; | ||
703 | } | ||
704 | |||
705 | |||
706 | /** | ||
707 | * Resumes a call after #GNUNET_CONVERSATION_call_suspend. | ||
708 | * | ||
709 | * @param call call to resume | ||
710 | * @param speaker speaker to use | ||
711 | * a ring tone on the speaker | ||
712 | * @param mic microphone to use | ||
713 | */ | ||
714 | void | ||
715 | GNUNET_CONVERSATION_call_resume (struct GNUNET_CONVERSATION_Call *call, | ||
716 | struct GNUNET_SPEAKER_Handle *speaker, | ||
717 | struct GNUNET_MICROPHONE_Handle *mic) | ||
718 | { | ||
719 | struct GNUNET_MQ_Envelope *e; | ||
720 | struct ClientPhoneResumeMessage *resume; | ||
721 | |||
722 | GNUNET_assert ((CS_SUSPENDED_CALLER == call->state) || | ||
723 | (CS_SUSPENDED_BOTH == call->state)); | ||
724 | e = GNUNET_MQ_msg (resume, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME); | ||
725 | GNUNET_MQ_send (call->mq, e); | ||
726 | call->speaker = speaker; | ||
727 | call->mic = mic; | ||
728 | if (CS_SUSPENDED_CALLER == call->state) | ||
729 | { | ||
730 | call->state = CS_ACTIVE; | ||
731 | call->speaker->enable_speaker (call->speaker->cls); | ||
732 | call->mic->enable_microphone (call->mic->cls, | ||
733 | &transmit_call_audio, | ||
734 | call); | ||
735 | } | ||
736 | else | ||
737 | { | ||
738 | call->state = CS_SUSPENDED_CALLEE; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | |||
743 | /* end of conversation_api_call.c */ | ||