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