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