-rps: merge duplicate functions
[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    * Handle to talk with CONVERSATION service.
165    */
166   struct GNUNET_CLIENT_Connection *client;
167
168   /**
169    * We keep all callers in a DLL.
170    */
171   struct GNUNET_CONVERSATION_Caller *caller_head;
172
173   /**
174    * We keep all callers in a DLL.
175    */
176   struct GNUNET_CONVERSATION_Caller *caller_tail;
177
178   /**
179    * Function to call for phone events.
180    */
181   GNUNET_CONVERSATION_PhoneEventHandler event_handler;
182
183   /**
184    * Closure for @e event_handler
185    */
186   void *event_handler_cls;
187
188   /**
189    * Connection to NAMESTORE (for reverse lookup).
190    */
191   struct GNUNET_NAMESTORE_Handle *ns;
192
193   /**
194    * Handle for transmitting to the CONVERSATION service.
195    */
196   struct GNUNET_MQ_Handle *mq;
197
198   /**
199    * This phone's record.
200    */
201   struct GNUNET_CONVERSATION_PhoneRecord my_record;
202
203   /**
204    * My GNS zone.
205    */
206   struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
207
208   /**
209    * State machine for the phone.
210    */
211   enum PhoneState state;
212
213 };
214
215
216 /**
217  * The phone got disconnected, reconnect to the service.
218  *
219  * @param phone phone to reconnect
220  */
221 static void
222 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone);
223
224
225 /**
226  * Process recorded audio data.
227  *
228  * @param cls closure with the `struct GNUNET_CONVERSATION_Caller`
229  * @param data_size number of bytes in @a data
230  * @param data audio data to play
231  */
232 static void
233 transmit_phone_audio (void *cls,
234                       size_t data_size,
235                       const void *data)
236 {
237   struct GNUNET_CONVERSATION_Caller *caller = cls;
238   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
239   struct GNUNET_MQ_Envelope *e;
240   struct ClientAudioMessage *am;
241
242   e = GNUNET_MQ_msg_extra (am,
243                            data_size,
244                            GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
245   am->cid = caller->cid;
246   memcpy (&am[1], data, data_size);
247   GNUNET_MQ_send (phone->mq, e);
248 }
249
250
251 /**
252  * We received a `struct ClientPhoneRingMessage`
253  *
254  * @param cls the `struct GNUNET_CONVERSATION_Phone`
255  * @param msg the message
256  */
257 static void
258 handle_phone_ring (void *cls,
259                    const struct GNUNET_MessageHeader *msg)
260 {
261   struct GNUNET_CONVERSATION_Phone *phone = cls;
262   const struct ClientPhoneRingMessage *ring;
263   struct GNUNET_CONVERSATION_Caller *caller;
264
265   ring = (const struct ClientPhoneRingMessage *) msg;
266   switch (phone->state)
267   {
268   case PS_REGISTER:
269     GNUNET_assert (0);
270     break;
271   case PS_READY:
272     caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller);
273     caller->phone = phone;
274     GNUNET_CONTAINER_DLL_insert (phone->caller_head,
275                                  phone->caller_tail,
276                                  caller);
277     caller->caller_id = ring->caller_id;
278     caller->cid = ring->cid;
279     caller->state = CS_RINGING;
280     phone->event_handler (phone->event_handler_cls,
281                           GNUNET_CONVERSATION_EC_PHONE_RING,
282                           caller,
283                           &caller->caller_id);
284     break;
285   }
286 }
287
288
289 /**
290  * We received a `struct ClientPhoneHangupMessage`.
291  *
292  * @param cls the `struct GNUNET_CONVERSATION_Phone *`
293  * @param msg the message
294  */
295 static void
296 handle_phone_hangup (void *cls,
297                      const struct GNUNET_MessageHeader *msg)
298 {
299   struct GNUNET_CONVERSATION_Phone *phone = cls;
300   const struct ClientPhoneHangupMessage *hang;
301   struct GNUNET_CONVERSATION_Caller *caller;
302
303   hang = (const struct ClientPhoneHangupMessage *) msg;
304   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
305     if (hang->cid == caller->cid)
306       break;
307   if (NULL == caller)
308   {
309     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310                 "Received HANG_UP message for unknown caller ID %u\n",
311                 (unsigned int) hang->cid);
312     return;
313   }
314
315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316               "Received HANG_UP message, terminating call with `%s'\n",
317               GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id));
318   switch (caller->state)
319   {
320   case CS_RINGING:
321     phone->event_handler (phone->event_handler_cls,
322                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
323                           caller,
324                           &caller->caller_id);
325     break;
326   case CS_ACTIVE:
327     caller->speaker->disable_speaker (caller->speaker->cls);
328     caller->mic->disable_microphone (caller->mic->cls);
329     phone->event_handler (phone->event_handler_cls,
330                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
331                           caller,
332                           &caller->caller_id);
333     break;
334   case CS_CALLEE_SUSPENDED:
335   case CS_CALLER_SUSPENDED:
336   case CS_BOTH_SUSPENDED:
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   GNUNET_CONTAINER_DLL_remove (phone->caller_head,
344                                phone->caller_tail,
345                                caller);
346   GNUNET_free (caller);
347 }
348
349
350 /**
351  * We received a `struct ClientPhoneSuspendMessage`.
352  *
353  * @param cls the `struct GNUNET_CONVERSATION_Phone`
354  * @param msg the message
355  */
356 static void
357 handle_phone_suspend (void *cls,
358                      const struct GNUNET_MessageHeader *msg)
359 {
360   struct GNUNET_CONVERSATION_Phone *phone = cls;
361   struct GNUNET_CONVERSATION_Caller *caller;
362   const struct ClientPhoneSuspendMessage *suspend;
363
364   suspend = (const struct ClientPhoneSuspendMessage *) msg;
365   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
366     if (suspend->cid == caller->cid)
367       break;
368   if (NULL == caller)
369     return;
370   switch (caller->state)
371   {
372   case CS_RINGING:
373     GNUNET_break_op (0);
374     break;
375   case CS_ACTIVE:
376     caller->state = CS_CALLER_SUSPENDED;
377     caller->speaker->disable_speaker (caller->speaker->cls);
378     caller->mic->disable_microphone (caller->mic->cls);
379     caller->event_handler (caller->event_handler_cls,
380                            GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
381     break;
382   case CS_CALLEE_SUSPENDED:
383     caller->state = CS_BOTH_SUSPENDED;
384     caller->event_handler (caller->event_handler_cls,
385                            GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
386     break;
387   case CS_CALLER_SUSPENDED:
388   case CS_BOTH_SUSPENDED:
389     GNUNET_break_op (0);
390     break;
391   }
392 }
393
394
395 /**
396  * We received a `struct ClientPhoneResumeMessage`.
397  *
398  * @param cls the `struct GNUNET_CONVERSATION_Phone`
399  * @param msg the message
400  */
401 static void
402 handle_phone_resume (void *cls,
403                      const struct GNUNET_MessageHeader *msg)
404 {
405   struct GNUNET_CONVERSATION_Phone *phone = cls;
406   struct GNUNET_CONVERSATION_Caller *caller;
407   const struct ClientPhoneResumeMessage *resume;
408
409   resume = (const struct ClientPhoneResumeMessage *) msg;
410   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
411     if (resume->cid == caller->cid)
412       break;
413   if (NULL == caller)
414     return;
415   switch (caller->state)
416   {
417   case CS_RINGING:
418     GNUNET_break_op (0);
419     break;
420   case CS_ACTIVE:
421   case CS_CALLEE_SUSPENDED:
422     GNUNET_break_op (0);
423     break;
424   case CS_CALLER_SUSPENDED:
425     caller->state = CS_ACTIVE;
426     caller->speaker->enable_speaker (caller->speaker->cls);
427     caller->mic->enable_microphone (caller->mic->cls,
428                                     &transmit_phone_audio,
429                                     caller);
430     caller->event_handler (caller->event_handler_cls,
431                            GNUNET_CONVERSATION_EC_CALLER_RESUME);
432     break;
433   case CS_BOTH_SUSPENDED:
434     caller->state = CS_CALLEE_SUSPENDED;
435     caller->event_handler (caller->event_handler_cls,
436                            GNUNET_CONVERSATION_EC_CALLER_RESUME);
437     break;
438   }
439 }
440
441
442 /**
443  * We received a `struct ClientAudioMessage`
444  *
445  * @param cls the `struct GNUNET_CONVERSATION_Phone`
446  * @param msg the message
447  */
448 static void
449 handle_phone_audio_message (void *cls,
450                             const struct GNUNET_MessageHeader *msg)
451 {
452   struct GNUNET_CONVERSATION_Phone *phone = cls;
453   const struct ClientAudioMessage *am;
454   struct GNUNET_CONVERSATION_Caller *caller;
455
456   am = (const struct ClientAudioMessage *) msg;
457   for (caller = phone->caller_head; NULL != caller; caller = caller->next)
458     if (am->cid == caller->cid)
459       break;
460   if (NULL == caller)
461     return;
462   switch (caller->state)
463   {
464   case CS_RINGING:
465     GNUNET_break_op (0);
466     break;
467   case CS_ACTIVE:
468     caller->speaker->play (caller->speaker->cls,
469                            ntohs (msg->size) - sizeof (struct ClientAudioMessage),
470                            &am[1]);
471     break;
472   case CS_CALLEE_SUSPENDED:
473   case CS_CALLER_SUSPENDED:
474   case CS_BOTH_SUSPENDED:
475     break;
476   }
477 }
478
479
480 /**
481  * We encountered an error talking with the conversation service.
482  *
483  * @param cls the `struct GNUNET_CONVERSATION_Phone`
484  * @param error details about the error
485  */
486 static void
487 phone_error_handler (void *cls,
488                      enum GNUNET_MQ_Error error)
489 {
490   struct GNUNET_CONVERSATION_Phone *phone = cls;
491
492   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
493               _("Connection to conversation service lost, trying to reconnect\n"));
494   reconnect_phone (phone);
495 }
496
497
498 /**
499  * Clean up all callers of the given phone.
500  *
501  * @param phone phone to clean up callers for
502  */
503 static void
504 clean_up_callers (struct GNUNET_CONVERSATION_Phone *phone)
505 {
506   struct GNUNET_CONVERSATION_Caller *caller;
507
508   while (NULL != (caller = phone->caller_head))
509   {
510     /* make sure mic/speaker are disabled *before* callback */
511     if (CS_ACTIVE == caller->state)
512     {
513       caller->speaker->disable_speaker (caller->speaker->cls);
514       caller->mic->disable_microphone (caller->mic->cls);
515       caller->state = CS_CALLER_SUSPENDED;
516     }
517     phone->event_handler (phone->event_handler_cls,
518                           GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
519                           caller,
520                           &caller->caller_id);
521     GNUNET_CONVERSATION_caller_hang_up (caller);
522   }
523 }
524
525
526 /**
527  * The phone got disconnected, reconnect to the service.
528  *
529  * @param phone phone to reconnect
530  */
531 static void
532 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone)
533 {
534   static struct GNUNET_MQ_MessageHandler handlers[] =
535   {
536     { &handle_phone_ring,
537       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING,
538       sizeof (struct ClientPhoneRingMessage) },
539     { &handle_phone_hangup,
540       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
541       sizeof (struct ClientPhoneHangupMessage) },
542     { &handle_phone_suspend,
543       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
544       sizeof (struct ClientPhoneSuspendMessage) },
545     { &handle_phone_resume,
546       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
547       sizeof (struct ClientPhoneResumeMessage) },
548     { &handle_phone_audio_message,
549       GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
550       0 },
551     { NULL, 0, 0 }
552   };
553   struct GNUNET_MQ_Envelope *e;
554   struct ClientPhoneRegisterMessage *reg;
555
556   clean_up_callers (phone);
557   if (NULL != phone->mq)
558   {
559     GNUNET_MQ_destroy (phone->mq);
560     phone->mq = NULL;
561   }
562   if (NULL != phone->client)
563   {
564     GNUNET_CLIENT_disconnect (phone->client);
565     phone->client = NULL;
566   }
567   phone->state = PS_REGISTER;
568   phone->client = GNUNET_CLIENT_connect ("conversation", phone->cfg);
569   if (NULL == phone->client)
570     return;
571   phone->mq = GNUNET_MQ_queue_for_connection_client (phone->client,
572                                                      handlers,
573                                                      &phone_error_handler,
574                                                      phone);
575   e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
576   reg->line = phone->my_record.line;
577   GNUNET_MQ_send (phone->mq, e);
578   phone->state = PS_READY;
579 }
580
581
582 /**
583  * Create a new phone.
584  *
585  * @param cfg configuration for the phone; specifies the phone service and
586  *        which line the phone is to be connected to
587  * @param ego ego to use for name resolution (when determining caller ID)
588  * @param event_handler how to notify the owner of the phone about events
589  * @param event_handler_cls closure for @a event_handler
590  * @return NULL on error (no valid line configured)
591  */
592 struct GNUNET_CONVERSATION_Phone *
593 GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
594                                   const struct GNUNET_IDENTITY_Ego *ego,
595                                   GNUNET_CONVERSATION_PhoneEventHandler event_handler,
596                                   void *event_handler_cls)
597 {
598   struct GNUNET_CONVERSATION_Phone *phone;
599   unsigned long long line;
600
601   if (GNUNET_OK !=
602       GNUNET_CONFIGURATION_get_value_number (cfg,
603                                              "CONVERSATION",
604                                              "LINE",
605                                              &line))
606   {
607     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
608                                "CONVERSATION",
609                                "LINE");
610     return NULL;
611   }
612   if (line >= (1 << 31))
613   {
614     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
615                                "CONVERSATION",
616                                "LINE",
617                                _("number too large"));
618     return NULL;
619   }
620   phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
621   if (GNUNET_OK !=
622       GNUNET_CRYPTO_get_peer_identity (cfg,
623                                        &phone->my_record.peer))
624   {
625     GNUNET_break (0);
626     GNUNET_free (phone);
627     return NULL;
628   }
629   phone->cfg = cfg;
630   phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
631   phone->event_handler = event_handler;
632   phone->event_handler_cls = event_handler_cls;
633   phone->ns = GNUNET_NAMESTORE_connect (cfg);
634   phone->my_record.line = htonl ((uint32_t) line);
635   phone->my_record.version = htonl (0);
636   reconnect_phone (phone);
637   if ( (NULL == phone->client) ||
638        (NULL == phone->ns) )
639   {
640     GNUNET_break (0);
641     GNUNET_CONVERSATION_phone_destroy (phone);
642     return NULL;
643   }
644   return phone;
645 }
646
647
648 /**
649  * Fill in a namestore record with the contact information
650  * for this phone.  Note that the filled in "data" value
651  * is only valid until the phone is destroyed.
652  *
653  * @param phone phone to create a record for
654  * @param rd namestore record to fill in
655  */
656 void
657 GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
658                                       struct GNUNET_GNSRECORD_Data *rd)
659 {
660   rd->data = &phone->my_record;
661   rd->expiration_time = 0;
662   rd->data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
663   rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE;
664   rd->flags = GNUNET_GNSRECORD_RF_NONE;
665 }
666
667
668 /**
669  * Picks up a (ringing) phone.  This will connect the speaker
670  * to the microphone of the other party, and vice versa.
671  *
672  * @param caller handle that identifies which caller should be answered
673  * @param event_handler how to notify about events by the caller
674  * @param event_handler_cls closure for @a event_handler
675  * @param speaker speaker to use
676  * @param mic microphone to use
677  */
678 void
679 GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
680                                     GNUNET_CONVERSATION_CallerEventHandler event_handler,
681                                     void *event_handler_cls,
682                                     struct GNUNET_SPEAKER_Handle *speaker,
683                                     struct GNUNET_MICROPHONE_Handle *mic)
684 {
685   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
686   struct GNUNET_MQ_Envelope *e;
687   struct ClientPhonePickupMessage *pick;
688
689   GNUNET_assert (CS_RINGING == caller->state);
690   caller->speaker = speaker;
691   caller->mic = mic;
692   e = GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
693   pick->cid = caller->cid;
694   GNUNET_MQ_send (phone->mq, e);
695   caller->state = CS_ACTIVE;
696   caller->event_handler = event_handler;
697   caller->event_handler_cls = event_handler_cls;
698   caller->speaker->enable_speaker (caller->speaker->cls);
699   caller->mic->enable_microphone (caller->mic->cls,
700                                   &transmit_phone_audio,
701                                   caller);
702 }
703
704
705 /**
706  * Hang up up a (possibly ringing) phone.  This will notify the other
707  * party that we are no longer interested in talking with them.
708  *
709  * @param caller conversation to hang up on
710  */
711 void
712 GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller)
713 {
714   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
715   struct GNUNET_MQ_Envelope *e;
716   struct ClientPhoneHangupMessage *hang;
717
718   switch (caller->state)
719   {
720   case CS_ACTIVE:
721     caller->speaker->disable_speaker (caller->speaker->cls);
722     caller->mic->disable_microphone (caller->mic->cls);
723     break;
724   default:
725     break;
726   }
727   GNUNET_CONTAINER_DLL_remove (phone->caller_head,
728                                phone->caller_tail,
729                                caller);
730   e = GNUNET_MQ_msg (hang,
731                      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
732   hang->cid = caller->cid;
733   GNUNET_MQ_send (phone->mq, e);
734   GNUNET_free (caller);
735 }
736
737
738 /**
739  * Destroys a phone.
740  *
741  * @param phone phone to destroy
742  */
743 void
744 GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
745 {
746   clean_up_callers (phone);
747   if (NULL != phone->ns)
748   {
749     GNUNET_NAMESTORE_disconnect (phone->ns);
750     phone->ns = NULL;
751   }
752   if (NULL != phone->mq)
753   {
754     GNUNET_MQ_destroy (phone->mq);
755     phone->mq = NULL;
756   }
757   if (NULL != phone->client)
758   {
759     GNUNET_CLIENT_disconnect (phone->client);
760     phone->client = NULL;
761   }
762   GNUNET_free (phone);
763 }
764
765
766 /**
767  * Pause conversation of an active call.  This will disconnect the speaker
768  * and the microphone.  The call can later be resumed with
769  * #GNUNET_CONVERSATION_caller_resume.
770  *
771  * @param caller call to suspend
772  */
773 void
774 GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller)
775 {
776   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
777   struct GNUNET_MQ_Envelope *e;
778   struct ClientPhoneSuspendMessage *suspend;
779
780   GNUNET_assert ( (CS_ACTIVE == caller->state) ||
781                   (CS_CALLER_SUSPENDED == caller->state) );
782   if (CS_ACTIVE == caller->state)
783   {
784     caller->speaker->disable_speaker (caller->speaker->cls);
785     caller->mic->disable_microphone (caller->mic->cls);
786   }
787   caller->speaker = NULL;
788   caller->mic = NULL;
789   e = GNUNET_MQ_msg (suspend, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
790   suspend->cid = caller->cid;
791   GNUNET_MQ_send (phone->mq, e);
792   if (CS_ACTIVE == caller->state)
793     caller->state = CS_CALLEE_SUSPENDED;
794   else
795     caller->state = CS_BOTH_SUSPENDED;
796 }
797
798
799 /**
800  * Resume suspended conversation of a phone.
801  *
802  * @param caller call to resume
803  * @param speaker speaker to use
804  * @param mic microphone to use
805  */
806 void
807 GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
808                                    struct GNUNET_SPEAKER_Handle *speaker,
809                                    struct GNUNET_MICROPHONE_Handle *mic)
810 {
811   struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
812   struct GNUNET_MQ_Envelope *e;
813   struct ClientPhoneResumeMessage *resume;
814
815   GNUNET_assert ( (CS_CALLEE_SUSPENDED == caller->state) ||
816                   (CS_BOTH_SUSPENDED == caller->state) );
817   caller->speaker = speaker;
818   caller->mic = mic;
819   e = GNUNET_MQ_msg (resume, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
820   resume->cid = caller->cid;
821   GNUNET_MQ_send (phone->mq, e);
822   if (CS_CALLEE_SUSPENDED == caller->state)
823   {
824     caller->state = CS_ACTIVE;
825     caller->speaker->enable_speaker (caller->speaker->cls);
826     caller->mic->enable_microphone (caller->mic->cls,
827                                     &transmit_phone_audio,
828                                     caller);
829   }
830   else
831   {
832     caller->state = CS_CALLER_SUSPENDED;
833   }
834 }
835
836 /* end of conversation_api.c */