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_api.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_gnsrecord_lib.h"
31 #include "gnunet_gns_service.h"
32 #include "conversation.h"
36 * Possible states of the phone.
41 * We still need to register the phone.
46 * We are waiting for a call.
51 * The phone is ringing.
56 * The phone is in an active conversation.
63 * A phone is a device that can ring to signal an incoming call and
64 * that you can pick up to answer the call and hang up to terminate
65 * the call. You can also hang up a ringing phone immediately
66 * (without picking it up) to stop it from ringing. Phones have
67 * caller ID. You can ask the phone for its record and make that
68 * record available (via GNS) to enable others to call you.
69 * Multiple phones maybe connected to the same line (the line is
70 * something rather internal to a phone and not obvious from it).
71 * You can only have one conversation per phone at any time.
73 struct GNUNET_CONVERSATION_Phone
78 const struct GNUNET_CONFIGURATION_Handle *cfg;
81 * Handle to talk with CONVERSATION service.
83 struct GNUNET_CLIENT_Connection *client;
86 * Function to call for phone events.
88 GNUNET_CONVERSATION_EventHandler event_handler;
91 * Closure for @e event_handler
93 void *event_handler_cls;
96 * Speaker, or NULL if none is attached.
98 struct GNUNET_SPEAKER_Handle *speaker;
101 * Microphone, or NULL if none is attached.
103 struct GNUNET_MICROPHONE_Handle *mic;
106 * Connection to NAMESTORE (for reverse lookup).
108 struct GNUNET_NAMESTORE_Handle *ns;
111 * Active NAMESTORE lookup (or NULL).
113 struct GNUNET_NAMESTORE_QueueEntry *qe;
116 * Handle for transmitting to the CONVERSATION service.
118 struct GNUNET_MQ_Handle *mq;
121 * This phone's record.
123 struct GNUNET_CONVERSATION_PhoneRecord my_record;
128 struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
131 * Identity of the person calling us (valid while in state #PS_RINGING).
133 struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
136 * State machine for the phone.
138 enum PhoneState state;
144 * The phone got disconnected, reconnect to the service.
146 * @param phone phone to reconnect
149 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone);
153 * We have resolved the caller ID using our name service.
155 * @param cls the `struct GNUNET_CONVERSATION_Phone`
156 * @param zone our zone used for resolution
157 * @param label name of the caller
158 * @param rd_count number of records we have in @a rd
159 * @param rd records we have for the caller's label
162 handle_caller_name (void *cls,
163 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
165 unsigned int rd_count,
166 const struct GNUNET_GNSRECORD_Data *rd)
168 struct GNUNET_CONVERSATION_Phone *phone = cls;
173 name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&phone->caller_id));
175 GNUNET_asprintf (&name, "%.gnu", label);
176 phone->event_handler (phone->event_handler_cls,
177 GNUNET_CONVERSATION_EC_RING,
184 * We received a `struct ClientPhoneRingMessage`
186 * @param cls the `struct GNUNET_CONVERSATION_Phone`
187 * @param msg the message
190 handle_phone_ring (void *cls,
191 const struct GNUNET_MessageHeader *msg)
193 struct GNUNET_CONVERSATION_Phone *phone = cls;
194 const struct ClientPhoneRingMessage *ring;
196 ring = (const struct ClientPhoneRingMessage *) msg;
197 switch (phone->state)
203 phone->state = PS_RINGING;
204 phone->caller_id = ring->caller_id;
205 phone->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns,
213 reconnect_phone (phone);
217 reconnect_phone (phone);
224 * We received a `struct ClientPhoneHangupMessage`.
226 * @param cls the `struct GNUNET_CONVERSATION_Phone`
227 * @param msg the message
230 handle_phone_hangup (void *cls,
231 const struct GNUNET_MessageHeader *msg)
233 struct GNUNET_CONVERSATION_Phone *phone = cls;
234 const struct ClientPhoneHangupMessage *hang;
238 hang = (const struct ClientPhoneHangupMessage *) msg;
239 reason = (const char *) &hang[1];
240 len = htons (hang->header.size) - sizeof (struct ClientPhoneHangupMessage);
242 ('\0' != reason[len-1]) )
245 reconnect_phone (phone);
248 switch (phone->state)
255 reconnect_phone (phone);
258 if (NULL != phone->qe)
260 GNUNET_NAMESTORE_cancel (phone->qe);
262 phone->state = PS_WAITING;
265 phone->state = PS_WAITING;
266 phone->event_handler (phone->event_handler_cls,
267 GNUNET_CONVERSATION_EC_TERMINATED,
271 GNUNET_break (NULL == phone->qe);
272 phone->state = PS_WAITING;
273 phone->event_handler (phone->event_handler_cls,
274 GNUNET_CONVERSATION_EC_TERMINATED,
276 phone->speaker->disable_speaker (phone->speaker->cls);
277 phone->mic->disable_microphone (phone->mic->cls);
284 * We received a `struct ClientAudioMessage`
286 * @param cls the `struct GNUNET_CONVERSATION_Phone`
287 * @param msg the message
290 handle_phone_audio_message (void *cls,
291 const struct GNUNET_MessageHeader *msg)
293 struct GNUNET_CONVERSATION_Phone *phone = cls;
294 const struct ClientAudioMessage *am;
296 am = (const struct ClientAudioMessage *) msg;
297 switch (phone->state)
304 reconnect_phone (phone);
308 reconnect_phone (phone);
311 phone->speaker->play (phone->speaker->cls,
312 ntohs (msg->size) - sizeof (struct ClientAudioMessage),
320 * We encountered an error talking with the conversation service.
322 * @param cls the `struct GNUNET_CONVERSATION_Phone`
323 * @param error details about the error
326 phone_error_handler (void *cls,
327 enum GNUNET_MQ_Error error)
329 struct GNUNET_CONVERSATION_Phone *phone = cls;
333 _("Internal error %d\n"),
335 reconnect_phone (phone);
340 * The phone got disconnected, reconnect to the service.
342 * @param phone phone to reconnect
345 reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone)
347 static struct GNUNET_MQ_MessageHandler handlers[] =
349 { &handle_phone_ring,
350 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING,
351 sizeof (struct ClientPhoneRingMessage) },
352 { &handle_phone_hangup,
353 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
355 { &handle_phone_audio_message,
356 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
360 struct GNUNET_MQ_Envelope *e;
361 struct ClientPhoneRegisterMessage *reg;
363 if (PS_ACTIVE == phone->state)
365 phone->speaker->disable_speaker (phone->speaker->cls);
366 phone->mic->disable_microphone (phone->mic->cls);
368 if (NULL != phone->mq)
370 GNUNET_MQ_destroy (phone->mq);
373 if (NULL != phone->client)
375 GNUNET_CLIENT_disconnect (phone->client);
376 phone->client = NULL;
378 phone->state = PS_REGISTER;
379 phone->client = GNUNET_CLIENT_connect ("conversation", phone->cfg);
380 if (NULL == phone->client)
382 phone->mq = GNUNET_MQ_queue_for_connection_client (phone->client,
384 &phone_error_handler,
386 e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
387 reg->line = phone->my_record.line;
388 GNUNET_MQ_send (phone->mq, e);
389 phone->state = PS_WAITING;
394 * Create a new phone.
396 * @param cfg configuration for the phone; specifies the phone service and
397 * which line the phone is to be connected to
398 * @param ego ego to use for name resolution (when determining caller ID)
399 * @param event_handler how to notify the owner of the phone about events
400 * @param event_handler_cls closure for @a event_handler
402 struct GNUNET_CONVERSATION_Phone *
403 GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
404 const struct GNUNET_IDENTITY_Ego *ego,
405 GNUNET_CONVERSATION_EventHandler event_handler,
406 void *event_handler_cls)
408 struct GNUNET_CONVERSATION_Phone *phone;
409 unsigned long long line;
412 GNUNET_CONFIGURATION_get_value_number (cfg,
417 phone = GNUNET_new (struct GNUNET_CONVERSATION_Phone);
419 GNUNET_CRYPTO_get_peer_identity (cfg,
420 &phone->my_record.peer))
427 phone->my_zone = *GNUNET_IDENTITY_ego_get_private_key (ego);
428 phone->event_handler = event_handler;
429 phone->event_handler_cls = event_handler_cls;
430 phone->ns = GNUNET_NAMESTORE_connect (cfg);
431 phone->my_record.line = htonl ((uint32_t) line);
432 phone->my_record.version = htonl (0);
433 reconnect_phone (phone);
434 if ( (NULL == phone->client) ||
435 (NULL == phone->ns) )
438 GNUNET_CONVERSATION_phone_destroy (phone);
446 * Fill in a namestore record with the contact information
447 * for this phone. Note that the filled in "data" value
448 * is only valid until the phone is destroyed.
450 * @param phone phone to create a record for
451 * @param rd namestore record to fill in
454 GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
455 struct GNUNET_GNSRECORD_Data *rd)
457 rd->data = &phone->my_record;
458 rd->expiration_time = 0;
459 rd->data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
460 rd->record_type = GNUNET_GNSRECORD_TYPE_PHONE;
461 rd->flags = GNUNET_GNSRECORD_RF_NONE;
466 * Process recorded audio data.
468 * @param cls closure with the `struct GNUNET_CONVERSATION_Phone`
469 * @param data_size number of bytes in @a data
470 * @param data audio data to play
473 transmit_phone_audio (void *cls,
477 struct GNUNET_CONVERSATION_Phone *phone = cls;
478 struct GNUNET_MQ_Envelope *e;
479 struct ClientAudioMessage *am;
481 GNUNET_assert (PS_ACTIVE == phone->state);
482 e = GNUNET_MQ_msg_extra (am,
484 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
485 memcpy (&am[1], data, data_size);
486 GNUNET_MQ_send (phone->mq, e);
491 * Picks up a (ringing) phone. This will connect the speaker
492 * to the microphone of the other party, and vice versa.
494 * @param phone phone to pick up
495 * @param metadata meta data to give to the other user about the pick up event
496 * @param speaker speaker to use
497 * @param mic microphone to use
500 GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone,
501 const char *metadata,
502 struct GNUNET_SPEAKER_Handle *speaker,
503 struct GNUNET_MICROPHONE_Handle *mic)
505 struct GNUNET_MQ_Envelope *e;
506 struct ClientPhonePickupMessage *pick;
509 GNUNET_assert (PS_RINGING == phone->state);
510 phone->speaker = speaker;
512 slen = strlen (metadata) + 1;
513 e = GNUNET_MQ_msg_extra (pick, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
514 memcpy (&pick[1], metadata, slen);
515 GNUNET_MQ_send (phone->mq, e);
516 phone->state = PS_ACTIVE;
517 phone->speaker->enable_speaker (phone->speaker->cls);
518 phone->mic->enable_microphone (phone->mic->cls,
519 &transmit_phone_audio,
525 * Hang up up a (possibly ringing) phone. This will notify the other
526 * party that we are no longer interested in talking with them.
528 * @param phone phone to pick up
529 * @param reason text we give to the other party about why we terminated the conversation
532 GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone,
535 struct GNUNET_MQ_Envelope *e;
536 struct ClientPhoneHangupMessage *hang;
539 GNUNET_assert ( (PS_RINGING == phone->state) ||
540 (PS_ACTIVE == phone->state) );
541 phone->speaker->disable_speaker (phone->speaker->cls);
542 phone->mic->disable_microphone (phone->mic->cls);
543 phone->speaker = NULL;
545 slen = strlen (reason) + 1;
546 e = GNUNET_MQ_msg_extra (hang, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
547 memcpy (&hang[1], reason, slen);
548 GNUNET_MQ_send (phone->mq, e);
549 phone->state = PS_WAITING;
556 * @param phone phone to destroy
559 GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
561 if (NULL != phone->speaker)
563 phone->speaker->disable_speaker (phone->speaker->cls);
564 phone->speaker = NULL;
566 if (NULL != phone->mic)
568 phone->mic->disable_microphone (phone->mic->cls);
571 if (NULL != phone->qe)
573 GNUNET_NAMESTORE_cancel (phone->qe);
576 if (NULL != phone->ns)
578 GNUNET_NAMESTORE_disconnect (phone->ns);
581 if (NULL != phone->mq)
583 GNUNET_MQ_destroy (phone->mq);
586 if (NULL != phone->client)
588 GNUNET_CLIENT_disconnect (phone->client);
589 phone->client = NULL;
595 /* ******************************* Call API *************************** */
598 * Possible states of the phone.
603 * We still need to lookup the callee.
608 * The call is ringing.
613 * The call is in an active conversation.
618 * The call is in termination.
625 * Handle for an outgoing call.
627 struct GNUNET_CONVERSATION_Call
633 const struct GNUNET_CONFIGURATION_Handle *cfg;
636 * Handle to talk with CONVERSATION service.
638 struct GNUNET_CLIENT_Connection *client;
641 * Our caller identity.
643 struct GNUNET_IDENTITY_Ego *caller_id;
646 * Target callee as a GNS address/name.
653 struct GNUNET_SPEAKER_Handle *speaker;
658 struct GNUNET_MICROPHONE_Handle *mic;
661 * Function to call with events.
663 GNUNET_CONVERSATION_EventHandler event_handler;
666 * Closure for @e event_handler
668 void *event_handler_cls;
671 * Handle for transmitting to the CONVERSATION service.
673 struct GNUNET_MQ_Handle *mq;
676 * Connection to GNS (can be NULL).
678 struct GNUNET_GNS_Handle *gns;
681 * Active GNS lookup (or NULL).
683 struct GNUNET_GNS_LookupRequest *gns_lookup;
686 * Target phone record, only valid after the lookup is done.
688 struct GNUNET_CONVERSATION_PhoneRecord phone_record;
691 * State machine for the call.
693 enum CallState state;
699 * The call got disconnected, reconnect to the service.
701 * @param call call to reconnect
704 reconnect_call (struct GNUNET_CONVERSATION_Call *call);
708 * We received a `struct ClientPhoneBusyMessage`
710 * @param cls the `struct GNUNET_CONVERSATION_Call`
711 * @param msg the message
714 handle_call_busy (void *cls,
715 const struct GNUNET_MessageHeader *msg)
717 struct GNUNET_CONVERSATION_Call *call = cls;
723 reconnect_call (call);
726 call->event_handler (call->event_handler_cls,
727 GNUNET_CONVERSATION_EC_BUSY);
728 GNUNET_CONVERSATION_call_stop (call, NULL);
732 reconnect_call (call);
735 GNUNET_CONVERSATION_call_stop (call, NULL);
742 * Process recorded audio data.
744 * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
745 * @param data_size number of bytes in @a data
746 * @param data audio data to play
749 transmit_call_audio (void *cls,
753 struct GNUNET_CONVERSATION_Call *call = cls;
754 struct GNUNET_MQ_Envelope *e;
755 struct ClientAudioMessage *am;
757 GNUNET_assert (CS_ACTIVE == call->state);
758 e = GNUNET_MQ_msg_extra (am,
760 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
761 memcpy (&am[1], data, data_size);
762 GNUNET_MQ_send (call->mq, e);
767 * We received a `struct ClientPhonePickedupMessage`
769 * @param cls the `struct GNUNET_CONVERSATION_Call`
770 * @param msg the message
773 handle_call_picked_up (void *cls,
774 const struct GNUNET_MessageHeader *msg)
776 struct GNUNET_CONVERSATION_Call *call = cls;
777 const struct ClientPhonePickedupMessage *am;
778 const char *metadata;
781 am = (const struct ClientPhonePickedupMessage *) msg;
782 size = ntohs (am->header.size) - sizeof (struct ClientPhonePickedupMessage);
783 metadata = (const char *) &am[1];
785 ('\0' != metadata[size - 1]) )
791 reconnect_call (call);
794 call->state = CS_ACTIVE;
795 call->event_handler (call->event_handler_cls,
796 GNUNET_CONVERSATION_EC_READY,
798 call->speaker->enable_speaker (call->speaker->cls);
799 call->mic->enable_microphone (call->mic->cls,
800 &transmit_call_audio,
805 reconnect_call (call);
808 GNUNET_CONVERSATION_call_stop (call, NULL);
815 * We received a `struct ClientPhoneHangupMessage`
817 * @param cls the `struct GNUNET_CONVERSATION_Call`
818 * @param msg the message
821 handle_call_hangup (void *cls,
822 const struct GNUNET_MessageHeader *msg)
824 struct GNUNET_CONVERSATION_Call *call = cls;
825 const struct ClientPhoneHangupMessage *am;
829 am = (const struct ClientPhoneHangupMessage *) msg;
830 size = ntohs (am->header.size) - sizeof (struct ClientPhoneHangupMessage);
831 reason = (const char *) &am[1];
833 ('\0' != reason[size - 1]) )
839 reconnect_call (call);
842 call->event_handler (call->event_handler_cls,
843 GNUNET_CONVERSATION_EC_TERMINATED,
845 GNUNET_CONVERSATION_call_stop (call, NULL);
848 call->event_handler (call->event_handler_cls,
849 GNUNET_CONVERSATION_EC_TERMINATED,
851 GNUNET_CONVERSATION_call_stop (call, NULL);
854 GNUNET_CONVERSATION_call_stop (call, NULL);
861 * We received a `struct ClientAudioMessage`
863 * @param cls the `struct GNUNET_CONVERSATION_Call`
864 * @param msg the message
867 handle_call_audio_message (void *cls,
868 const struct GNUNET_MessageHeader *msg)
870 struct GNUNET_CONVERSATION_Call *call = cls;
871 const struct ClientAudioMessage *am;
873 am = (const struct ClientAudioMessage *) msg;
878 reconnect_call (call);
882 reconnect_call (call);
885 call->speaker->play (call->speaker->cls,
886 ntohs (msg->size) - sizeof (struct ClientAudioMessage),
890 GNUNET_CONVERSATION_call_stop (call, NULL);
898 * Iterator called on obtained result for a GNS lookup.
900 * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
901 * @param rd_count number of records in @a rd
902 * @param rd the records in reply
905 handle_gns_response (void *cls,
907 const struct GNUNET_GNSRECORD_Data *rd)
909 struct GNUNET_CONVERSATION_Call *call = cls;
911 struct GNUNET_MQ_Envelope *e;
912 struct ClientCallMessage *ccm;
914 call->gns_lookup = NULL;
915 for (i=0;i<rd_count;i++)
917 if (GNUNET_GNSRECORD_TYPE_PHONE == rd[i].record_type)
919 if (rd[i].data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
924 memcpy (&call->phone_record,
927 e = GNUNET_MQ_msg (ccm, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL);
928 ccm->line = call->phone_record.line;
929 ccm->target = call->phone_record.peer;
930 ccm->caller_id = *GNUNET_IDENTITY_ego_get_private_key (call->caller_id);
931 GNUNET_MQ_send (call->mq, e);
932 call->state = CS_RINGING;
933 call->event_handler (call->event_handler_cls,
934 GNUNET_CONVERSATION_EC_RINGING);
939 call->event_handler (call->event_handler_cls,
940 GNUNET_CONVERSATION_EC_GNS_FAIL);
941 GNUNET_CONVERSATION_call_stop (call, NULL);
946 * We encountered an error talking with the conversation service.
948 * @param cls the `struct GNUNET_CONVERSATION_Call`
949 * @param error details about the error
952 call_error_handler (void *cls,
953 enum GNUNET_MQ_Error error)
955 struct GNUNET_CONVERSATION_Call *call = cls;
959 _("Internal error %d\n"),
961 reconnect_call (call);
966 * The call got disconnected, reconnect to the service.
968 * @param call call to reconnect
971 reconnect_call (struct GNUNET_CONVERSATION_Call *call)
973 static struct GNUNET_MQ_MessageHandler handlers[] =
976 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY,
977 sizeof (struct ClientPhoneBusyMessage) },
978 { &handle_call_picked_up,
979 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP,
981 { &handle_call_hangup,
982 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
984 { &handle_call_audio_message,
985 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
989 struct GNUNET_CRYPTO_EcdsaPublicKey my_zone;
991 if (CS_ACTIVE == call->state)
993 call->speaker->disable_speaker (call->speaker->cls);
994 call->mic->disable_microphone (call->mic->cls);
996 if (NULL != call->mq)
998 GNUNET_MQ_destroy (call->mq);
1001 if (NULL != call->client)
1003 GNUNET_CLIENT_disconnect (call->client);
1004 call->client = NULL;
1006 call->state = CS_SHUTDOWN;
1007 call->client = GNUNET_CLIENT_connect ("conversation", call->cfg);
1008 if (NULL == call->client)
1010 call->mq = GNUNET_MQ_queue_for_connection_client (call->client,
1012 &call_error_handler,
1014 call->state = CS_LOOKUP;
1015 GNUNET_IDENTITY_ego_get_public_key (call->caller_id,
1017 call->gns_lookup = GNUNET_GNS_lookup (call->gns,
1020 GNUNET_GNSRECORD_TYPE_PHONE,
1022 NULL /* FIXME: add shortening support */,
1023 &handle_gns_response, call);
1024 GNUNET_assert (NULL != call->gns_lookup);
1029 * Call the phone of another user.
1031 * @param cfg configuration to use, specifies our phone service
1032 * @param caller_id identity of the caller
1033 * @param callee GNS name of the callee (used to locate the callee's record)
1034 * @param speaker speaker to use (will be used automatically immediately once the
1035 * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT generate
1036 * a ring tone on the speaker
1037 * @param mic microphone to use (will be used automatically immediately once the
1038 * #GNUNET_CONVERSATION_EC_READY event is generated)
1039 * @param event_handler how to notify the owner of the phone about events
1040 * @param event_handler_cls closure for @a event_handler
1042 struct GNUNET_CONVERSATION_Call *
1043 GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
1044 struct GNUNET_IDENTITY_Ego *caller_id,
1046 struct GNUNET_SPEAKER_Handle *speaker,
1047 struct GNUNET_MICROPHONE_Handle *mic,
1048 GNUNET_CONVERSATION_EventHandler event_handler,
1049 void *event_handler_cls)
1051 struct GNUNET_CONVERSATION_Call *call;
1053 call = GNUNET_new (struct GNUNET_CONVERSATION_Call);
1055 call->caller_id = caller_id;
1056 call->callee = GNUNET_strdup (callee);
1057 call->speaker = speaker;
1059 call->event_handler = event_handler;
1060 call->event_handler_cls = event_handler_cls;
1061 call->gns = GNUNET_GNS_connect (cfg);
1062 reconnect_call (call);
1064 if ( (NULL == call->client) ||
1065 (NULL == call->gns) )
1067 GNUNET_CONVERSATION_call_stop (call, NULL);
1075 * We've sent the hang up message, now finish terminating the call.
1077 * @param cls the `struct GNUNET_CONVERSATION_Call` to terminate
1080 finish_stop (void *cls)
1082 struct GNUNET_CONVERSATION_Call *call = cls;
1084 GNUNET_assert (CS_SHUTDOWN == call->state);
1085 GNUNET_CONVERSATION_call_stop (call, NULL);
1090 * Terminate a call. The call may be ringing or ready at this time.
1092 * @param call call to terminate
1093 * @param reason if the call was active (ringing or ready) this will be the
1094 * reason given to the other user for why we hung up
1097 GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call,
1100 struct GNUNET_MQ_Envelope *e;
1101 struct ClientPhoneHangupMessage *hang;
1104 if ( (NULL != call->speaker) &&
1105 (CS_ACTIVE == call->state) )
1106 call->speaker->disable_speaker (call->speaker->cls);
1107 if ( (NULL != call->mic) &&
1108 (CS_ACTIVE == call->state) )
1109 call->mic->disable_microphone (call->mic->cls);
1112 slen = strlen (reason) + 1;
1113 e = GNUNET_MQ_msg_extra (hang, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1114 memcpy (&hang[1], reason, slen);
1115 GNUNET_MQ_notify_sent (e, &finish_stop, call);
1116 GNUNET_MQ_send (call->mq, e);
1117 call->state = CS_SHUTDOWN;
1120 if (NULL != call->mq)
1122 GNUNET_MQ_destroy (call->mq);
1125 if (NULL != call->client)
1127 GNUNET_CLIENT_disconnect (call->client);
1128 call->client = NULL;
1130 if (NULL != call->gns_lookup)
1132 GNUNET_GNS_lookup_cancel (call->gns_lookup);
1133 call->gns_lookup = NULL;
1135 if (NULL != call->gns)
1137 GNUNET_GNS_disconnect (call->gns);
1140 GNUNET_free (call->callee);
1145 /* end of conversation_api.c */