diff options
Diffstat (limited to 'src/conversation/conversation_api.c')
-rw-r--r-- | src/conversation/conversation_api.c | 871 |
1 files changed, 0 insertions, 871 deletions
diff --git a/src/conversation/conversation_api.c b/src/conversation/conversation_api.c deleted file mode 100644 index 1984abdd6..000000000 --- a/src/conversation/conversation_api.c +++ /dev/null | |||
@@ -1,871 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2013, 2014 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.c | ||
23 | * @brief phone and caller 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 "conversation.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Possible states of a caller. | ||
35 | */ | ||
36 | enum CallerState | ||
37 | { | ||
38 | /** | ||
39 | * The phone is ringing (user knows about incoming call). | ||
40 | */ | ||
41 | CS_RINGING, | ||
42 | |||
43 | /** | ||
44 | * The phone is in an active conversation. | ||
45 | */ | ||
46 | CS_ACTIVE, | ||
47 | |||
48 | /** | ||
49 | * We suspended the conversation. | ||
50 | */ | ||
51 | CS_CALLEE_SUSPENDED, | ||
52 | |||
53 | /** | ||
54 | * Caller suspended the conversation. | ||
55 | */ | ||
56 | CS_CALLER_SUSPENDED, | ||
57 | |||
58 | /** | ||
59 | * Both sides suspended the conversation. | ||
60 | */ | ||
61 | CS_BOTH_SUSPENDED | ||
62 | }; | ||
63 | |||
64 | |||
65 | /** | ||
66 | * A caller is the handle we have for an incoming call. | ||
67 | */ | ||
68 | struct GNUNET_CONVERSATION_Caller | ||
69 | { | ||
70 | /** | ||
71 | * We keep all callers in a DLL. | ||
72 | */ | ||
73 | struct GNUNET_CONVERSATION_Caller *next; | ||
74 | |||
75 | /** | ||
76 | * We keep all callers in a DLL. | ||
77 | */ | ||
78 | struct GNUNET_CONVERSATION_Caller *prev; | ||
79 | |||
80 | /** | ||
81 | * Our phone. | ||
82 | */ | ||
83 | struct GNUNET_CONVERSATION_Phone *phone; | ||
84 | |||
85 | /** | ||
86 | * Function to call for phone events. | ||
87 | */ | ||
88 | GNUNET_CONVERSATION_CallerEventHandler event_handler; | ||
89 | |||
90 | /** | ||
91 | * Closure for @e event_handler | ||
92 | */ | ||
93 | void *event_handler_cls; | ||
94 | |||
95 | /** | ||
96 | * Speaker, or NULL if none is attached. | ||
97 | */ | ||
98 | struct GNUNET_SPEAKER_Handle *speaker; | ||
99 | |||
100 | /** | ||
101 | * Microphone, or NULL if none is attached. | ||
102 | */ | ||
103 | struct GNUNET_MICROPHONE_Handle *mic; | ||
104 | |||
105 | /** | ||
106 | * Identity of the person calling us. | ||
107 | */ | ||
108 | struct GNUNET_IDENTITY_PublicKey caller_id; | ||
109 | |||
110 | /** | ||
111 | * Internal handle to identify the caller with the service. | ||
112 | */ | ||
113 | uint32_t cid; | ||
114 | |||
115 | /** | ||
116 | * State machine for the phone. | ||
117 | */ | ||
118 | enum CallerState state; | ||
119 | }; | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Possible states of a phone. | ||
124 | */ | ||
125 | enum PhoneState | ||
126 | { | ||
127 | /** | ||
128 | * We still need to register the phone. | ||
129 | */ | ||
130 | PS_REGISTER = 0, | ||
131 | |||
132 | /** | ||
133 | * We are waiting for calls. | ||
134 | */ | ||
135 | PS_READY | ||
136 | }; | ||
137 | |||
138 | |||
139 | /** | ||
140 | * A phone is a device that can ring to signal an incoming call and | ||
141 | * that you can pick up to answer the call and hang up to terminate | ||
142 | * the call. You can also hang up a ringing phone immediately | ||
143 | * (without picking it up) to stop it from ringing. Phones have | ||
144 | * caller ID. You can ask the phone for its record and make that | ||
145 | * record available (via GNS) to enable others to call you. | ||
146 | * Multiple phones maybe connected to the same line (the line is | ||
147 | * something rather internal to a phone and not obvious from it). | ||
148 | * You can only have one conversation per phone at any time. | ||
149 | */ | ||
150 | struct GNUNET_CONVERSATION_Phone | ||
151 | { | ||
152 | /** | ||
153 | * Our configuration. | ||
154 | */ | ||
155 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
156 | |||
157 | /** | ||
158 | * We keep all callers in a DLL. | ||
159 | */ | ||
160 | struct GNUNET_CONVERSATION_Caller *caller_head; | ||
161 | |||
162 | /** | ||
163 | * We keep all callers in a DLL. | ||
164 | */ | ||
165 | struct GNUNET_CONVERSATION_Caller *caller_tail; | ||
166 | |||
167 | /** | ||
168 | * Function to call for phone events. | ||
169 | */ | ||
170 | GNUNET_CONVERSATION_PhoneEventHandler event_handler; | ||
171 | |||
172 | /** | ||
173 | * Closure for @e event_handler | ||
174 | */ | ||
175 | void *event_handler_cls; | ||
176 | |||
177 | /** | ||
178 | * Connection to NAMESTORE (for reverse lookup). | ||
179 | */ | ||
180 | struct GNUNET_NAMESTORE_Handle *ns; | ||
181 | |||
182 | /** | ||
183 | * Handle for transmitting to the CONVERSATION service. | ||
184 | */ | ||
185 | struct GNUNET_MQ_Handle *mq; | ||
186 | |||
187 | /** | ||
188 | * This phone's record. | ||
189 | */ | ||
190 | struct GNUNET_CONVERSATION_PhoneRecord my_record; | ||
191 | |||
192 | /** | ||
193 | * My GNS zone. | ||
194 | */ | ||
195 | struct GNUNET_IDENTITY_PrivateKey my_zone; | ||
196 | |||
197 | /** | ||
198 | * State machine for the phone. | ||
199 | */ | ||
200 | enum PhoneState state; | ||
201 | }; | ||
202 | |||
203 | |||
204 | /** | ||
205 | * The phone got disconnected, reconnect to the service. | ||
206 | * | ||
207 | * @param phone phone to reconnect | ||
208 | */ | ||
209 | static void | ||
210 | reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone); | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Process recorded audio data. | ||
215 | * | ||
216 | * @param cls closure with the `struct GNUNET_CONVERSATION_Caller` | ||
217 | * @param data_size number of bytes in @a data | ||
218 | * @param data audio data to play | ||
219 | */ | ||
220 | static void | ||
221 | transmit_phone_audio (void *cls, | ||
222 | size_t data_size, | ||
223 | const void *data) | ||
224 | { | ||
225 | struct GNUNET_CONVERSATION_Caller *caller = cls; | ||
226 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
227 | struct GNUNET_MQ_Envelope *e; | ||
228 | struct ClientAudioMessage *am; | ||
229 | |||
230 | e = GNUNET_MQ_msg_extra (am, | ||
231 | data_size, | ||
232 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO); | ||
233 | am->cid = caller->cid; | ||
234 | GNUNET_memcpy (&am[1], | ||
235 | data, | ||
236 | data_size); | ||
237 | GNUNET_MQ_send (phone->mq, | ||
238 | e); | ||
239 | } | ||
240 | |||
241 | |||
242 | /** | ||
243 | * We received a `struct ClientPhoneRingMessage` | ||
244 | * | ||
245 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
246 | * @param ring the message | ||
247 | */ | ||
248 | static void | ||
249 | handle_phone_ring (void *cls, | ||
250 | const struct ClientPhoneRingMessage *ring) | ||
251 | { | ||
252 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
253 | struct GNUNET_CONVERSATION_Caller *caller; | ||
254 | |||
255 | switch (phone->state) | ||
256 | { | ||
257 | case PS_REGISTER: | ||
258 | GNUNET_assert (0); | ||
259 | break; | ||
260 | |||
261 | case PS_READY: | ||
262 | caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller); | ||
263 | caller->phone = phone; | ||
264 | GNUNET_CONTAINER_DLL_insert (phone->caller_head, | ||
265 | phone->caller_tail, | ||
266 | caller); | ||
267 | caller->caller_id = ring->caller_id; | ||
268 | caller->cid = ring->cid; | ||
269 | caller->state = CS_RINGING; | ||
270 | phone->event_handler (phone->event_handler_cls, | ||
271 | GNUNET_CONVERSATION_EC_PHONE_RING, | ||
272 | caller, | ||
273 | &caller->caller_id); | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Find the record of the caller matching the @a cid | ||
281 | * | ||
282 | * @param phone phone to search | ||
283 | * @param cid caller ID to search for (in NBO) | ||
284 | * @return NULL if @a cid was not found | ||
285 | */ | ||
286 | static struct GNUNET_CONVERSATION_Caller * | ||
287 | find_caller (struct GNUNET_CONVERSATION_Phone *phone, | ||
288 | uint32_t cid) | ||
289 | { | ||
290 | struct GNUNET_CONVERSATION_Caller *caller; | ||
291 | |||
292 | for (caller = phone->caller_head; NULL != caller; caller = caller->next) | ||
293 | if (cid == caller->cid) | ||
294 | return caller; | ||
295 | return NULL; | ||
296 | } | ||
297 | |||
298 | |||
299 | /** | ||
300 | * We received a `struct ClientPhoneHangupMessage`. | ||
301 | * | ||
302 | * @param cls the `struct GNUNET_CONVERSATION_Phone *` | ||
303 | * @param msg the message | ||
304 | */ | ||
305 | static void | ||
306 | handle_phone_hangup (void *cls, | ||
307 | const struct ClientPhoneHangupMessage *hang) | ||
308 | { | ||
309 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
310 | struct GNUNET_CONVERSATION_Caller *caller; | ||
311 | |||
312 | caller = find_caller (phone, | ||
313 | hang->cid); | ||
314 | if (NULL == caller) | ||
315 | { | ||
316 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
317 | "Received HANG_UP message for unknown caller ID %u\n", | ||
318 | (unsigned int) hang->cid); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
323 | "Received HANG_UP message, terminating call with `%s'\n", | ||
324 | GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id)); | ||
325 | switch (caller->state) | ||
326 | { | ||
327 | case CS_RINGING: | ||
328 | phone->event_handler (phone->event_handler_cls, | ||
329 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, | ||
330 | caller, | ||
331 | &caller->caller_id); | ||
332 | break; | ||
333 | |||
334 | case CS_ACTIVE: | ||
335 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
336 | caller->mic->disable_microphone (caller->mic->cls); | ||
337 | phone->event_handler (phone->event_handler_cls, | ||
338 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, | ||
339 | caller, | ||
340 | &caller->caller_id); | ||
341 | break; | ||
342 | |||
343 | case CS_CALLEE_SUSPENDED: | ||
344 | case CS_CALLER_SUSPENDED: | ||
345 | case CS_BOTH_SUSPENDED: | ||
346 | phone->event_handler (phone->event_handler_cls, | ||
347 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, | ||
348 | caller, | ||
349 | &caller->caller_id); | ||
350 | break; | ||
351 | } | ||
352 | GNUNET_CONTAINER_DLL_remove (phone->caller_head, | ||
353 | phone->caller_tail, | ||
354 | caller); | ||
355 | GNUNET_free (caller); | ||
356 | } | ||
357 | |||
358 | |||
359 | /** | ||
360 | * We received a `struct ClientPhoneSuspendMessage`. | ||
361 | * | ||
362 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
363 | * @param suspend the message | ||
364 | */ | ||
365 | static void | ||
366 | handle_phone_suspend (void *cls, | ||
367 | const struct ClientPhoneSuspendMessage *suspend) | ||
368 | { | ||
369 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
370 | struct GNUNET_CONVERSATION_Caller *caller; | ||
371 | |||
372 | caller = find_caller (phone, | ||
373 | suspend->cid); | ||
374 | if (NULL == caller) | ||
375 | return; | ||
376 | switch (caller->state) | ||
377 | { | ||
378 | case CS_RINGING: | ||
379 | GNUNET_break_op (0); | ||
380 | break; | ||
381 | |||
382 | case CS_ACTIVE: | ||
383 | caller->state = CS_CALLER_SUSPENDED; | ||
384 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
385 | caller->mic->disable_microphone (caller->mic->cls); | ||
386 | caller->event_handler (caller->event_handler_cls, | ||
387 | GNUNET_CONVERSATION_EC_CALLER_SUSPEND); | ||
388 | break; | ||
389 | |||
390 | case CS_CALLEE_SUSPENDED: | ||
391 | caller->state = CS_BOTH_SUSPENDED; | ||
392 | caller->event_handler (caller->event_handler_cls, | ||
393 | GNUNET_CONVERSATION_EC_CALLER_SUSPEND); | ||
394 | break; | ||
395 | |||
396 | case CS_CALLER_SUSPENDED: | ||
397 | case CS_BOTH_SUSPENDED: | ||
398 | GNUNET_break_op (0); | ||
399 | break; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | |||
404 | /** | ||
405 | * We received a `struct ClientPhoneResumeMessage`. | ||
406 | * | ||
407 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
408 | * @param resume the message | ||
409 | */ | ||
410 | static void | ||
411 | handle_phone_resume (void *cls, | ||
412 | const struct ClientPhoneResumeMessage *resume) | ||
413 | { | ||
414 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
415 | struct GNUNET_CONVERSATION_Caller *caller; | ||
416 | |||
417 | caller = find_caller (phone, | ||
418 | resume->cid); | ||
419 | if (NULL == caller) | ||
420 | return; | ||
421 | switch (caller->state) | ||
422 | { | ||
423 | case CS_RINGING: | ||
424 | GNUNET_break_op (0); | ||
425 | break; | ||
426 | |||
427 | case CS_ACTIVE: | ||
428 | case CS_CALLEE_SUSPENDED: | ||
429 | GNUNET_break_op (0); | ||
430 | break; | ||
431 | |||
432 | case CS_CALLER_SUSPENDED: | ||
433 | caller->state = CS_ACTIVE; | ||
434 | caller->speaker->enable_speaker (caller->speaker->cls); | ||
435 | caller->mic->enable_microphone (caller->mic->cls, | ||
436 | &transmit_phone_audio, | ||
437 | caller); | ||
438 | caller->event_handler (caller->event_handler_cls, | ||
439 | GNUNET_CONVERSATION_EC_CALLER_RESUME); | ||
440 | break; | ||
441 | |||
442 | case CS_BOTH_SUSPENDED: | ||
443 | caller->state = CS_CALLEE_SUSPENDED; | ||
444 | caller->event_handler (caller->event_handler_cls, | ||
445 | GNUNET_CONVERSATION_EC_CALLER_RESUME); | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | |||
451 | /** | ||
452 | * We received a `struct ClientAudioMessage`, check it is well-formed. | ||
453 | * | ||
454 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
455 | * @param am the message | ||
456 | * @return #GNUNET_OK if @a am is well-formed | ||
457 | */ | ||
458 | static int | ||
459 | check_phone_audio (void *cls, | ||
460 | const struct ClientAudioMessage *am) | ||
461 | { | ||
462 | (void) cls; | ||
463 | (void) am; | ||
464 | |||
465 | /* any variable-size payload is OK */ | ||
466 | return GNUNET_OK; | ||
467 | } | ||
468 | |||
469 | |||
470 | /** | ||
471 | * We received a `struct ClientAudioMessage` | ||
472 | * | ||
473 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
474 | * @param am the message | ||
475 | */ | ||
476 | static void | ||
477 | handle_phone_audio (void *cls, | ||
478 | const struct ClientAudioMessage *am) | ||
479 | { | ||
480 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
481 | struct GNUNET_CONVERSATION_Caller *caller; | ||
482 | |||
483 | caller = find_caller (phone, | ||
484 | am->cid); | ||
485 | if (NULL == caller) | ||
486 | return; | ||
487 | switch (caller->state) | ||
488 | { | ||
489 | case CS_RINGING: | ||
490 | GNUNET_break_op (0); | ||
491 | break; | ||
492 | |||
493 | case CS_ACTIVE: | ||
494 | caller->speaker->play (caller->speaker->cls, | ||
495 | ntohs (am->header.size) - sizeof(struct | ||
496 | ClientAudioMessage), | ||
497 | &am[1]); | ||
498 | break; | ||
499 | |||
500 | case CS_CALLEE_SUSPENDED: | ||
501 | case CS_CALLER_SUSPENDED: | ||
502 | case CS_BOTH_SUSPENDED: | ||
503 | break; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | |||
508 | /** | ||
509 | * We encountered an error talking with the conversation service. | ||
510 | * | ||
511 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
512 | * @param error details about the error | ||
513 | */ | ||
514 | static void | ||
515 | phone_error_handler (void *cls, | ||
516 | enum GNUNET_MQ_Error error) | ||
517 | { | ||
518 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
519 | |||
520 | (void) error; | ||
521 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
522 | _ ( | ||
523 | "Connection to conversation service lost, trying to reconnect\n")); | ||
524 | reconnect_phone (phone); | ||
525 | } | ||
526 | |||
527 | |||
528 | /** | ||
529 | * Clean up all callers of the given phone. | ||
530 | * | ||
531 | * @param phone phone to clean up callers for | ||
532 | */ | ||
533 | static void | ||
534 | clean_up_callers (struct GNUNET_CONVERSATION_Phone *phone) | ||
535 | { | ||
536 | struct GNUNET_CONVERSATION_Caller *caller; | ||
537 | |||
538 | while (NULL != (caller = phone->caller_head)) | ||
539 | { | ||
540 | /* make sure mic/speaker are disabled *before* callback */ | ||
541 | if (CS_ACTIVE == caller->state) | ||
542 | { | ||
543 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
544 | caller->mic->disable_microphone (caller->mic->cls); | ||
545 | caller->state = CS_CALLER_SUSPENDED; | ||
546 | } | ||
547 | phone->event_handler (phone->event_handler_cls, | ||
548 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, | ||
549 | caller, | ||
550 | &caller->caller_id); | ||
551 | GNUNET_CONVERSATION_caller_hang_up (caller); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * The phone got disconnected, reconnect to the service. | ||
558 | * | ||
559 | * @param phone phone to reconnect | ||
560 | */ | ||
561 | static void | ||
562 | reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone) | ||
563 | { | ||
564 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
565 | GNUNET_MQ_hd_fixed_size (phone_ring, | ||
566 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING, | ||
567 | struct ClientPhoneRingMessage, | ||
568 | phone), | ||
569 | GNUNET_MQ_hd_fixed_size (phone_hangup, | ||
570 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, | ||
571 | struct ClientPhoneHangupMessage, | ||
572 | phone), | ||
573 | GNUNET_MQ_hd_fixed_size (phone_suspend, | ||
574 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND, | ||
575 | struct ClientPhoneSuspendMessage, | ||
576 | phone), | ||
577 | GNUNET_MQ_hd_fixed_size (phone_resume, | ||
578 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME, | ||
579 | struct ClientPhoneResumeMessage, | ||
580 | phone), | ||
581 | GNUNET_MQ_hd_var_size (phone_audio, | ||
582 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, | ||
583 | struct ClientAudioMessage, | ||
584 | phone), | ||
585 | GNUNET_MQ_handler_end () | ||
586 | }; | ||
587 | struct GNUNET_MQ_Envelope *e; | ||
588 | struct ClientPhoneRegisterMessage *reg; | ||
589 | |||
590 | clean_up_callers (phone); | ||
591 | if (NULL != phone->mq) | ||
592 | { | ||
593 | GNUNET_MQ_destroy (phone->mq); | ||
594 | phone->mq = NULL; | ||
595 | } | ||
596 | phone->state = PS_REGISTER; | ||
597 | phone->mq = GNUNET_CLIENT_connect (phone->cfg, | ||
598 | "conversation", | ||
599 | handlers, | ||
600 | &phone_error_handler, | ||
601 | phone); | ||
602 | if (NULL == phone->mq) | ||
603 | return; | ||
604 | e = GNUNET_MQ_msg (reg, | ||
605 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER); | ||
606 | reg->line_port = phone->my_record.line_port; | ||
607 | GNUNET_MQ_send (phone->mq, | ||
608 | e); | ||
609 | phone->state = PS_READY; | ||
610 | } | ||
611 | |||
612 | |||
613 | /** | ||
614 | * Create a new phone. | ||
615 | * | ||
616 | * @param cfg configuration for the phone; specifies the phone service and | ||
617 | * which line the phone is to be connected to | ||
618 | * @param ego ego to use for name resolution (when determining caller ID) | ||
619 | * @param event_handler how to notify the owner of the phone about events | ||
620 | * @param event_handler_cls closure for @a event_handler | ||
621 | * @return NULL on error (no valid line configured) | ||
622 | */ | ||
623 | struct GNUNET_CONVERSATION_Phone * | ||
624 | GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
625 | const struct GNUNET_IDENTITY_Ego *ego, | ||
626 | GNUNET_CONVERSATION_PhoneEventHandler | ||
627 | event_handler, | ||
628 | void *event_handler_cls) | ||
629 | { | ||
630 | struct GNUNET_CONVERSATION_Phone *phone; | ||
631 | char *line; | ||
632 | struct GNUNET_HashCode line_port; | ||
633 | |||
634 | if (GNUNET_OK != | ||
635 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
636 | "CONVERSATION", | ||
637 | "LINE", | ||
638 | &line)) | ||
639 | { | ||
640 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
641 | "CONVERSATION", | ||
642 | "LINE"); | ||
643 | return NULL; | ||
644 | } | ||
645 | GNUNET_CRYPTO_hash (line, | ||
646 | strlen (line), | ||
647 | &line_port); | ||
648 | GNUNET_free (line); | ||
649 | phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone); | ||
650 | if (GNUNET_OK != | ||
651 | GNUNET_CRYPTO_get_peer_identity (cfg, | ||
652 | &phone->my_record.peer)) | ||
653 | { | ||
654 | GNUNET_break (0); | ||
655 | GNUNET_free (phone); | ||
656 | return NULL; | ||
657 | } | ||
658 | phone->cfg = cfg; | ||
659 | phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego); | ||
660 | phone->event_handler = event_handler; | ||
661 | phone->event_handler_cls = event_handler_cls; | ||
662 | phone->ns = GNUNET_NAMESTORE_connect (cfg); | ||
663 | phone->my_record.version = htonl (1); | ||
664 | phone->my_record.reserved = htonl (0); | ||
665 | phone->my_record.line_port = line_port; | ||
666 | reconnect_phone (phone); | ||
667 | if ((NULL == phone->mq) || | ||
668 | (NULL == phone->ns)) | ||
669 | { | ||
670 | GNUNET_break (0); | ||
671 | GNUNET_CONVERSATION_phone_destroy (phone); | ||
672 | return NULL; | ||
673 | } | ||
674 | return phone; | ||
675 | } | ||
676 | |||
677 | |||
678 | /** | ||
679 | * Fill in a namestore record with the contact information | ||
680 | * for this phone. Note that the filled in "data" value | ||
681 | * is only valid until the phone is destroyed. | ||
682 | * | ||
683 | * @param phone phone to create a record for | ||
684 | * @param rd namestore record to fill in | ||
685 | */ | ||
686 | void | ||
687 | GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone, | ||
688 | struct GNUNET_GNSRECORD_Data *rd) | ||
689 | { | ||
690 | rd->data = &phone->my_record; | ||
691 | rd->expiration_time = 0; | ||
692 | rd->data_size = sizeof(struct GNUNET_CONVERSATION_PhoneRecord); | ||
693 | rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE; | ||
694 | rd->flags = GNUNET_GNSRECORD_RF_NONE; | ||
695 | } | ||
696 | |||
697 | |||
698 | /** | ||
699 | * Picks up a (ringing) phone. This will connect the speaker | ||
700 | * to the microphone of the other party, and vice versa. | ||
701 | * | ||
702 | * @param caller handle that identifies which caller should be answered | ||
703 | * @param event_handler how to notify about events by the caller | ||
704 | * @param event_handler_cls closure for @a event_handler | ||
705 | * @param speaker speaker to use | ||
706 | * @param mic microphone to use | ||
707 | */ | ||
708 | void | ||
709 | GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller, | ||
710 | GNUNET_CONVERSATION_CallerEventHandler | ||
711 | event_handler, | ||
712 | void *event_handler_cls, | ||
713 | struct GNUNET_SPEAKER_Handle *speaker, | ||
714 | struct GNUNET_MICROPHONE_Handle *mic) | ||
715 | { | ||
716 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
717 | struct GNUNET_MQ_Envelope *e; | ||
718 | struct ClientPhonePickupMessage *pick; | ||
719 | |||
720 | GNUNET_assert (CS_RINGING == caller->state); | ||
721 | caller->speaker = speaker; | ||
722 | caller->mic = mic; | ||
723 | e = GNUNET_MQ_msg (pick, | ||
724 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP); | ||
725 | pick->cid = caller->cid; | ||
726 | GNUNET_MQ_send (phone->mq, | ||
727 | e); | ||
728 | caller->state = CS_ACTIVE; | ||
729 | caller->event_handler = event_handler; | ||
730 | caller->event_handler_cls = event_handler_cls; | ||
731 | caller->speaker->enable_speaker (caller->speaker->cls); | ||
732 | caller->mic->enable_microphone (caller->mic->cls, | ||
733 | &transmit_phone_audio, | ||
734 | caller); | ||
735 | } | ||
736 | |||
737 | |||
738 | /** | ||
739 | * Hang up up a (possibly ringing) phone. This will notify the other | ||
740 | * party that we are no longer interested in talking with them. | ||
741 | * | ||
742 | * @param caller conversation to hang up on | ||
743 | */ | ||
744 | void | ||
745 | GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller) | ||
746 | { | ||
747 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
748 | struct GNUNET_MQ_Envelope *e; | ||
749 | struct ClientPhoneHangupMessage *hang; | ||
750 | |||
751 | switch (caller->state) | ||
752 | { | ||
753 | case CS_ACTIVE: | ||
754 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
755 | caller->mic->disable_microphone (caller->mic->cls); | ||
756 | break; | ||
757 | |||
758 | default: | ||
759 | break; | ||
760 | } | ||
761 | GNUNET_CONTAINER_DLL_remove (phone->caller_head, | ||
762 | phone->caller_tail, | ||
763 | caller); | ||
764 | e = GNUNET_MQ_msg (hang, | ||
765 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP); | ||
766 | hang->cid = caller->cid; | ||
767 | GNUNET_MQ_send (phone->mq, | ||
768 | e); | ||
769 | GNUNET_free (caller); | ||
770 | } | ||
771 | |||
772 | |||
773 | /** | ||
774 | * Destroys a phone. | ||
775 | * | ||
776 | * @param phone phone to destroy | ||
777 | */ | ||
778 | void | ||
779 | GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone) | ||
780 | { | ||
781 | clean_up_callers (phone); | ||
782 | if (NULL != phone->ns) | ||
783 | { | ||
784 | GNUNET_NAMESTORE_disconnect (phone->ns); | ||
785 | phone->ns = NULL; | ||
786 | } | ||
787 | if (NULL != phone->mq) | ||
788 | { | ||
789 | GNUNET_MQ_destroy (phone->mq); | ||
790 | phone->mq = NULL; | ||
791 | } | ||
792 | GNUNET_free (phone); | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Pause conversation of an active call. This will disconnect the speaker | ||
798 | * and the microphone. The call can later be resumed with | ||
799 | * #GNUNET_CONVERSATION_caller_resume. | ||
800 | * | ||
801 | * @param caller call to suspend | ||
802 | */ | ||
803 | void | ||
804 | GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller) | ||
805 | { | ||
806 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
807 | struct GNUNET_MQ_Envelope *e; | ||
808 | struct ClientPhoneSuspendMessage *suspend; | ||
809 | |||
810 | GNUNET_assert ((CS_ACTIVE == caller->state) || | ||
811 | (CS_CALLER_SUSPENDED == caller->state)); | ||
812 | if (CS_ACTIVE == caller->state) | ||
813 | { | ||
814 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
815 | caller->mic->disable_microphone (caller->mic->cls); | ||
816 | } | ||
817 | caller->speaker = NULL; | ||
818 | caller->mic = NULL; | ||
819 | e = GNUNET_MQ_msg (suspend, | ||
820 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND); | ||
821 | suspend->cid = caller->cid; | ||
822 | GNUNET_MQ_send (phone->mq, | ||
823 | e); | ||
824 | if (CS_ACTIVE == caller->state) | ||
825 | caller->state = CS_CALLEE_SUSPENDED; | ||
826 | else | ||
827 | caller->state = CS_BOTH_SUSPENDED; | ||
828 | } | ||
829 | |||
830 | |||
831 | /** | ||
832 | * Resume suspended conversation of a phone. | ||
833 | * | ||
834 | * @param caller call to resume | ||
835 | * @param speaker speaker to use | ||
836 | * @param mic microphone to use | ||
837 | */ | ||
838 | void | ||
839 | GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller, | ||
840 | struct GNUNET_SPEAKER_Handle *speaker, | ||
841 | struct GNUNET_MICROPHONE_Handle *mic) | ||
842 | { | ||
843 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
844 | struct GNUNET_MQ_Envelope *e; | ||
845 | struct ClientPhoneResumeMessage *resume; | ||
846 | |||
847 | GNUNET_assert ((CS_CALLEE_SUSPENDED == caller->state) || | ||
848 | (CS_BOTH_SUSPENDED == caller->state)); | ||
849 | caller->speaker = speaker; | ||
850 | caller->mic = mic; | ||
851 | e = GNUNET_MQ_msg (resume, | ||
852 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME); | ||
853 | resume->cid = caller->cid; | ||
854 | GNUNET_MQ_send (phone->mq, | ||
855 | e); | ||
856 | if (CS_CALLEE_SUSPENDED == caller->state) | ||
857 | { | ||
858 | caller->state = CS_ACTIVE; | ||
859 | caller->speaker->enable_speaker (caller->speaker->cls); | ||
860 | caller->mic->enable_microphone (caller->mic->cls, | ||
861 | &transmit_phone_audio, | ||
862 | caller); | ||
863 | } | ||
864 | else | ||
865 | { | ||
866 | caller->state = CS_CALLER_SUSPENDED; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | |||
871 | /* end of conversation_api.c */ | ||