aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/conversation_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conversation/conversation_api.c')
-rw-r--r--src/conversation/conversation_api.c897
1 files changed, 0 insertions, 897 deletions
diff --git a/src/conversation/conversation_api.c b/src/conversation/conversation_api.c
deleted file mode 100644
index 9c4c520be..000000000
--- a/src/conversation/conversation_api.c
+++ /dev/null
@@ -1,897 +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 */
36enum 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 */
68struct 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 */
125enum 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 */
150struct 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 */
209static void
210reconnect_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 */
220static void
221transmit_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 * We received a `struct ClientPhoneRingMessage`
243 *
244 * @param cls the `struct GNUNET_CONVERSATION_Phone`
245 * @param ring the message
246 */
247static enum GNUNET_GenericReturnValue
248check_phone_ring (void *cls,
249 const struct ClientPhoneRingMessage *ring)
250{
251 //FIXME
252 return GNUNET_OK;
253}
254/**
255 * We received a `struct ClientPhoneRingMessage`
256 *
257 * @param cls the `struct GNUNET_CONVERSATION_Phone`
258 * @param ring the message
259 */
260static void
261handle_phone_ring (void *cls,
262 const struct ClientPhoneRingMessage *ring)
263{
264 struct GNUNET_CONVERSATION_Phone *phone = cls;
265 struct GNUNET_CONVERSATION_Caller *caller;
266 struct GNUNET_IDENTITY_PublicKey caller_id;
267 size_t key_len;
268 size_t read;
269
270 key_len = ntohl (ring->key_len);
271 switch (phone->state)
272 {
273 case PS_REGISTER:
274 GNUNET_assert (0);
275 break;
276
277 case PS_READY:
278 if ((GNUNET_SYSERR ==
279 GNUNET_IDENTITY_read_public_key_from_buffer (&ring[1],
280 key_len,
281 &caller_id,
282 &read)) ||
283 (read != key_len))
284 {
285 GNUNET_break (0);
286 break;
287 }
288 caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller);
289 caller->phone = phone;
290 GNUNET_CONTAINER_DLL_insert (phone->caller_head,
291 phone->caller_tail,
292 caller);
293 caller->caller_id = caller_id;
294 caller->cid = ring->cid;
295 caller->state = CS_RINGING;
296 phone->event_handler (phone->event_handler_cls,
297 GNUNET_CONVERSATION_EC_PHONE_RING,
298 caller,
299 &caller->caller_id);
300 break;
301 }
302}
303
304
305/**
306 * Find the record of the caller matching the @a cid
307 *
308 * @param phone phone to search
309 * @param cid caller ID to search for (in NBO)
310 * @return NULL if @a cid was not found
311 */
312static struct GNUNET_CONVERSATION_Caller *
313find_caller (struct GNUNET_CONVERSATION_Phone *phone,
314 uint32_t cid)
315{
316 struct GNUNET_CONVERSATION_Caller *caller;
317
318 for (caller = phone->caller_head; NULL != caller; caller = caller->next)
319 if (cid == caller->cid)
320 return caller;
321 return NULL;
322}
323
324
325/**
326 * We received a `struct ClientPhoneHangupMessage`.
327 *
328 * @param cls the `struct GNUNET_CONVERSATION_Phone *`
329 * @param hang the message
330 */
331static void
332handle_phone_hangup (void *cls,
333 const struct ClientPhoneHangupMessage *hang)
334{
335 struct GNUNET_CONVERSATION_Phone *phone = cls;
336 struct GNUNET_CONVERSATION_Caller *caller;
337
338 caller = find_caller (phone,
339 hang->cid);
340 if (NULL == caller)
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Received HANG_UP message for unknown caller ID %u\n",
344 (unsigned int) hang->cid);
345 return;
346 }
347
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349 "Received HANG_UP message, terminating call with `%s'\n",
350 GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id));
351 switch (caller->state)
352 {
353 case CS_RINGING:
354 phone->event_handler (phone->event_handler_cls,
355 GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
356 caller,
357 &caller->caller_id);
358 break;
359
360 case CS_ACTIVE:
361 caller->speaker->disable_speaker (caller->speaker->cls);
362 caller->mic->disable_microphone (caller->mic->cls);
363 phone->event_handler (phone->event_handler_cls,
364 GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
365 caller,
366 &caller->caller_id);
367 break;
368
369 case CS_CALLEE_SUSPENDED:
370 case CS_CALLER_SUSPENDED:
371 case CS_BOTH_SUSPENDED:
372 phone->event_handler (phone->event_handler_cls,
373 GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
374 caller,
375 &caller->caller_id);
376 break;
377 }
378 GNUNET_CONTAINER_DLL_remove (phone->caller_head,
379 phone->caller_tail,
380 caller);
381 GNUNET_free (caller);
382}
383
384
385/**
386 * We received a `struct ClientPhoneSuspendMessage`.
387 *
388 * @param cls the `struct GNUNET_CONVERSATION_Phone`
389 * @param suspend the message
390 */
391static void
392handle_phone_suspend (void *cls,
393 const struct ClientPhoneSuspendMessage *suspend)
394{
395 struct GNUNET_CONVERSATION_Phone *phone = cls;
396 struct GNUNET_CONVERSATION_Caller *caller;
397
398 caller = find_caller (phone,
399 suspend->cid);
400 if (NULL == caller)
401 return;
402 switch (caller->state)
403 {
404 case CS_RINGING:
405 GNUNET_break_op (0);
406 break;
407
408 case CS_ACTIVE:
409 caller->state = CS_CALLER_SUSPENDED;
410 caller->speaker->disable_speaker (caller->speaker->cls);
411 caller->mic->disable_microphone (caller->mic->cls);
412 caller->event_handler (caller->event_handler_cls,
413 GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
414 break;
415
416 case CS_CALLEE_SUSPENDED:
417 caller->state = CS_BOTH_SUSPENDED;
418 caller->event_handler (caller->event_handler_cls,
419 GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
420 break;
421
422 case CS_CALLER_SUSPENDED:
423 case CS_BOTH_SUSPENDED:
424 GNUNET_break_op (0);
425 break;
426 }
427}
428
429
430/**
431 * We received a `struct ClientPhoneResumeMessage`.
432 *
433 * @param cls the `struct GNUNET_CONVERSATION_Phone`
434 * @param resume the message
435 */
436static void
437handle_phone_resume (void *cls,
438 const struct ClientPhoneResumeMessage *resume)
439{
440 struct GNUNET_CONVERSATION_Phone *phone = cls;
441 struct GNUNET_CONVERSATION_Caller *caller;
442
443 caller = find_caller (phone,
444 resume->cid);
445 if (NULL == caller)
446 return;
447 switch (caller->state)
448 {
449 case CS_RINGING:
450 GNUNET_break_op (0);
451 break;
452
453 case CS_ACTIVE:
454 case CS_CALLEE_SUSPENDED:
455 GNUNET_break_op (0);
456 break;
457
458 case CS_CALLER_SUSPENDED:
459 caller->state = CS_ACTIVE;
460 caller->speaker->enable_speaker (caller->speaker->cls);
461 caller->mic->enable_microphone (caller->mic->cls,
462 &transmit_phone_audio,
463 caller);
464 caller->event_handler (caller->event_handler_cls,
465 GNUNET_CONVERSATION_EC_CALLER_RESUME);
466 break;
467
468 case CS_BOTH_SUSPENDED:
469 caller->state = CS_CALLEE_SUSPENDED;
470 caller->event_handler (caller->event_handler_cls,
471 GNUNET_CONVERSATION_EC_CALLER_RESUME);
472 break;
473 }
474}
475
476
477/**
478 * We received a `struct ClientAudioMessage`, check it is well-formed.
479 *
480 * @param cls the `struct GNUNET_CONVERSATION_Phone`
481 * @param am the message
482 * @return #GNUNET_OK if @a am is well-formed
483 */
484static int
485check_phone_audio (void *cls,
486 const struct ClientAudioMessage *am)
487{
488 (void) cls;
489 (void) am;
490
491 /* any variable-size payload is OK */
492 return GNUNET_OK;
493}
494
495
496/**
497 * We received a `struct ClientAudioMessage`
498 *
499 * @param cls the `struct GNUNET_CONVERSATION_Phone`
500 * @param am the message
501 */
502static void
503handle_phone_audio (void *cls,
504 const struct ClientAudioMessage *am)
505{
506 struct GNUNET_CONVERSATION_Phone *phone = cls;
507 struct GNUNET_CONVERSATION_Caller *caller;
508
509 caller = find_caller (phone,
510 am->cid);
511 if (NULL == caller)
512 return;
513 switch (caller->state)
514 {
515 case CS_RINGING:
516 GNUNET_break_op (0);
517 break;
518
519 case CS_ACTIVE:
520 caller->speaker->play (caller->speaker->cls,
521 ntohs (am->header.size) - sizeof(struct
522 ClientAudioMessage),
523 &am[1]);
524 break;
525
526 case CS_CALLEE_SUSPENDED:
527 case CS_CALLER_SUSPENDED:
528 case CS_BOTH_SUSPENDED:
529 break;
530 }
531}
532
533
534/**
535 * We encountered an error talking with the conversation service.
536 *
537 * @param cls the `struct GNUNET_CONVERSATION_Phone`
538 * @param error details about the error
539 */
540static void
541phone_error_handler (void *cls,
542 enum GNUNET_MQ_Error error)
543{
544 struct GNUNET_CONVERSATION_Phone *phone = cls;
545
546 (void) error;
547 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
548 _ (
549 "Connection to conversation service lost, trying to reconnect\n"));
550 reconnect_phone (phone);
551}
552
553
554/**
555 * Clean up all callers of the given phone.
556 *
557 * @param phone phone to clean up callers for
558 */
559static void
560clean_up_callers (struct GNUNET_CONVERSATION_Phone *phone)
561{
562 struct GNUNET_CONVERSATION_Caller *caller;
563
564 while (NULL != (caller = phone->caller_head))
565 {
566 /* make sure mic/speaker are disabled *before* callback */
567 if (CS_ACTIVE == caller->state)
568 {
569 caller->speaker->disable_speaker (caller->speaker->cls);
570 caller->mic->disable_microphone (caller->mic->cls);
571 caller->state = CS_CALLER_SUSPENDED;
572 }
573 phone->event_handler (phone->event_handler_cls,
574 GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
575 caller,
576 &caller->caller_id);
577 GNUNET_CONVERSATION_caller_hang_up (caller);
578 }
579}
580
581
582/**
583 * The phone got disconnected, reconnect to the service.
584 *
585 * @param phone phone to reconnect
586 */
587static void
588reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone)
589{
590 struct GNUNET_MQ_MessageHandler handlers[] = {
591 GNUNET_MQ_hd_var_size (phone_ring,
592 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING,
593 struct ClientPhoneRingMessage,
594 phone),
595 GNUNET_MQ_hd_fixed_size (phone_hangup,
596 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
597 struct ClientPhoneHangupMessage,
598 phone),
599 GNUNET_MQ_hd_fixed_size (phone_suspend,
600 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
601 struct ClientPhoneSuspendMessage,
602 phone),
603 GNUNET_MQ_hd_fixed_size (phone_resume,
604 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
605 struct ClientPhoneResumeMessage,
606 phone),
607 GNUNET_MQ_hd_var_size (phone_audio,
608 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
609 struct ClientAudioMessage,
610 phone),
611 GNUNET_MQ_handler_end ()
612 };
613 struct GNUNET_MQ_Envelope *e;
614 struct ClientPhoneRegisterMessage *reg;
615
616 clean_up_callers (phone);
617 if (NULL != phone->mq)
618 {
619 GNUNET_MQ_destroy (phone->mq);
620 phone->mq = NULL;
621 }
622 phone->state = PS_REGISTER;
623 phone->mq = GNUNET_CLIENT_connect (phone->cfg,
624 "conversation",
625 handlers,
626 &phone_error_handler,
627 phone);
628 if (NULL == phone->mq)
629 return;
630 e = GNUNET_MQ_msg (reg,
631 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
632 reg->line_port = phone->my_record.line_port;
633 GNUNET_MQ_send (phone->mq,
634 e);
635 phone->state = PS_READY;
636}
637
638
639/**
640 * Create a new phone.
641 *
642 * @param cfg configuration for the phone; specifies the phone service and
643 * which line the phone is to be connected to
644 * @param ego ego to use for name resolution (when determining caller ID)
645 * @param event_handler how to notify the owner of the phone about events
646 * @param event_handler_cls closure for @a event_handler
647 * @return NULL on error (no valid line configured)
648 */
649struct GNUNET_CONVERSATION_Phone *
650GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
651 const struct GNUNET_IDENTITY_Ego *ego,
652 GNUNET_CONVERSATION_PhoneEventHandler
653 event_handler,
654 void *event_handler_cls)
655{
656 struct GNUNET_CONVERSATION_Phone *phone;
657 char *line;
658 struct GNUNET_HashCode line_port;
659
660 if (GNUNET_OK !=
661 GNUNET_CONFIGURATION_get_value_string (cfg,
662 "CONVERSATION",
663 "LINE",
664 &line))
665 {
666 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
667 "CONVERSATION",
668 "LINE");
669 return NULL;
670 }
671 GNUNET_CRYPTO_hash (line,
672 strlen (line),
673 &line_port);
674 GNUNET_free (line);
675 phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
676 if (GNUNET_OK !=
677 GNUNET_CRYPTO_get_peer_identity (cfg,
678 &phone->my_record.peer))
679 {
680 GNUNET_break (0);
681 GNUNET_free (phone);
682 return NULL;
683 }
684 phone->cfg = cfg;
685 phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
686 phone->event_handler = event_handler;
687 phone->event_handler_cls = event_handler_cls;
688 phone->ns = GNUNET_NAMESTORE_connect (cfg);
689 phone->my_record.version = htonl (1);
690 phone->my_record.reserved = htonl (0);
691 phone->my_record.line_port = line_port;
692 reconnect_phone (phone);
693 if ((NULL == phone->mq) ||
694 (NULL == phone->ns))
695 {
696 GNUNET_break (0);
697 GNUNET_CONVERSATION_phone_destroy (phone);
698 return NULL;
699 }
700 return phone;
701}
702
703
704/**
705 * Fill in a namestore record with the contact information
706 * for this phone. Note that the filled in "data" value
707 * is only valid until the phone is destroyed.
708 *
709 * @param phone phone to create a record for
710 * @param rd namestore record to fill in
711 */
712void
713GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
714 struct GNUNET_GNSRECORD_Data *rd)
715{
716 rd->data = &phone->my_record;
717 rd->expiration_time = 0;
718 rd->data_size = sizeof(struct GNUNET_CONVERSATION_PhoneRecord);
719 rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE;
720 rd->flags = GNUNET_GNSRECORD_RF_NONE;
721}
722
723
724/**
725 * Picks up a (ringing) phone. This will connect the speaker
726 * to the microphone of the other party, and vice versa.
727 *
728 * @param caller handle that identifies which caller should be answered
729 * @param event_handler how to notify about events by the caller
730 * @param event_handler_cls closure for @a event_handler
731 * @param speaker speaker to use
732 * @param mic microphone to use
733 */
734void
735GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
736 GNUNET_CONVERSATION_CallerEventHandler
737 event_handler,
738 void *event_handler_cls,
739 struct GNUNET_SPEAKER_Handle *speaker,
740 struct GNUNET_MICROPHONE_Handle *mic)
741{
742 struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
743 struct GNUNET_MQ_Envelope *e;
744 struct ClientPhonePickupMessage *pick;
745
746 GNUNET_assert (CS_RINGING == caller->state);
747 caller->speaker = speaker;
748 caller->mic = mic;
749 e = GNUNET_MQ_msg (pick,
750 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
751 pick->cid = caller->cid;
752 GNUNET_MQ_send (phone->mq,
753 e);
754 caller->state = CS_ACTIVE;
755 caller->event_handler = event_handler;
756 caller->event_handler_cls = event_handler_cls;
757 caller->speaker->enable_speaker (caller->speaker->cls);
758 caller->mic->enable_microphone (caller->mic->cls,
759 &transmit_phone_audio,
760 caller);
761}
762
763
764/**
765 * Hang up up a (possibly ringing) phone. This will notify the other
766 * party that we are no longer interested in talking with them.
767 *
768 * @param caller conversation to hang up on
769 */
770void
771GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller)
772{
773 struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
774 struct GNUNET_MQ_Envelope *e;
775 struct ClientPhoneHangupMessage *hang;
776
777 switch (caller->state)
778 {
779 case CS_ACTIVE:
780 caller->speaker->disable_speaker (caller->speaker->cls);
781 caller->mic->disable_microphone (caller->mic->cls);
782 break;
783
784 default:
785 break;
786 }
787 GNUNET_CONTAINER_DLL_remove (phone->caller_head,
788 phone->caller_tail,
789 caller);
790 e = GNUNET_MQ_msg (hang,
791 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
792 hang->cid = caller->cid;
793 GNUNET_MQ_send (phone->mq,
794 e);
795 GNUNET_free (caller);
796}
797
798
799/**
800 * Destroys a phone.
801 *
802 * @param phone phone to destroy
803 */
804void
805GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
806{
807 clean_up_callers (phone);
808 if (NULL != phone->ns)
809 {
810 GNUNET_NAMESTORE_disconnect (phone->ns);
811 phone->ns = NULL;
812 }
813 if (NULL != phone->mq)
814 {
815 GNUNET_MQ_destroy (phone->mq);
816 phone->mq = NULL;
817 }
818 GNUNET_free (phone);
819}
820
821
822/**
823 * Pause conversation of an active call. This will disconnect the speaker
824 * and the microphone. The call can later be resumed with
825 * #GNUNET_CONVERSATION_caller_resume.
826 *
827 * @param caller call to suspend
828 */
829void
830GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller)
831{
832 struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
833 struct GNUNET_MQ_Envelope *e;
834 struct ClientPhoneSuspendMessage *suspend;
835
836 GNUNET_assert ((CS_ACTIVE == caller->state) ||
837 (CS_CALLER_SUSPENDED == caller->state));
838 if (CS_ACTIVE == caller->state)
839 {
840 caller->speaker->disable_speaker (caller->speaker->cls);
841 caller->mic->disable_microphone (caller->mic->cls);
842 }
843 caller->speaker = NULL;
844 caller->mic = NULL;
845 e = GNUNET_MQ_msg (suspend,
846 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
847 suspend->cid = caller->cid;
848 GNUNET_MQ_send (phone->mq,
849 e);
850 if (CS_ACTIVE == caller->state)
851 caller->state = CS_CALLEE_SUSPENDED;
852 else
853 caller->state = CS_BOTH_SUSPENDED;
854}
855
856
857/**
858 * Resume suspended conversation of a phone.
859 *
860 * @param caller call to resume
861 * @param speaker speaker to use
862 * @param mic microphone to use
863 */
864void
865GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
866 struct GNUNET_SPEAKER_Handle *speaker,
867 struct GNUNET_MICROPHONE_Handle *mic)
868{
869 struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
870 struct GNUNET_MQ_Envelope *e;
871 struct ClientPhoneResumeMessage *resume;
872
873 GNUNET_assert ((CS_CALLEE_SUSPENDED == caller->state) ||
874 (CS_BOTH_SUSPENDED == caller->state));
875 caller->speaker = speaker;
876 caller->mic = mic;
877 e = GNUNET_MQ_msg (resume,
878 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
879 resume->cid = caller->cid;
880 GNUNET_MQ_send (phone->mq,
881 e);
882 if (CS_CALLEE_SUSPENDED == caller->state)
883 {
884 caller->state = CS_ACTIVE;
885 caller->speaker->enable_speaker (caller->speaker->cls);
886 caller->mic->enable_microphone (caller->mic->cls,
887 &transmit_phone_audio,
888 caller);
889 }
890 else
891 {
892 caller->state = CS_CALLER_SUSPENDED;
893 }
894}
895
896
897/* end of conversation_api.c */