2 This file is part of GNUnet
3 (C) 2013 Christian Grothoff (and other contributing authors)
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.
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.
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file conversation/conversation_api2.c
23 * @brief API to the conversation service
24 * @author Simon Dieterle
25 * @author Andreas Fuchs
26 * @author Christian Grothoff
29 #include "gnunet_conversation_service.h"
30 #include "gnunet_gns_service.h"
31 #include "conversation.h"
35 * Possible states of the phone.
40 * We still need to register the phone.
45 * We are waiting for a call.
50 * The phone is ringing.
55 * The phone is in an active conversation.
62 * A phone is a device that can ring to signal an incoming call and
63 * that you can pick up to answer the call and hang up to terminate
64 * the call. You can also hang up a ringing phone immediately
65 * (without picking it up) to stop it from ringing. Phones have
66 * caller ID. You can ask the phone for its record and make that
67 * record available (via GNS) to enable others to call you.
68 * Multiple phones maybe connected to the same line (the line is
69 * something rather internal to a phone and not obvious from it).
70 * You can only have one conversation per phone at any time.
72 struct GNUNET_CONVERSATION_Phone
77 const struct GNUNET_CONFIGURATION_Handle *cfg;
80 * Handle to talk with CONVERSATION service.
82 struct GNUNET_CLIENT_Connection *client;
85 * Function to call for phone events.
87 GNUNET_CONVERSATION_EventHandler event_handler;
90 * Closure for @e event_handler
92 void *event_handler_cls;
95 * Speaker, or NULL if none is attached.
97 struct GNUNET_SPEAKER_Handle *speaker;
100 * Microphone, or NULL if none is attached.
102 struct GNUNET_MICROPHONE_Handle *mic;
105 * Connection to NAMESTORE (for reverse lookup).
107 struct GNUNET_NAMESTORE_Handle *ns;
110 * Active NAMESTORE lookup (or NULL).
112 struct GNUNET_NAMESTORE_QueueEntry *qe;
115 * Handle for transmitting to the CONVERSATION service.
117 struct GNUNET_MQ_Handle *mq;
120 * This phone's record.
122 struct GNUNET_CONVERSATION_PhoneRecord my_record;
127 struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
130 * Identity of the person calling us (valid while in state #PS_RINGING).
132 struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
135 * State machine for the phone.
137 enum PhoneState state;
143 * The phone got disconnected, reconnect to the service.
145 * @param phone phone to reconnect
148 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone);
152 * We have resolved the caller ID using our name service.
154 * @param cls the `struct GNUNET_CONVERSATION_Phone`
155 * @param zone our zone used for resolution
156 * @param label name of the caller
157 * @param rd_count number of records we have in @a rd
158 * @param rd records we have for the caller's label
161 handle_caller_name (void *cls,
162 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
164 unsigned int rd_count,
165 const struct GNUNET_NAMESTORE_RecordData *rd)
167 struct GNUNET_CONVERSATION_Phone *phone = cls;
172 name = GNUNET_strdup (GNUNET_NAMESTORE_pkey_to_zkey (&phone->caller_id));
174 GNUNET_asprintf (&name, "%.gnu", label);
175 phone->event_handler (phone->event_handler_cls,
176 GNUNET_CONVERSATION_EC_RING,
183 * We received a `struct ClientPhoneRingMessage`
185 * @param cls the `struct GNUNET_CONVERSATION_Phone`
186 * @param msg the message
189 handle_phone_ring (void *cls,
190 const struct GNUNET_MessageHeader *msg)
192 struct GNUNET_CONVERSATION_Phone *phone = cls;
193 const struct ClientPhoneRingMessage *ring;
195 ring = (const struct ClientPhoneRingMessage *) msg;
196 switch (phone->state)
202 phone->state = PS_RINGING;
203 phone->caller_id = ring->caller_id;
204 phone->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns,
212 reconnect_phone (phone);
216 reconnect_phone (phone);
223 * We received a `struct ClientPhoneHangupMessage`.
225 * @param cls the `struct GNUNET_CONVERSATION_Phone`
226 * @param msg the message
229 handle_phone_hangup (void *cls,
230 const struct GNUNET_MessageHeader *msg)
232 struct GNUNET_CONVERSATION_Phone *phone = cls;
233 const struct ClientPhoneHangupMessage *hang;
237 hang = (const struct ClientPhoneHangupMessage *) msg;
238 reason = (const char *) &hang[1];
239 len = htons (hang->header.size) - sizeof (struct ClientPhoneHangupMessage);
241 ('\0' != reason[len-1]) )
244 reconnect_phone (phone);
247 switch (phone->state)
254 reconnect_phone (phone);
257 if (NULL != phone->qe)
259 GNUNET_NAMESTORE_cancel (phone->qe);
261 phone->state = PS_WAITING;
264 phone->state = PS_WAITING;
265 phone->event_handler (phone->event_handler_cls,
266 GNUNET_CONVERSATION_EC_TERMINATED,
270 GNUNET_break (NULL == phone->qe);
271 phone->state = PS_WAITING;
272 phone->event_handler (phone->event_handler_cls,
273 GNUNET_CONVERSATION_EC_TERMINATED,
275 phone->speaker->disable_speaker (phone->speaker->cls);
276 phone->mic->disable_microphone (phone->mic->cls);
283 * We received a `struct ClientAudioMessage`
285 * @param cls the `struct GNUNET_CONVERSATION_Phone`
286 * @param msg the message
289 handle_phone_audio_message (void *cls,
290 const struct GNUNET_MessageHeader *msg)
292 struct GNUNET_CONVERSATION_Phone *phone = cls;
293 const struct ClientAudioMessage *am;
295 am = (const struct ClientAudioMessage *) msg;
296 switch (phone->state)
303 reconnect_phone (phone);
307 reconnect_phone (phone);
310 phone->speaker->play (phone->speaker->cls,
311 ntohs (msg->size) - sizeof (struct ClientAudioMessage),
319 * We encountered an error talking with the conversation service.
321 * @param cls the `struct GNUNET_CONVERSATION_Phone`
322 * @param error details about the error
325 phone_error_handler (void *cls,
326 enum GNUNET_MQ_Error error)
328 struct GNUNET_CONVERSATION_Phone *phone = cls;
332 _("Internal error %d\n"),
334 reconnect_phone (phone);
339 * The phone got disconnected, reconnect to the service.
341 * @param phone phone to reconnect
344 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone)
346 static struct GNUNET_MQ_MessageHandler handlers[] =
348 { &handle_phone_ring,
349 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING,
350 sizeof (struct ClientPhoneRingMessage) },
351 { &handle_phone_hangup,
352 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
354 { &handle_phone_audio_message,
355 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
359 struct GNUNET_MQ_Envelope *e;
360 struct ClientPhoneRegisterMessage *reg;
362 if (PS_ACTIVE == phone->state)
364 phone->speaker->disable_speaker (phone->speaker->cls);
365 phone->mic->disable_microphone (phone->mic->cls);
367 if (NULL != phone->mq)
369 GNUNET_MQ_destroy (phone->mq);
372 if (NULL != phone->client)
374 GNUNET_CLIENT_disconnect (phone->client);
375 phone->client = NULL;
377 phone->state = PS_REGISTER;
378 phone->client = GNUNET_CLIENT_connect ("conversation", phone->cfg);
379 if (NULL == phone->client)
381 phone->mq = GNUNET_MQ_queue_for_connection_client (phone->client,
383 &phone_error_handler,
385 e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
386 reg->line = phone->my_record.line;
387 GNUNET_MQ_send (phone->mq, e);
388 phone->state = PS_WAITING;
393 * Create a new phone.
395 * @param cfg configuration for the phone; specifies the phone service and
396 * which line the phone is to be connected to
397 * @param ego ego to use for name resolution (when determining caller ID)
398 * @param event_handler how to notify the owner of the phone about events
399 * @param event_handler_cls closure for @a event_handler
401 struct GNUNET_CONVERSATION_Phone *
402 GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
403 const struct GNUNET_IDENTITY_Ego *ego,
404 GNUNET_CONVERSATION_EventHandler event_handler,
405 void *event_handler_cls)
407 struct GNUNET_CONVERSATION_Phone *phone;
408 unsigned long long line;
411 GNUNET_CONFIGURATION_get_value_number (cfg,
416 phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
418 GNUNET_CRYPTO_get_peer_identity (cfg,
419 &phone->my_record.peer))
426 phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
427 phone->event_handler = event_handler;
428 phone->event_handler_cls = event_handler_cls;
429 phone->ns = GNUNET_NAMESTORE_connect (cfg);
430 phone->my_record.line = htonl ((uint32_t) line);
431 phone->my_record.version = htonl (0);
432 reconnect_phone (phone);
433 if ( (NULL == phone->client) ||
434 (NULL == phone->ns) )
437 GNUNET_CONVERSATION_phone_destroy (phone);
445 * Fill in a namestore record with the contact information
446 * for this phone. Note that the filled in "data" value
447 * is only valid until the phone is destroyed.
449 * @param phone phone to create a record for
450 * @param rd namestore record to fill in
453 GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
454 struct GNUNET_NAMESTORE_RecordData *rd)
456 rd->data = &phone->my_record;
457 rd->expiration_time = 0;
458 rd->data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
459 rd->record_type = GNUNET_NAMESTORE_TYPE_PHONE;
460 rd->flags = GNUNET_NAMESTORE_RF_NONE;
465 * Process recorded audio data.
467 * @param cls closure with the `struct GNUNET_CONVERSATION_Phone`
468 * @param data_size number of bytes in @a data
469 * @param data audio data to play
472 transmit_phone_audio (void *cls,
476 struct GNUNET_CONVERSATION_Phone *phone = cls;
477 struct GNUNET_MQ_Envelope *e;
478 struct ClientAudioMessage *am;
480 GNUNET_assert (PS_ACTIVE == phone->state);
481 e = GNUNET_MQ_msg_extra (am,
483 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
484 memcpy (&am[1], data, data_size);
485 GNUNET_MQ_send (phone->mq, e);
490 * Picks up a (ringing) phone. This will connect the speaker
491 * to the microphone of the other party, and vice versa.
493 * @param phone phone to pick up
494 * @param metadata meta data to give to the other user about the pick up event
495 * @param speaker speaker to use
496 * @param mic microphone to use
499 GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone,
500 const char *metadata,
501 struct GNUNET_SPEAKER_Handle *speaker,
502 struct GNUNET_MICROPHONE_Handle *mic)
504 struct GNUNET_MQ_Envelope *e;
505 struct ClientPhonePickupMessage *pick;
508 GNUNET_assert (PS_RINGING == phone->state);
509 phone->speaker = speaker;
511 slen = strlen (metadata) + 1;
512 e = GNUNET_MQ_msg_extra (pick, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
513 memcpy (&pick[1], metadata, slen);
514 GNUNET_MQ_send (phone->mq, e);
515 phone->state = PS_ACTIVE;
516 phone->speaker->enable_speaker (phone->speaker->cls);
517 phone->mic->enable_microphone (phone->mic->cls,
518 &transmit_phone_audio,
524 * Hang up up a (possibly ringing) phone. This will notify the other
525 * party that we are no longer interested in talking with them.
527 * @param phone phone to pick up
528 * @param reason text we give to the other party about why we terminated the conversation
531 GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone,
534 struct GNUNET_MQ_Envelope *e;
535 struct ClientPhoneHangupMessage *hang;
538 GNUNET_assert ( (PS_RINGING == phone->state) ||
539 (PS_ACTIVE == phone->state) );
540 phone->speaker->disable_speaker (phone->speaker->cls);
541 phone->mic->disable_microphone (phone->mic->cls);
542 phone->speaker = NULL;
544 slen = strlen (reason) + 1;
545 e = GNUNET_MQ_msg_extra (hang, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
546 memcpy (&hang[1], reason, slen);
547 GNUNET_MQ_send (phone->mq, e);
548 phone->state = PS_WAITING;
555 * @param phone phone to destroy
558 GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
560 if (NULL != phone->speaker)
562 phone->speaker->disable_speaker (phone->speaker->cls);
563 phone->speaker = NULL;
565 if (NULL != phone->mic)
567 phone->mic->disable_microphone (phone->mic->cls);
570 if (NULL != phone->qe)
572 GNUNET_NAMESTORE_cancel (phone->qe);
575 if (NULL != phone->ns)
577 GNUNET_NAMESTORE_disconnect (phone->ns);
580 if (NULL != phone->mq)
582 GNUNET_MQ_destroy (phone->mq);
585 if (NULL != phone->client)
587 GNUNET_CLIENT_disconnect (phone->client);
588 phone->client = NULL;
594 /* ******************************* Call API *************************** */
597 * Possible states of the phone.
602 * We still need to lookup the callee.
607 * The call is ringing.
612 * The call is in an active conversation.
617 * The call is in termination.
624 * Handle for an outgoing call.
626 struct GNUNET_CONVERSATION_Call
632 const struct GNUNET_CONFIGURATION_Handle *cfg;
635 * Handle to talk with CONVERSATION service.
637 struct GNUNET_CLIENT_Connection *client;
640 * Our caller identity.
642 struct GNUNET_IDENTITY_Ego *caller_id;
645 * Target callee as a GNS address/name.
652 struct GNUNET_SPEAKER_Handle *speaker;
657 struct GNUNET_MICROPHONE_Handle *mic;
660 * Function to call with events.
662 GNUNET_CONVERSATION_EventHandler event_handler;
665 * Closure for @e event_handler
667 void *event_handler_cls;
670 * Handle for transmitting to the CONVERSATION service.
672 struct GNUNET_MQ_Handle *mq;
675 * Connection to GNS (can be NULL).
677 struct GNUNET_GNS_Handle *gns;
680 * Active GNS lookup (or NULL).
682 struct GNUNET_GNS_LookupRequest *gns_lookup;
685 * Target phone record, only valid after the lookup is done.
687 struct GNUNET_CONVERSATION_PhoneRecord phone_record;
690 * State machine for the call.
692 enum CallState state;
698 * The call got disconnected, reconnect to the service.
700 * @param call call to reconnect
703 reconnect_call (struct GNUNET_CONVERSATION_Call *call);
707 * We received a `struct ClientPhoneBusyMessage`
709 * @param cls the `struct GNUNET_CONVERSATION_Call`
710 * @param msg the message
713 handle_call_busy (void *cls,
714 const struct GNUNET_MessageHeader *msg)
716 struct GNUNET_CONVERSATION_Call *call = cls;
722 reconnect_call (call);
725 call->event_handler (call->event_handler_cls,
726 GNUNET_CONVERSATION_EC_BUSY);
727 GNUNET_CONVERSATION_call_stop (call, NULL);
731 reconnect_call (call);
734 GNUNET_CONVERSATION_call_stop (call, NULL);
741 * Process recorded audio data.
743 * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
744 * @param data_size number of bytes in @a data
745 * @param data audio data to play
748 transmit_call_audio (void *cls,
752 struct GNUNET_CONVERSATION_Call *call = cls;
753 struct GNUNET_MQ_Envelope *e;
754 struct ClientAudioMessage *am;
756 GNUNET_assert (CS_ACTIVE == call->state);
757 e = GNUNET_MQ_msg_extra (am,
759 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
760 memcpy (&am[1], data, data_size);
761 GNUNET_MQ_send (call->mq, e);
766 * We received a `struct ClientPhonePickedupMessage`
768 * @param cls the `struct GNUNET_CONVERSATION_Call`
769 * @param msg the message
772 handle_call_picked_up (void *cls,
773 const struct GNUNET_MessageHeader *msg)
775 struct GNUNET_CONVERSATION_Call *call = cls;
776 const struct ClientPhonePickedupMessage *am;
777 const char *metadata;
780 am = (const struct ClientPhonePickedupMessage *) msg;
781 size = ntohs (am->header.size) - sizeof (struct ClientPhonePickedupMessage);
782 metadata = (const char *) &am[1];
784 ('\0' != metadata[size - 1]) )
790 reconnect_call (call);
793 call->state = CS_ACTIVE;
794 call->event_handler (call->event_handler_cls,
795 GNUNET_CONVERSATION_EC_READY,
797 call->speaker->enable_speaker (call->speaker->cls);
798 call->mic->enable_microphone (call->mic->cls,
799 &transmit_call_audio,
804 reconnect_call (call);
807 GNUNET_CONVERSATION_call_stop (call, NULL);
814 * We received a `struct ClientPhoneHangupMessage`
816 * @param cls the `struct GNUNET_CONVERSATION_Call`
817 * @param msg the message
820 handle_call_hangup (void *cls,
821 const struct GNUNET_MessageHeader *msg)
823 struct GNUNET_CONVERSATION_Call *call = cls;
824 const struct ClientPhoneHangupMessage *am;
828 am = (const struct ClientPhoneHangupMessage *) msg;
829 size = ntohs (am->header.size) - sizeof (struct ClientPhoneHangupMessage);
830 reason = (const char *) &am[1];
832 ('\0' != reason[size - 1]) )
838 reconnect_call (call);
841 call->event_handler (call->event_handler_cls,
842 GNUNET_CONVERSATION_EC_TERMINATED,
844 GNUNET_CONVERSATION_call_stop (call, NULL);
847 call->event_handler (call->event_handler_cls,
848 GNUNET_CONVERSATION_EC_TERMINATED,
850 GNUNET_CONVERSATION_call_stop (call, NULL);
853 GNUNET_CONVERSATION_call_stop (call, NULL);
860 * We received a `struct ClientAudioMessage`
862 * @param cls the `struct GNUNET_CONVERSATION_Call`
863 * @param msg the message
866 handle_call_audio_message (void *cls,
867 const struct GNUNET_MessageHeader *msg)
869 struct GNUNET_CONVERSATION_Call *call = cls;
870 const struct ClientAudioMessage *am;
872 am = (const struct ClientAudioMessage *) msg;
877 reconnect_call (call);
881 reconnect_call (call);
884 call->speaker->play (call->speaker->cls,
885 ntohs (msg->size) - sizeof (struct ClientAudioMessage),
889 GNUNET_CONVERSATION_call_stop (call, NULL);
897 * Iterator called on obtained result for a GNS lookup.
899 * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
900 * @param rd_count number of records in @a rd
901 * @param rd the records in reply
904 handle_gns_response (void *cls,
906 const struct GNUNET_NAMESTORE_RecordData *rd)
908 struct GNUNET_CONVERSATION_Call *call = cls;
910 struct GNUNET_MQ_Envelope *e;
911 struct ClientCallMessage *ccm;
913 call->gns_lookup = NULL;
914 for (i=0;i<rd_count;i++)
916 if (GNUNET_NAMESTORE_TYPE_PHONE == rd[i].record_type)
918 if (rd[i].data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
923 memcpy (&call->phone_record,
926 e = GNUNET_MQ_msg (ccm, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL);
927 ccm->line = call->phone_record.line;
928 ccm->target = call->phone_record.peer;
929 ccm->caller_id = *GNUNET_IDENTITY_ego_get_private_key (call->caller_id);
930 GNUNET_MQ_send (call->mq, e);
931 call->state = CS_RINGING;
932 call->event_handler (call->event_handler_cls,
933 GNUNET_CONVERSATION_EC_RINGING);
938 call->event_handler (call->event_handler_cls,
939 GNUNET_CONVERSATION_EC_GNS_FAIL);
940 GNUNET_CONVERSATION_call_stop (call, NULL);
945 * We encountered an error talking with the conversation service.
947 * @param cls the `struct GNUNET_CONVERSATION_Call`
948 * @param error details about the error
951 call_error_handler (void *cls,
952 enum GNUNET_MQ_Error error)
954 struct GNUNET_CONVERSATION_Call *call = cls;
958 _("Internal error %d\n"),
960 reconnect_call (call);
965 * The call got disconnected, reconnect to the service.
967 * @param call call to reconnect
970 reconnect_call (struct GNUNET_CONVERSATION_Call *call)
972 static struct GNUNET_MQ_MessageHandler handlers[] =
975 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY,
976 sizeof (struct ClientPhoneBusyMessage) },
977 { &handle_call_picked_up,
978 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP,
980 { &handle_call_hangup,
981 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
983 { &handle_call_audio_message,
984 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
988 struct GNUNET_CRYPTO_EcdsaPublicKey my_zone;
990 if (CS_ACTIVE == call->state)
992 call->speaker->disable_speaker (call->speaker->cls);
993 call->mic->disable_microphone (call->mic->cls);
995 if (NULL != call->mq)
997 GNUNET_MQ_destroy (call->mq);
1000 if (NULL != call->client)
1002 GNUNET_CLIENT_disconnect (call->client);
1003 call->client = NULL;
1005 call->state = CS_SHUTDOWN;
1006 call->client = GNUNET_CLIENT_connect ("conversation", call->cfg);
1007 if (NULL == call->client)
1009 call->mq = GNUNET_MQ_queue_for_connection_client (call->client,
1011 &call_error_handler,
1013 call->state = CS_LOOKUP;
1014 GNUNET_IDENTITY_ego_get_public_key (call->caller_id,
1016 call->gns_lookup = GNUNET_GNS_lookup (call->gns,
1019 GNUNET_NAMESTORE_TYPE_PHONE,
1021 NULL /* FIXME: add shortening support */,
1022 &handle_gns_response, call);
1023 GNUNET_assert (NULL != call->gns_lookup);
1028 * Call the phone of another user.
1030 * @param cfg configuration to use, specifies our phone service
1031 * @param caller_id identity of the caller
1032 * @param callee GNS name of the callee (used to locate the callee's record)
1033 * @param speaker speaker to use (will be used automatically immediately once the
1034 * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT generate
1035 * a ring tone on the speaker
1036 * @param mic microphone to use (will be used automatically immediately once the
1037 * #GNUNET_CONVERSATION_EC_READY event is generated)
1038 * @param event_handler how to notify the owner of the phone about events
1039 * @param event_handler_cls closure for @a event_handler
1041 struct GNUNET_CONVERSATION_Call *
1042 GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
1043 struct GNUNET_IDENTITY_Ego *caller_id,
1045 struct GNUNET_SPEAKER_Handle *speaker,
1046 struct GNUNET_MICROPHONE_Handle *mic,
1047 GNUNET_CONVERSATION_EventHandler event_handler,
1048 void *event_handler_cls)
1050 struct GNUNET_CONVERSATION_Call *call;
1052 call = GNUNET_new (struct GNUNET_CONVERSATION_Call);
1054 call->caller_id = caller_id;
1055 call->callee = GNUNET_strdup (callee);
1056 call->speaker = speaker;
1058 call->event_handler = event_handler;
1059 call->event_handler_cls = event_handler_cls;
1060 call->gns = GNUNET_GNS_connect (cfg);
1061 reconnect_call (call);
1063 if ( (NULL == call->client) ||
1064 (NULL == call->gns) )
1066 GNUNET_CONVERSATION_call_stop (call, NULL);
1074 * We've sent the hang up message, now finish terminating the call.
1076 * @param cls the `struct GNUNET_CONVERSATION_Call` to terminate
1079 finish_stop (void *cls)
1081 struct GNUNET_CONVERSATION_Call *call = cls;
1083 GNUNET_assert (CS_SHUTDOWN == call->state);
1084 GNUNET_CONVERSATION_call_stop (call, NULL);
1089 * Terminate a call. The call may be ringing or ready at this time.
1091 * @param call call to terminate
1092 * @param reason if the call was active (ringing or ready) this will be the
1093 * reason given to the other user for why we hung up
1096 GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call,
1099 struct GNUNET_MQ_Envelope *e;
1100 struct ClientPhoneHangupMessage *hang;
1103 if ( (NULL != call->speaker) &&
1104 (CS_ACTIVE == call->state) )
1105 call->speaker->disable_speaker (call->speaker->cls);
1106 if ( (NULL != call->mic) &&
1107 (CS_ACTIVE == call->state) )
1108 call->mic->disable_microphone (call->mic->cls);
1111 slen = strlen (reason) + 1;
1112 e = GNUNET_MQ_msg_extra (hang, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1113 memcpy (&hang[1], reason, slen);
1114 GNUNET_MQ_notify_sent (e, &finish_stop, call);
1115 GNUNET_MQ_send (call->mq, e);
1116 call->state = CS_SHUTDOWN;
1119 if (NULL != call->mq)
1121 GNUNET_MQ_destroy (call->mq);
1124 if (NULL != call->client)
1126 GNUNET_CLIENT_disconnect (call->client);
1127 call->client = NULL;
1129 if (NULL != call->gns_lookup)
1131 GNUNET_GNS_lookup_cancel (call->gns_lookup);
1132 call->gns_lookup = NULL;
1134 if (NULL != call->gns)
1136 GNUNET_GNS_disconnect (call->gns);
1139 GNUNET_free (call->callee);
1144 /* end of conversation_api.c */