error handling
[oweals/gnunet.git] / src / conversation / conversation_api.c
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_CRYPTO_EcdsaPublicKey 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_CRYPTO_EcdsaPrivateKey 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   phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
649   if (GNUNET_OK !=
650       GNUNET_CRYPTO_get_peer_identity (cfg,
651                                        &phone->my_record.peer))
652   {
653     GNUNET_break (0);
654     GNUNET_free (phone);
655     return NULL;
656   }
657   phone->cfg = cfg;
658   phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
659   phone->event_handler = event_handler;
660   phone->event_handler_cls = event_handler_cls;
661   phone->ns = GNUNET_NAMESTORE_connect (cfg);
662   phone->my_record.version = htonl (1);
663   phone->my_record.reserved = htonl (0);
664   phone->my_record.line_port = line_port;
665   reconnect_phone (phone);
666   if ((NULL == phone->mq) ||
667       (NULL == phone->ns))
668   {
669     GNUNET_break (0);
670     GNUNET_CONVERSATION_phone_destroy (phone);
671     return NULL;
672   }
673   return phone;
674 }
675
676
677 /**
678  * Fill in a namestore record with the contact information
679  * for this phone.  Note that the filled in "data" value
680  * is only valid until the phone is destroyed.
681  *
682  * @param phone phone to create a record for
683  * @param rd namestore record to fill in
684  */
685 void
686 GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
687                                       struct GNUNET_GNSRECORD_Data *rd)
688 {
689   rd->data = &phone->my_record;
690   rd->expiration_time = 0;
691   rd->data_size = sizeof(struct GNUNET_CONVERSATION_PhoneRecord);
692   rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE;
693   rd->flags = GNUNET_GNSRECORD_RF_NONE;
694 }
695
696
697 /**
698  * Picks up a (ringing) phone.  This will connect the speaker
699  * to the microphone of the other party, and vice versa.
700  *
701  * @param caller handle that identifies which caller should be answered
702  * @param event_handler how to notify about events by the caller
703  * @param event_handler_cls closure for @a event_handler
704  * @param speaker speaker to use
705  * @param mic microphone to use
706  */
707 void
708 GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
709                                     GNUNET_CONVERSATION_CallerEventHandler
710                                     event_handler,
711                                     void *event_handler_cls,
712                                     struct GNUNET_SPEAKER_Handle *speaker,
713                                     struct GNUNET_MICROPHONE_Handle *mic)
714 {
715   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
716   struct GNUNET_MQ_Envelope *e;
717   struct ClientPhonePickupMessage *pick;
718
719   GNUNET_assert (CS_RINGING == caller->state);
720   caller->speaker = speaker;
721   caller->mic = mic;
722   e = GNUNET_MQ_msg (pick,
723                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
724   pick->cid = caller->cid;
725   GNUNET_MQ_send (phone->mq,
726                   e);
727   caller->state = CS_ACTIVE;
728   caller->event_handler = event_handler;
729   caller->event_handler_cls = event_handler_cls;
730   caller->speaker->enable_speaker (caller->speaker->cls);
731   caller->mic->enable_microphone (caller->mic->cls,
732                                   &transmit_phone_audio,
733                                   caller);
734 }
735
736
737 /**
738  * Hang up up a (possibly ringing) phone.  This will notify the other
739  * party that we are no longer interested in talking with them.
740  *
741  * @param caller conversation to hang up on
742  */
743 void
744 GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller)
745 {
746   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
747   struct GNUNET_MQ_Envelope *e;
748   struct ClientPhoneHangupMessage *hang;
749
750   switch (caller->state)
751   {
752   case CS_ACTIVE:
753     caller->speaker->disable_speaker (caller->speaker->cls);
754     caller->mic->disable_microphone (caller->mic->cls);
755     break;
756
757   default:
758     break;
759   }
760   GNUNET_CONTAINER_DLL_remove (phone->caller_head,
761                                phone->caller_tail,
762                                caller);
763   e = GNUNET_MQ_msg (hang,
764                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
765   hang->cid = caller->cid;
766   GNUNET_MQ_send (phone->mq,
767                   e);
768   GNUNET_free (caller);
769 }
770
771
772 /**
773  * Destroys a phone.
774  *
775  * @param phone phone to destroy
776  */
777 void
778 GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
779 {
780   clean_up_callers (phone);
781   if (NULL != phone->ns)
782   {
783     GNUNET_NAMESTORE_disconnect (phone->ns);
784     phone->ns = NULL;
785   }
786   if (NULL != phone->mq)
787   {
788     GNUNET_MQ_destroy (phone->mq);
789     phone->mq = NULL;
790   }
791   GNUNET_free (phone);
792 }
793
794
795 /**
796  * Pause conversation of an active call.  This will disconnect the speaker
797  * and the microphone.  The call can later be resumed with
798  * #GNUNET_CONVERSATION_caller_resume.
799  *
800  * @param caller call to suspend
801  */
802 void
803 GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller)
804 {
805   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
806   struct GNUNET_MQ_Envelope *e;
807   struct ClientPhoneSuspendMessage *suspend;
808
809   GNUNET_assert ((CS_ACTIVE == caller->state) ||
810                  (CS_CALLER_SUSPENDED == caller->state));
811   if (CS_ACTIVE == caller->state)
812   {
813     caller->speaker->disable_speaker (caller->speaker->cls);
814     caller->mic->disable_microphone (caller->mic->cls);
815   }
816   caller->speaker = NULL;
817   caller->mic = NULL;
818   e = GNUNET_MQ_msg (suspend,
819                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
820   suspend->cid = caller->cid;
821   GNUNET_MQ_send (phone->mq,
822                   e);
823   if (CS_ACTIVE == caller->state)
824     caller->state = CS_CALLEE_SUSPENDED;
825   else
826     caller->state = CS_BOTH_SUSPENDED;
827 }
828
829
830 /**
831  * Resume suspended conversation of a phone.
832  *
833  * @param caller call to resume
834  * @param speaker speaker to use
835  * @param mic microphone to use
836  */
837 void
838 GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
839                                    struct GNUNET_SPEAKER_Handle *speaker,
840                                    struct GNUNET_MICROPHONE_Handle *mic)
841 {
842   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
843   struct GNUNET_MQ_Envelope *e;
844   struct ClientPhoneResumeMessage *resume;
845
846   GNUNET_assert ((CS_CALLEE_SUSPENDED == caller->state) ||
847                  (CS_BOTH_SUSPENDED == caller->state));
848   caller->speaker = speaker;
849   caller->mic = mic;
850   e = GNUNET_MQ_msg (resume,
851                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
852   resume->cid = caller->cid;
853   GNUNET_MQ_send (phone->mq,
854                   e);
855   if (CS_CALLEE_SUSPENDED == caller->state)
856   {
857     caller->state = CS_ACTIVE;
858     caller->speaker->enable_speaker (caller->speaker->cls);
859     caller->mic->enable_microphone (caller->mic->cls,
860                                     &transmit_phone_audio,
861                                     caller);
862   }
863   else
864   {
865     caller->state = CS_CALLER_SUSPENDED;
866   }
867 }
868
869
870 /* end of conversation_api.c */