[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r30734 - in gnunet/src: conversation include
From: |
gnunet |
Subject: |
[GNUnet-SVN] r30734 - in gnunet/src: conversation include |
Date: |
Fri, 15 Nov 2013 20:06:56 +0100 |
Author: grothoff
Date: 2013-11-15 20:06:55 +0100 (Fri, 15 Nov 2013)
New Revision: 30734
Added:
gnunet/src/conversation/conversation_api_call.c
Modified:
gnunet/src/conversation/Makefile.am
gnunet/src/conversation/conversation.h
gnunet/src/conversation/conversation_api.c
gnunet/src/conversation/gnunet-conversation.c
gnunet/src/include/gnunet_conversation_service.h
gnunet/src/include/gnunet_protocols.h
Log:
-towards enabling call waiting in conversation -- creates FTBFS
Modified: gnunet/src/conversation/Makefile.am
===================================================================
--- gnunet/src/conversation/Makefile.am 2013-11-15 17:00:41 UTC (rev 30733)
+++ gnunet/src/conversation/Makefile.am 2013-11-15 19:06:55 UTC (rev 30734)
@@ -142,6 +142,7 @@
test_conversation_api_SOURCES = \
+ test_conversation_api_call.c \
test_conversation_api.c
test_conversation_api_LDADD = \
libgnunetconversation.la \
Modified: gnunet/src/conversation/conversation.h
===================================================================
--- gnunet/src/conversation/conversation.h 2013-11-15 17:00:41 UTC (rev
30733)
+++ gnunet/src/conversation/conversation.h 2013-11-15 19:06:55 UTC (rev
30734)
@@ -82,9 +82,10 @@
struct GNUNET_MessageHeader header;
/**
- * Always zero.
+ * CID, internal caller ID to identify which active call we are
+ * talking about.
*/
- uint32_t reserved GNUNET_PACKED;
+ uint32_t cid GNUNET_PACKED;
/**
* Who is calling us?
@@ -95,19 +96,44 @@
/**
- * Service -> Client message for phone is busy.
+ * Service <-> Client message for phone was suspended.
*/
-struct ClientPhoneBusyMessage
+struct ClientPhoneSuspendMessage
{
/**
- * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY
+ * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND
*/
struct GNUNET_MessageHeader header;
+ /**
+ * CID, internal caller ID to identify which active call we are
+ * talking about.
+ */
+ uint32_t cid GNUNET_PACKED;
+
};
/**
+ * Service <-> Client message for phone was resumed.
+ */
+struct ClientPhoneResumeMessage
+{
+ /**
+ * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * CID, internal caller ID to identify which active call we are
+ * talking about.
+ */
+ uint32_t cid GNUNET_PACKED;
+
+};
+
+
+/**
* Client -> Service pick up phone that is ringing.
*/
struct ClientPhonePickupMessage
@@ -117,7 +143,11 @@
*/
struct GNUNET_MessageHeader header;
- /* followed by variable length 0-terminated string with meta data */
+ /**
+ * CID, internal caller ID to identify which active call we are
+ * talking about.
+ */
+ uint32_t cid GNUNET_PACKED;
};
@@ -133,7 +163,11 @@
*/
struct GNUNET_MessageHeader header;
- /* followed by variable length 0-terminated string with meta data */
+ /**
+ * CID, internal caller ID to identify which active call we are
+ * talking about.
+ */
+ uint32_t cid GNUNET_PACKED;
};
@@ -148,6 +182,12 @@
*/
struct GNUNET_MessageHeader header;
+ /**
+ * CID, internal caller ID to identify which active call we are
+ * sending data to.
+ */
+ uint32_t cid GNUNET_PACKED;
+
/* followed by audio data */
};
@@ -191,8 +231,6 @@
*/
struct GNUNET_MessageHeader header;
- /* followed by variable length 0-terminated string with meta data */
-
};
@@ -259,7 +297,6 @@
*/
struct GNUNET_MessageHeader header;
- /* followed by variable-size 0-terminated reason string */
};
@@ -273,17 +310,16 @@
*/
struct GNUNET_MessageHeader header;
- /* followed by variable-size 0-terminated metadata string */
};
/**
- * Mesh message for phone busy.
+ * Mesh message for phone suspended.
*/
-struct MeshPhoneBusyMessage
+struct MeshPhoneSuspendMessage
{
/**
- * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY
+ * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND
*/
struct GNUNET_MessageHeader header;
@@ -291,6 +327,19 @@
/**
+ * Mesh message for phone resumed.
+ */
+struct MeshPhoneResumeMessage
+{
+ /**
+ * Type is: #GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME
+ */
+ struct GNUNET_MessageHeader header;
+
+};
+
+
+/**
* Mesh message to transmit the audio.
*/
struct MeshAudioMessage
Modified: gnunet/src/conversation/conversation_api.c
===================================================================
--- gnunet/src/conversation/conversation_api.c 2013-11-15 17:00:41 UTC (rev
30733)
+++ gnunet/src/conversation/conversation_api.c 2013-11-15 19:06:55 UTC (rev
30734)
@@ -20,7 +20,7 @@
/**
* @file conversation/conversation_api.c
- * @brief API to the conversation service
+ * @brief phone and caller API to the conversation service
* @author Simon Dieterle
* @author Andreas Fuchs
* @author Christian Grothoff
@@ -33,33 +33,131 @@
/**
- * Possible states of the phone.
+ * Possible states of a caller.
*/
-enum PhoneState
+enum CallerState
{
/**
- * We still need to register the phone.
+ * We still need to reverse lookup the caller ID.
*/
- PS_REGISTER = 0,
+ CS_RESOLVE,
/**
- * We are waiting for a call.
+ * The phone is ringing (user knows about incoming call).
*/
- PS_WAITING,
+ CS_RINGING,
/**
- * The phone is ringing.
+ * The phone is in an active conversation.
*/
- PS_RINGING,
+ CS_ACTIVE,
/**
- * The phone is in an active conversation.
+ * We suspended the conversation.
*/
- PS_ACTIVE
+ CS_CALLEE_SUSPENDED,
+
+ /**
+ * Caller suspended the conversation.
+ */
+ CS_CALLER_SUSPENDED,
+
+ /**
+ * Both sides suspended the conversation.
+ */
+ CS_BOTH_SUSPENDED
};
+
/**
+ * A caller is the handle we have for an incoming call.
+ */
+struct GNUNET_CONVERSATION_Caller
+{
+
+ /**
+ * We keep all callers in a DLL.
+ */
+ struct GNUNET_CONVERSATION_Caller *next;
+
+ /**
+ * We keep all callers in a DLL.
+ */
+ struct GNUNET_CONVERSATION_Caller *prev;
+
+ /**
+ * Our phone.
+ */
+ struct GNUNET_CONVERSATION_Phone *phone;
+
+ /**
+ * Function to call for phone events.
+ */
+ GNUNET_CONVERSATION_CallerEventHandler event_handler;
+
+ /**
+ * Closure for @e event_handler
+ */
+ void *event_handler_cls;
+
+ /**
+ * Speaker, or NULL if none is attached.
+ */
+ struct GNUNET_SPEAKER_Handle *speaker;
+
+ /**
+ * Microphone, or NULL if none is attached.
+ */
+ struct GNUNET_MICROPHONE_Handle *mic;
+
+ /**
+ * Active NAMESTORE lookup (or NULL).
+ */
+ struct GNUNET_NAMESTORE_QueueEntry *qe;
+
+ /**
+ * Identity of the person calling us (valid while in state #PS_RINGING).
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
+
+ /**
+ * Caller ID of the person calling us as a string.
+ */
+ char *caller_id_str;
+
+ /**
+ * Internal handle to identify the caller with the service.
+ */
+ uint32_t cid;
+
+ /**
+ * State machine for the phone.
+ */
+ enum CallerState state;
+
+};
+
+
+/**
+ * Possible states of a phone.
+ */
+enum PhoneState
+{
+ /**
+ * We still need to register the phone.
+ */
+ PS_REGISTER = 0,
+
+ /**
+ * We are waiting for calls.
+ */
+ PS_READY
+
+};
+
+
+/**
* A phone is a device that can ring to signal an incoming call and
* that you can pick up to answer the call and hang up to terminate
* the call. You can also hang up a ringing phone immediately
@@ -83,24 +181,24 @@
struct GNUNET_CLIENT_Connection *client;
/**
- * Function to call for phone events.
+ * We keep all callers in a DLL.
*/
- GNUNET_CONVERSATION_EventHandler event_handler;
+ struct GNUNET_CONVERSATION_Caller *caller_head;
/**
- * Closure for @e event_handler
+ * We keep all callers in a DLL.
*/
- void *event_handler_cls;
+ struct GNUNET_CONVERSATION_Caller *caller_tail;
/**
- * Speaker, or NULL if none is attached.
+ * Function to call for phone events.
*/
- struct GNUNET_SPEAKER_Handle *speaker;
+ GNUNET_CONVERSATION_PhoneEventHandler event_handler;
/**
- * Microphone, or NULL if none is attached.
+ * Closure for @e event_handler
*/
- struct GNUNET_MICROPHONE_Handle *mic;
+ void *event_handler_cls;
/**
* Connection to NAMESTORE (for reverse lookup).
@@ -108,11 +206,6 @@
struct GNUNET_NAMESTORE_Handle *ns;
/**
- * Active NAMESTORE lookup (or NULL).
- */
- struct GNUNET_NAMESTORE_QueueEntry *qe;
-
- /**
* Handle for transmitting to the CONVERSATION service.
*/
struct GNUNET_MQ_Handle *mq;
@@ -128,11 +221,6 @@
struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone;
/**
- * Identity of the person calling us (valid while in state #PS_RINGING).
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey caller_id;
-
- /**
* State machine for the phone.
*/
enum PhoneState state;
@@ -152,7 +240,7 @@
/**
* We have resolved the caller ID using our name service.
*
- * @param cls the `struct GNUNET_CONVERSATION_Phone`
+ * @param cls the `struct GNUNET_CONVERSATION_Caller`
* @param zone our zone used for resolution
* @param label name of the caller
* @param rd_count number of records we have in @a rd
@@ -165,22 +253,51 @@
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
- struct GNUNET_CONVERSATION_Phone *phone = cls;
+ struct GNUNET_CONVERSATION_Caller *caller = cls;
+ struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
char *name;
- phone->qe = NULL;
+ caller->qe = NULL;
if (NULL == label)
- name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&phone->caller_id));
+ name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id));
else
GNUNET_asprintf (&name, "%.gnu", label);
+ caller->caller_id_str = name;
+ caller->state = CS_RINGING;
phone->event_handler (phone->event_handler_cls,
- GNUNET_CONVERSATION_EC_RING,
+ GNUNET_CONVERSATION_EC_PHONE_RING,
+ caller,
name);
- GNUNET_free (name);
}
/**
+ * Process recorded audio data.
+ *
+ * @param cls closure with the `struct GNUNET_CONVERSATION_Caller`
+ * @param data_size number of bytes in @a data
+ * @param data audio data to play
+ */
+static void
+transmit_phone_audio (void *cls,
+ size_t data_size,
+ const void *data)
+{
+ struct GNUNET_CONVERSATION_Caller *caller = cls;
+ struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
+ struct GNUNET_MQ_Envelope *e;
+ struct ClientAudioMessage *am;
+
+ e = GNUNET_MQ_msg_extra (am,
+ data_size,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
+ am->cid = caller->cid;
+ memcpy (&am[1], data, data_size);
+ GNUNET_MQ_send (phone->mq, e);
+}
+
+
+/**
* We received a `struct ClientPhoneRingMessage`
*
* @param cls the `struct GNUNET_CONVERSATION_Phone`
@@ -192,6 +309,7 @@
{
struct GNUNET_CONVERSATION_Phone *phone = cls;
const struct ClientPhoneRingMessage *ring;
+ struct GNUNET_CONVERSATION_Caller *caller;
ring = (const struct ClientPhoneRingMessage *) msg;
switch (phone->state)
@@ -199,23 +317,21 @@
case PS_REGISTER:
GNUNET_assert (0);
break;
- case PS_WAITING:
- phone->state = PS_RINGING;
- phone->caller_id = ring->caller_id;
- phone->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns,
- &phone->my_zone,
- &ring->caller_id,
- &handle_caller_name,
- phone);
+ case PS_READY:
+ caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller);
+ caller->phone = phone;
+ GNUNET_CONTAINER_DLL_insert (phone->caller_head,
+ phone->caller_tail,
+ caller);
+ caller->state = CS_RESOLVE;
+ caller->caller_id = ring->caller_id;
+ caller->cid = ring->cid;
+ caller->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns,
+ &phone->my_zone,
+ &ring->caller_id,
+ &handle_caller_name,
+ caller);
break;
- case PS_RINGING:
- GNUNET_break (0);
- reconnect_phone (phone);
- break;
- case PS_ACTIVE:
- GNUNET_break (0);
- reconnect_phone (phone);
- break;
}
}
@@ -232,55 +348,150 @@
{
struct GNUNET_CONVERSATION_Phone *phone = cls;
const struct ClientPhoneHangupMessage *hang;
- size_t len;
- const char *reason;
+ struct GNUNET_CONVERSATION_Caller *caller;
hang = (const struct ClientPhoneHangupMessage *) msg;
- reason = (const char *) &hang[1];
- len = htons (hang->header.size) - sizeof (struct ClientPhoneHangupMessage);
- if ( (0 == len) ||
- ('\0' != reason[len-1]) )
- {
- GNUNET_break (0);
- reconnect_phone (phone);
+ for (caller = phone->caller_head; NULL != caller; caller = caller->next)
+ if (hang->cid == caller->cid)
+ break;
+ if (NULL == caller)
return;
- }
- switch (phone->state)
+
+ switch (caller->state)
{
- case PS_REGISTER:
- GNUNET_assert (0);
+ case CS_RESOLVE:
+ GNUNET_NAMESTORE_cancel (caller->qe);
+ caller->qe = NULL;
break;
- case PS_WAITING:
- GNUNET_break (0);
- reconnect_phone (phone);
+ case CS_RINGING:
+ phone->event_handler (phone->event_handler_cls,
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
+ caller,
+ caller->caller_id_str);
break;
- case PS_RINGING:
- if (NULL != phone->qe)
- {
- GNUNET_NAMESTORE_cancel (phone->qe);
- phone->qe = NULL;
- phone->state = PS_WAITING;
- break;
- }
- phone->state = PS_WAITING;
+ case CS_ACTIVE:
+ caller->speaker->disable_speaker (caller->speaker->cls);
+ caller->mic->disable_microphone (caller->mic->cls);
phone->event_handler (phone->event_handler_cls,
- GNUNET_CONVERSATION_EC_TERMINATED,
- reason);
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
+ caller,
+ caller->caller_id_str);
break;
- case PS_ACTIVE:
- GNUNET_break (NULL == phone->qe);
- phone->state = PS_WAITING;
+ case CS_CALLEE_SUSPENDED:
+ case CS_CALLER_SUSPENDED:
+ case CS_BOTH_SUSPENDED:
phone->event_handler (phone->event_handler_cls,
- GNUNET_CONVERSATION_EC_TERMINATED,
- reason);
- phone->speaker->disable_speaker (phone->speaker->cls);
- phone->mic->disable_microphone (phone->mic->cls);
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
+ caller,
+ caller->caller_id_str);
break;
}
+ GNUNET_CONTAINER_DLL_remove (phone->caller_head,
+ phone->caller_tail,
+ caller);
+ GNUNET_free (caller);
}
/**
+ * We received a `struct ClientPhoneSuspendMessage`.
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Phone`
+ * @param msg the message
+ */
+static void
+handle_phone_suspend (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Phone *phone = cls;
+ struct GNUNET_CONVERSATION_Caller *caller;
+ const struct ClientPhoneSuspendMessage *suspend;
+
+ suspend = (const struct ClientPhoneSuspendMessage *) msg;
+ for (caller = phone->caller_head; NULL != caller; caller = caller->next)
+ if (suspend->cid == caller->cid)
+ break;
+ if (NULL == caller)
+ return;
+ switch (caller->state)
+ {
+ case CS_RESOLVE:
+ GNUNET_break_op (0);
+ break;
+ case CS_RINGING:
+ GNUNET_break_op (0);
+ break;
+ case CS_ACTIVE:
+ caller->state = CS_CALLER_SUSPENDED;
+ caller->speaker->disable_speaker (caller->speaker->cls);
+ caller->mic->disable_microphone (caller->mic->cls);
+ caller->event_handler (caller->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
+ break;
+ case CS_CALLEE_SUSPENDED:
+ caller->state = CS_BOTH_SUSPENDED;
+ caller->event_handler (caller->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALLER_SUSPEND);
+ break;
+ case CS_CALLER_SUSPENDED:
+ case CS_BOTH_SUSPENDED:
+ GNUNET_break_op (0);
+ break;
+ }
+}
+
+
+/**
+ * We received a `struct ClientPhoneResumeMessage`.
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Phone`
+ * @param msg the message
+ */
+static void
+handle_phone_resume (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Phone *phone = cls;
+ struct GNUNET_CONVERSATION_Caller *caller;
+ const struct ClientPhoneResumeMessage *resume;
+
+ resume = (const struct ClientPhoneResumeMessage *) msg;
+ for (caller = phone->caller_head; NULL != caller; caller = caller->next)
+ if (resume->cid == caller->cid)
+ break;
+ if (NULL == caller)
+ return;
+ switch (caller->state)
+ {
+ case CS_RESOLVE:
+ GNUNET_break_op (0);
+ break;
+ case CS_RINGING:
+ GNUNET_break_op (0);
+ break;
+ case CS_ACTIVE:
+ case CS_CALLEE_SUSPENDED:
+ GNUNET_break_op (0);
+ break;
+ case CS_CALLER_SUSPENDED:
+ caller->state = CS_ACTIVE;
+ caller->speaker->enable_speaker (caller->speaker->cls);
+ caller->mic->enable_microphone (caller->mic->cls,
+ &transmit_phone_audio,
+ caller);
+ caller->event_handler (caller->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALLER_RESUME);
+ break;
+ case CS_BOTH_SUSPENDED:
+ caller->state = CS_CALLEE_SUSPENDED;
+ caller->event_handler (caller->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALLER_RESUME);
+ break;
+ }
+}
+
+
+/**
* We received a `struct ClientAudioMessage`
*
* @param cls the `struct GNUNET_CONVERSATION_Phone`
@@ -292,25 +503,30 @@
{
struct GNUNET_CONVERSATION_Phone *phone = cls;
const struct ClientAudioMessage *am;
+ struct GNUNET_CONVERSATION_Caller *caller;
am = (const struct ClientAudioMessage *) msg;
- switch (phone->state)
+ for (caller = phone->caller_head; NULL != caller; caller = caller->next)
+ if (am->cid == caller->cid)
+ break;
+ if (NULL == caller)
+ return;
+ switch (caller->state)
{
- case PS_REGISTER:
- GNUNET_assert (0);
+ case CS_RESOLVE:
+ GNUNET_break_op (0);
break;
- case PS_WAITING:
- GNUNET_break (0);
- reconnect_phone (phone);
+ case CS_RINGING:
+ GNUNET_break_op (0);
break;
- case PS_RINGING:
- GNUNET_break (0);
- reconnect_phone (phone);
+ case CS_ACTIVE:
+ caller->speaker->play (caller->speaker->cls,
+ ntohs (msg->size) - sizeof (struct
ClientAudioMessage),
+ &am[1]);
break;
- case PS_ACTIVE:
- phone->speaker->play (phone->speaker->cls,
- ntohs (msg->size) - sizeof (struct
ClientAudioMessage),
- &am[1]);
+ case CS_CALLEE_SUSPENDED:
+ case CS_CALLER_SUSPENDED:
+ case CS_BOTH_SUSPENDED:
break;
}
}
@@ -329,9 +545,9 @@
struct GNUNET_CONVERSATION_Phone *phone = cls;
GNUNET_break (0);
- FPRINTF (stderr,
- _("Internal error %d\n"),
- error);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Internal MQ error %d\n"),
+ error);
reconnect_phone (phone);
}
@@ -351,7 +567,13 @@
sizeof (struct ClientPhoneRingMessage) },
{ &handle_phone_hangup,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
- 0 },
+ sizeof (struct ClientPhoneHangupMessage) },
+ { &handle_phone_suspend,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
+ sizeof (struct ClientPhoneSuspendMessage) },
+ { &handle_phone_resume,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
+ sizeof (struct ClientPhoneResumeMessage) },
{ &handle_phone_audio_message,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
0 },
@@ -359,11 +581,15 @@
};
struct GNUNET_MQ_Envelope *e;
struct ClientPhoneRegisterMessage *reg;
+ struct GNUNET_CONVERSATION_Caller *caller;
- if (PS_ACTIVE == phone->state)
+ while (NULL != (caller = phone->caller_head))
{
- phone->speaker->disable_speaker (phone->speaker->cls);
- phone->mic->disable_microphone (phone->mic->cls);
+ phone->event_handler (phone->event_handler_cls,
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
+ caller,
+ caller->caller_id_str);
+ GNUNET_CONVERSATION_caller_hang_up (caller);
}
if (NULL != phone->mq)
{
@@ -386,7 +612,7 @@
e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER);
reg->line = phone->my_record.line;
GNUNET_MQ_send (phone->mq, e);
- phone->state = PS_WAITING;
+ phone->state = PS_READY;
}
@@ -402,7 +628,7 @@
struct GNUNET_CONVERSATION_Phone *
GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle
*cfg,
const struct GNUNET_IDENTITY_Ego *ego,
- GNUNET_CONVERSATION_EventHandler
event_handler,
+ GNUNET_CONVERSATION_PhoneEventHandler
event_handler,
void *event_handler_cls)
{
struct GNUNET_CONVERSATION_Phone *phone;
@@ -463,61 +689,39 @@
/**
- * Process recorded audio data.
- *
- * @param cls closure with the `struct GNUNET_CONVERSATION_Phone`
- * @param data_size number of bytes in @a data
- * @param data audio data to play
- */
-static void
-transmit_phone_audio (void *cls,
- size_t data_size,
- const void *data)
-{
- struct GNUNET_CONVERSATION_Phone *phone = cls;
- struct GNUNET_MQ_Envelope *e;
- struct ClientAudioMessage *am;
-
- GNUNET_assert (PS_ACTIVE == phone->state);
- e = GNUNET_MQ_msg_extra (am,
- data_size,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
- memcpy (&am[1], data, data_size);
- GNUNET_MQ_send (phone->mq, e);
-}
-
-
-/**
* Picks up a (ringing) phone. This will connect the speaker
* to the microphone of the other party, and vice versa.
*
- * @param phone phone to pick up
- * @param metadata meta data to give to the other user about the pick up event
+ * @param caller handle that identifies which caller should be answered
+ * @param event_handler how to notify about events by the caller
+ * @param event_handler_cls closure for @a event_handler
* @param speaker speaker to use
* @param mic microphone to use
*/
void
-GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone,
- const char *metadata,
- struct GNUNET_SPEAKER_Handle *speaker,
- struct GNUNET_MICROPHONE_Handle *mic)
+GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
+ GNUNET_CONVERSATION_CallerEventHandler
event_handler,
+ void *event_handler_cls,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic)
{
+ struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
struct GNUNET_MQ_Envelope *e;
struct ClientPhonePickupMessage *pick;
- size_t slen;
- GNUNET_assert (PS_RINGING == phone->state);
- phone->speaker = speaker;
- phone->mic = mic;
- slen = strlen (metadata) + 1;
- e = GNUNET_MQ_msg_extra (pick, slen,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
- memcpy (&pick[1], metadata, slen);
+ GNUNET_assert (CS_RINGING == caller->state);
+ caller->speaker = speaker;
+ caller->mic = mic;
+ e = GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
+ pick->cid = caller->cid;
GNUNET_MQ_send (phone->mq, e);
- phone->state = PS_ACTIVE;
- phone->speaker->enable_speaker (phone->speaker->cls);
- phone->mic->enable_microphone (phone->mic->cls,
- &transmit_phone_audio,
- phone);
+ caller->state = CS_ACTIVE;
+ caller->event_handler = event_handler;
+ caller->event_handler_cls = event_handler_cls;
+ caller->speaker->enable_speaker (caller->speaker->cls);
+ caller->mic->enable_microphone (caller->mic->cls,
+ &transmit_phone_audio,
+ caller);
}
@@ -525,28 +729,35 @@
* Hang up up a (possibly ringing) phone. This will notify the other
* party that we are no longer interested in talking with them.
*
- * @param phone phone to pick up
- * @param reason text we give to the other party about why we terminated the
conversation
+ * @param caller conversation to hang up on
*/
void
-GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone,
- const char *reason)
+GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller)
{
+ struct GNUNET_CONVERSATION_Phone *phone = caller->phone;
struct GNUNET_MQ_Envelope *e;
struct ClientPhoneHangupMessage *hang;
- size_t slen;
- GNUNET_assert ( (PS_RINGING == phone->state) ||
- (PS_ACTIVE == phone->state) );
- phone->speaker->disable_speaker (phone->speaker->cls);
- phone->mic->disable_microphone (phone->mic->cls);
- phone->speaker = NULL;
- phone->mic = NULL;
- slen = strlen (reason) + 1;
- e = GNUNET_MQ_msg_extra (hang, slen,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
- memcpy (&hang[1], reason, slen);
+ switch (caller->state)
+ {
+ case CS_RESOLVE:
+ GNUNET_NAMESTORE_cancel (caller->qe);
+ caller->qe = NULL;
+ break;
+ case CS_ACTIVE:
+ caller->speaker->disable_speaker (caller->speaker->cls);
+ caller->mic->disable_microphone (caller->mic->cls);
+ break;
+ default:
+ break;
+ }
+ GNUNET_CONTAINER_DLL_remove (phone->caller_head,
+ phone->caller_tail,
+ caller);
+ GNUNET_free_non_null (caller->caller_id_str);
+ GNUNET_free (caller);
+ e = GNUNET_MQ_msg (hang, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
GNUNET_MQ_send (phone->mq, e);
- phone->state = PS_WAITING;
}
@@ -558,21 +769,16 @@
void
GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone)
{
- if (NULL != phone->speaker)
+ struct GNUNET_CONVERSATION_Caller *caller;
+
+ while (NULL != (caller = phone->caller_head))
{
- phone->speaker->disable_speaker (phone->speaker->cls);
- phone->speaker = NULL;
+ phone->event_handler (phone->event_handler_cls,
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP,
+ caller,
+ caller->caller_id_str);
+ GNUNET_CONVERSATION_caller_hang_up (caller);
}
- if (NULL != phone->mic)
- {
- phone->mic->disable_microphone (phone->mic->cls);
- phone->mic = NULL;
- }
- if (NULL != phone->qe)
- {
- GNUNET_NAMESTORE_cancel (phone->qe);
- phone->qe = NULL;
- }
if (NULL != phone->ns)
{
GNUNET_NAMESTORE_disconnect (phone->ns);
@@ -592,554 +798,33 @@
}
-/* ******************************* Call API *************************** */
-
/**
- * Possible states of the phone.
- */
-enum CallState
-{
- /**
- * We still need to lookup the callee.
- */
- CS_LOOKUP = 0,
-
- /**
- * The call is ringing.
- */
- CS_RINGING,
-
- /**
- * The call is in an active conversation.
- */
- CS_ACTIVE,
-
- /**
- * The call is in termination.
- */
- CS_SHUTDOWN
-};
-
-
-/**
- * Handle for an outgoing call.
- */
-struct GNUNET_CONVERSATION_Call
-{
-
- /**
- * Our configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Handle to talk with CONVERSATION service.
- */
- struct GNUNET_CLIENT_Connection *client;
-
- /**
- * Our caller identity.
- */
- struct GNUNET_IDENTITY_Ego *caller_id;
-
- /**
- * Target callee as a GNS address/name.
- */
- char *callee;
-
- /**
- * Our speaker.
- */
- struct GNUNET_SPEAKER_Handle *speaker;
-
- /**
- * Our microphone.
- */
- struct GNUNET_MICROPHONE_Handle *mic;
-
- /**
- * Function to call with events.
- */
- GNUNET_CONVERSATION_EventHandler event_handler;
-
- /**
- * Closure for @e event_handler
- */
- void *event_handler_cls;
-
- /**
- * Handle for transmitting to the CONVERSATION service.
- */
- struct GNUNET_MQ_Handle *mq;
-
- /**
- * Connection to GNS (can be NULL).
- */
- struct GNUNET_GNS_Handle *gns;
-
- /**
- * Active GNS lookup (or NULL).
- */
- struct GNUNET_GNS_LookupRequest *gns_lookup;
-
- /**
- * Target phone record, only valid after the lookup is done.
- */
- struct GNUNET_CONVERSATION_PhoneRecord phone_record;
-
- /**
- * State machine for the call.
- */
- enum CallState state;
-
-};
-
-
-/**
- * The call got disconnected, reconnect to the service.
+ * Pause conversation of an active call. This will disconnect the speaker
+ * and the microphone. The call can later be resumed with
+ * #GNUNET_CONVERSATION_caller_resume.
*
- * @param call call to reconnect
+ * @param phone phone to pause
*/
-static void
-reconnect_call (struct GNUNET_CONVERSATION_Call *call);
-
-
-/**
- * We received a `struct ClientPhoneBusyMessage`
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call`
- * @param msg the message
- */
-static void
-handle_call_busy (void *cls,
- const struct GNUNET_MessageHeader *msg)
+void
+GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller)
{
- struct GNUNET_CONVERSATION_Call *call = cls;
-
- switch (call->state)
- {
- case CS_LOOKUP:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_RINGING:
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_BUSY);
- GNUNET_CONVERSATION_call_stop (call, NULL);
- break;
- case CS_ACTIVE:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_SHUTDOWN:
- GNUNET_CONVERSATION_call_stop (call, NULL);
- break;
- }
-}
-
-
-/**
- * Process recorded audio data.
- *
- * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
- * @param data_size number of bytes in @a data
- * @param data audio data to play
- */
-static void
-transmit_call_audio (void *cls,
- size_t data_size,
- const void *data)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
- struct GNUNET_MQ_Envelope *e;
- struct ClientAudioMessage *am;
-
- GNUNET_assert (CS_ACTIVE == call->state);
- e = GNUNET_MQ_msg_extra (am,
- data_size,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
- memcpy (&am[1], data, data_size);
- GNUNET_MQ_send (call->mq, e);
-}
-
-
-/**
- * We received a `struct ClientPhonePickedupMessage`
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call`
- * @param msg the message
- */
-static void
-handle_call_picked_up (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
- const struct ClientPhonePickedupMessage *am;
- const char *metadata;
- size_t size;
-
- am = (const struct ClientPhonePickedupMessage *) msg;
- size = ntohs (am->header.size) - sizeof (struct ClientPhonePickedupMessage);
- metadata = (const char *) &am[1];
- if ( (0 == size) ||
- ('\0' != metadata[size - 1]) )
- metadata = NULL;
- switch (call->state)
- {
- case CS_LOOKUP:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_RINGING:
- call->state = CS_ACTIVE;
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_READY,
- metadata);
- call->speaker->enable_speaker (call->speaker->cls);
- call->mic->enable_microphone (call->mic->cls,
- &transmit_call_audio,
- call);
- break;
- case CS_ACTIVE:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_SHUTDOWN:
- GNUNET_CONVERSATION_call_stop (call, NULL);
- break;
- }
-}
-
-
-/**
- * We received a `struct ClientPhoneHangupMessage`
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call`
- * @param msg the message
- */
-static void
-handle_call_hangup (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
- const struct ClientPhoneHangupMessage *am;
- const char *reason;
- size_t size;
-
- am = (const struct ClientPhoneHangupMessage *) msg;
- size = ntohs (am->header.size) - sizeof (struct ClientPhoneHangupMessage);
- reason = (const char *) &am[1];
- if ( (0 == size) ||
- ('\0' != reason[size - 1]) )
- reason = NULL;
- switch (call->state)
- {
- case CS_LOOKUP:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_RINGING:
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_TERMINATED,
- reason);
- GNUNET_CONVERSATION_call_stop (call, NULL);
- return;
- case CS_ACTIVE:
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_TERMINATED,
- reason);
- GNUNET_CONVERSATION_call_stop (call, NULL);
- return;
- case CS_SHUTDOWN:
- GNUNET_CONVERSATION_call_stop (call, NULL);
- break;
- }
-}
-
-
-/**
- * We received a `struct ClientAudioMessage`
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call`
- * @param msg the message
- */
-static void
-handle_call_audio_message (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
- const struct ClientAudioMessage *am;
-
- am = (const struct ClientAudioMessage *) msg;
- switch (call->state)
- {
- case CS_LOOKUP:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_RINGING:
- GNUNET_break (0);
- reconnect_call (call);
- break;
- case CS_ACTIVE:
- call->speaker->play (call->speaker->cls,
- ntohs (msg->size) - sizeof (struct
ClientAudioMessage),
- &am[1]);
- break;
- case CS_SHUTDOWN:
- GNUNET_CONVERSATION_call_stop (call, NULL);
- break;
-
- }
-}
-
-
-/**
- * Iterator called on obtained result for a GNS lookup.
- *
- * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
- * @param rd_count number of records in @a rd
- * @param rd the records in reply
- */
-static void
-handle_gns_response (void *cls,
- uint32_t rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
- uint32_t i;
- struct GNUNET_MQ_Envelope *e;
- struct ClientCallMessage *ccm;
-
- call->gns_lookup = NULL;
- for (i=0;i<rd_count;i++)
- {
- if (GNUNET_GNSRECORD_TYPE_PHONE == rd[i].record_type)
- {
- if (rd[i].data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
- {
- GNUNET_break_op (0);
- continue;
- }
- memcpy (&call->phone_record,
- rd[i].data,
- rd[i].data_size);
- e = GNUNET_MQ_msg (ccm, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL);
- ccm->line = call->phone_record.line;
- ccm->target = call->phone_record.peer;
- ccm->caller_id = *GNUNET_IDENTITY_ego_get_private_key (call->caller_id);
- GNUNET_MQ_send (call->mq, e);
- call->state = CS_RINGING;
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_RINGING);
- return;
- }
- }
- /* not found */
- call->event_handler (call->event_handler_cls,
- GNUNET_CONVERSATION_EC_GNS_FAIL);
- GNUNET_CONVERSATION_call_stop (call, NULL);
-}
-
-
-/**
- * We encountered an error talking with the conversation service.
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call`
- * @param error details about the error
- */
-static void
-call_error_handler (void *cls,
- enum GNUNET_MQ_Error error)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
-
GNUNET_break (0);
- FPRINTF (stderr,
- _("Internal error %d\n"),
- error);
- reconnect_call (call);
}
/**
- * The call got disconnected, reconnect to the service.
+ * Resume suspended conversation of a phone.
*
- * @param call call to reconnect
+ * @param phone phone to resume
+ * @param speaker speaker to use
+ * @param mic microphone to use
*/
-static void
-reconnect_call (struct GNUNET_CONVERSATION_Call *call)
-{
- static struct GNUNET_MQ_MessageHandler handlers[] =
- {
- { &handle_call_busy,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY,
- sizeof (struct ClientPhoneBusyMessage) },
- { &handle_call_picked_up,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP,
- 0 },
- { &handle_call_hangup,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
- 0 },
- { &handle_call_audio_message,
- GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
- 0 },
- { NULL, 0, 0 }
- };
- struct GNUNET_CRYPTO_EcdsaPublicKey my_zone;
-
- if (CS_ACTIVE == call->state)
- {
- call->speaker->disable_speaker (call->speaker->cls);
- call->mic->disable_microphone (call->mic->cls);
- }
- if (NULL != call->mq)
- {
- GNUNET_MQ_destroy (call->mq);
- call->mq = NULL;
- }
- if (NULL != call->client)
- {
- GNUNET_CLIENT_disconnect (call->client);
- call->client = NULL;
- }
- call->state = CS_SHUTDOWN;
- call->client = GNUNET_CLIENT_connect ("conversation", call->cfg);
- if (NULL == call->client)
- return;
- call->mq = GNUNET_MQ_queue_for_connection_client (call->client,
- handlers,
- &call_error_handler,
- call);
- call->state = CS_LOOKUP;
- GNUNET_IDENTITY_ego_get_public_key (call->caller_id,
- &my_zone);
- call->gns_lookup = GNUNET_GNS_lookup (call->gns,
- call->callee,
- &my_zone,
- GNUNET_GNSRECORD_TYPE_PHONE,
- GNUNET_NO,
- NULL /* FIXME: add shortening support
*/,
- &handle_gns_response, call);
- GNUNET_assert (NULL != call->gns_lookup);
-}
-
-
-/**
- * Call the phone of another user.
- *
- * @param cfg configuration to use, specifies our phone service
- * @param caller_id identity of the caller
- * @param callee GNS name of the callee (used to locate the callee's record)
- * @param speaker speaker to use (will be used automatically immediately once
the
- * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT
generate
- * a ring tone on the speaker
- * @param mic microphone to use (will be used automatically immediately once
the
- * #GNUNET_CONVERSATION_EC_READY event is generated)
- * @param event_handler how to notify the owner of the phone about events
- * @param event_handler_cls closure for @a event_handler
- */
-struct GNUNET_CONVERSATION_Call *
-GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_IDENTITY_Ego *caller_id,
- const char *callee,
- struct GNUNET_SPEAKER_Handle *speaker,
- struct GNUNET_MICROPHONE_Handle *mic,
- GNUNET_CONVERSATION_EventHandler event_handler,
- void *event_handler_cls)
-{
- struct GNUNET_CONVERSATION_Call *call;
-
- call = GNUNET_new (struct GNUNET_CONVERSATION_Call);
- call->cfg = cfg;
- call->caller_id = caller_id;
- call->callee = GNUNET_strdup (callee);
- call->speaker = speaker;
- call->mic = mic;
- call->event_handler = event_handler;
- call->event_handler_cls = event_handler_cls;
- call->gns = GNUNET_GNS_connect (cfg);
- reconnect_call (call);
-
- if ( (NULL == call->client) ||
- (NULL == call->gns) )
- {
- GNUNET_CONVERSATION_call_stop (call, NULL);
- return NULL;
- }
- return call;
-}
-
-
-/**
- * We've sent the hang up message, now finish terminating the call.
- *
- * @param cls the `struct GNUNET_CONVERSATION_Call` to terminate
- */
-static void
-finish_stop (void *cls)
-{
- struct GNUNET_CONVERSATION_Call *call = cls;
-
- GNUNET_assert (CS_SHUTDOWN == call->state);
- GNUNET_CONVERSATION_call_stop (call, NULL);
-}
-
-
-/**
- * Terminate a call. The call may be ringing or ready at this time.
- *
- * @param call call to terminate
- * @param reason if the call was active (ringing or ready) this will be the
- * reason given to the other user for why we hung up
- */
void
-GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call,
- const char *reason)
+GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic)
{
- struct GNUNET_MQ_Envelope *e;
- struct ClientPhoneHangupMessage *hang;
- size_t slen;
-
- if ( (NULL != call->speaker) &&
- (CS_ACTIVE == call->state) )
- call->speaker->disable_speaker (call->speaker->cls);
- if ( (NULL != call->mic) &&
- (CS_ACTIVE == call->state) )
- call->mic->disable_microphone (call->mic->cls);
- if (NULL != reason)
- {
- slen = strlen (reason) + 1;
- e = GNUNET_MQ_msg_extra (hang, slen,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
- memcpy (&hang[1], reason, slen);
- GNUNET_MQ_notify_sent (e, &finish_stop, call);
- GNUNET_MQ_send (call->mq, e);
- call->state = CS_SHUTDOWN;
- return;
- }
- if (NULL != call->mq)
- {
- GNUNET_MQ_destroy (call->mq);
- call->mq = NULL;
- }
- if (NULL != call->client)
- {
- GNUNET_CLIENT_disconnect (call->client);
- call->client = NULL;
- }
- if (NULL != call->gns_lookup)
- {
- GNUNET_GNS_lookup_cancel (call->gns_lookup);
- call->gns_lookup = NULL;
- }
- if (NULL != call->gns)
- {
- GNUNET_GNS_disconnect (call->gns);
- call->gns = NULL;
- }
- GNUNET_free (call->callee);
- GNUNET_free (call);
+ GNUNET_break (0);
}
-
/* end of conversation_api.c */
Added: gnunet/src/conversation/conversation_api_call.c
===================================================================
--- gnunet/src/conversation/conversation_api_call.c
(rev 0)
+++ gnunet/src/conversation/conversation_api_call.c 2013-11-15 19:06:55 UTC
(rev 30734)
@@ -0,0 +1,678 @@
+/*
+ This file is part of GNUnet
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file conversation/conversation_api_call.c
+ * @brief call API to the conversation service
+ * @author Simon Dieterle
+ * @author Andreas Fuchs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_conversation_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_gns_service.h"
+#include "conversation.h"
+
+
+/**
+ * Possible states of the phone.
+ */
+enum CallState
+{
+ /**
+ * We still need to lookup the callee.
+ */
+ CS_LOOKUP = 0,
+
+ /**
+ * The call is ringing.
+ */
+ CS_RINGING,
+
+ /**
+ * The call is in an active conversation.
+ */
+ CS_ACTIVE,
+
+ /**
+ * The call is in termination.
+ */
+ CS_SHUTDOWN,
+
+ /**
+ * The call was suspended by the caller.
+ */
+ CS_SUSPENDED_CALLER,
+
+ /**
+ * The call was suspended by the callee.
+ */
+ CS_SUSPENDED_CALLEE,
+
+ /**
+ * The call was suspended by both caller and callee.
+ */
+ CS_SUSPENDED_BOTH
+};
+
+
+/**
+ * Handle for an outgoing call.
+ */
+struct GNUNET_CONVERSATION_Call
+{
+
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Handle to talk with CONVERSATION service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Our caller identity.
+ */
+ struct GNUNET_IDENTITY_Ego *caller_id;
+
+ /**
+ * Target callee as a GNS address/name.
+ */
+ char *callee;
+
+ /**
+ * Our speaker.
+ */
+ struct GNUNET_SPEAKER_Handle *speaker;
+
+ /**
+ * Our microphone.
+ */
+ struct GNUNET_MICROPHONE_Handle *mic;
+
+ /**
+ * Function to call with events.
+ */
+ GNUNET_CONVERSATION_CallEventHandler event_handler;
+
+ /**
+ * Closure for @e event_handler
+ */
+ void *event_handler_cls;
+
+ /**
+ * Handle for transmitting to the CONVERSATION service.
+ */
+ struct GNUNET_MQ_Handle *mq;
+
+ /**
+ * Connection to GNS (can be NULL).
+ */
+ struct GNUNET_GNS_Handle *gns;
+
+ /**
+ * Active GNS lookup (or NULL).
+ */
+ struct GNUNET_GNS_LookupRequest *gns_lookup;
+
+ /**
+ * Target phone record, only valid after the lookup is done.
+ */
+ struct GNUNET_CONVERSATION_PhoneRecord phone_record;
+
+ /**
+ * State machine for the call.
+ */
+ enum CallState state;
+
+};
+
+
+/**
+ * The call got disconnected, reconnect to the service.
+ *
+ * @param call call to reconnect
+ */
+static void
+reconnect_call (struct GNUNET_CONVERSATION_Call *call);
+
+
+/**
+ * Process recorded audio data.
+ *
+ * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
+ * @param data_size number of bytes in @a data
+ * @param data audio data to play
+ */
+static void
+transmit_call_audio (void *cls,
+ size_t data_size,
+ const void *data)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+ struct GNUNET_MQ_Envelope *e;
+ struct ClientAudioMessage *am;
+
+ GNUNET_assert (CS_ACTIVE == call->state);
+ e = GNUNET_MQ_msg_extra (am,
+ data_size,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
+ memcpy (&am[1], data, data_size);
+ GNUNET_MQ_send (call->mq, e);
+}
+
+
+/**
+ * We received a `struct ClientPhoneSuspendMessage`
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param msg the message
+ */
+static void
+handle_call_suspend (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ switch (call->state)
+ {
+ case CS_LOOKUP:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_RINGING:
+ GNUNET_break_op (0);
+ reconnect_call (call);
+ break;
+ case CS_SUSPENDED_CALLER:
+ call->state = CS_SUSPENDED_BOTH;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_SUSPENDED);
+ break;
+ case CS_SUSPENDED_CALLEE:
+ case CS_SUSPENDED_BOTH:
+ GNUNET_break_op (0);
+ break;
+ case CS_ACTIVE:
+ call->state = CS_SUSPENDED_CALLEE;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_SUSPENDED);
+ call->speaker->disable_speaker (call->speaker->cls);
+ call->mic->disable_microphone (call->mic->cls);
+ break;
+ case CS_SHUTDOWN:
+ GNUNET_CONVERSATION_call_stop (call);
+ break;
+ }
+}
+
+
+/**
+ * We received a `struct ClientPhoneResumeMessage`
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param msg the message
+ */
+static void
+handle_call_resume (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ switch (call->state)
+ {
+ case CS_LOOKUP:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_RINGING:
+ GNUNET_break_op (0);
+ reconnect_call (call);
+ break;
+ case CS_SUSPENDED_CALLER:
+ GNUNET_break_op (0);
+ break;
+ case CS_SUSPENDED_CALLEE:
+ call->state = CS_ACTIVE;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_RESUMED);
+ call->speaker->enable_speaker (call->speaker->cls);
+ call->mic->enable_microphone (call->mic->cls,
+ &transmit_call_audio,
+ call);
+ break;
+ case CS_SUSPENDED_BOTH:
+ call->state = CS_SUSPENDED_CALLER;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_RESUMED);
+ break;
+ case CS_ACTIVE:
+ GNUNET_break_op (0);
+ break;
+ case CS_SHUTDOWN:
+ GNUNET_CONVERSATION_call_stop (call);
+ break;
+ }
+}
+
+
+/**
+ * We received a `struct ClientPhonePickedupMessage`
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param msg the message
+ */
+static void
+handle_call_picked_up (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ switch (call->state)
+ {
+ case CS_LOOKUP:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_RINGING:
+ call->state = CS_ACTIVE;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_PICKED_UP);
+ call->speaker->enable_speaker (call->speaker->cls);
+ call->mic->enable_microphone (call->mic->cls,
+ &transmit_call_audio,
+ call);
+ break;
+ case CS_SUSPENDED_CALLER:
+ case CS_SUSPENDED_CALLEE:
+ case CS_SUSPENDED_BOTH:
+ case CS_ACTIVE:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_SHUTDOWN:
+ GNUNET_CONVERSATION_call_stop (call);
+ break;
+ }
+}
+
+
+/**
+ * We received a `struct ClientPhoneHangupMessage`
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param msg the message
+ */
+static void
+handle_call_hangup (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ switch (call->state)
+ {
+ case CS_LOOKUP:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_RINGING:
+ case CS_SUSPENDED_CALLER:
+ case CS_SUSPENDED_CALLEE:
+ case CS_SUSPENDED_BOTH:
+ case CS_ACTIVE:
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_HUNG_UP);
+ GNUNET_CONVERSATION_call_stop (call);
+ return;
+ case CS_SHUTDOWN:
+ GNUNET_CONVERSATION_call_stop (call);
+ break;
+ }
+}
+
+
+/**
+ * We received a `struct ClientAudioMessage`
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param msg the message
+ */
+static void
+handle_call_audio_message (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+ const struct ClientAudioMessage *am;
+
+ am = (const struct ClientAudioMessage *) msg;
+ switch (call->state)
+ {
+ case CS_LOOKUP:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_RINGING:
+ GNUNET_break (0);
+ reconnect_call (call);
+ break;
+ case CS_SUSPENDED_CALLER:
+ /* can happen: we suspended, other peer did not yet
+ learn about this. */
+ break;
+ case CS_SUSPENDED_CALLEE:
+ case CS_SUSPENDED_BOTH:
+ /* can (rarely) also happen: other peer suspended, but mesh might
+ have had delayed data on the unreliable channel */
+ break;
+ case CS_ACTIVE:
+ call->speaker->play (call->speaker->cls,
+ ntohs (msg->size) - sizeof (struct
ClientAudioMessage),
+ &am[1]);
+ break;
+ case CS_SHUTDOWN:
+ GNUNET_CONVERSATION_call_stop (call);
+ break;
+ }
+}
+
+
+/**
+ * Iterator called on obtained result for a GNS lookup.
+ *
+ * @param cls closure with the `struct GNUNET_CONVERSATION_Call`
+ * @param rd_count number of records in @a rd
+ * @param rd the records in reply
+ */
+static void
+handle_gns_response (void *cls,
+ uint32_t rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+ uint32_t i;
+ struct GNUNET_MQ_Envelope *e;
+ struct ClientCallMessage *ccm;
+
+ call->gns_lookup = NULL;
+ for (i=0;i<rd_count;i++)
+ {
+ if (GNUNET_GNSRECORD_TYPE_PHONE == rd[i].record_type)
+ {
+ if (rd[i].data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ memcpy (&call->phone_record,
+ rd[i].data,
+ rd[i].data_size);
+ e = GNUNET_MQ_msg (ccm, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL);
+ ccm->line = call->phone_record.line;
+ ccm->target = call->phone_record.peer;
+ ccm->caller_id = *GNUNET_IDENTITY_ego_get_private_key (call->caller_id);
+ GNUNET_MQ_send (call->mq, e);
+ call->state = CS_RINGING;
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_RINGING);
+ return;
+ }
+ }
+ /* not found */
+ call->event_handler (call->event_handler_cls,
+ GNUNET_CONVERSATION_EC_CALL_GNS_FAIL);
+ GNUNET_CONVERSATION_call_stop (call);
+}
+
+
+/**
+ * We encountered an error talking with the conversation service.
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call`
+ * @param error details about the error
+ */
+static void
+call_error_handler (void *cls,
+ enum GNUNET_MQ_Error error)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Internal MQ error %d\n"),
+ error);
+ reconnect_call (call);
+}
+
+
+/**
+ * The call got disconnected, reconnect to the service.
+ *
+ * @param call call to reconnect
+ */
+static void
+reconnect_call (struct GNUNET_CONVERSATION_Call *call)
+{
+ static struct GNUNET_MQ_MessageHandler handlers[] =
+ {
+ { &handle_call_suspend,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
+ sizeof (struct ClientPhoneSuspendMessage) },
+ { &handle_call_resume,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
+ sizeof (struct ClientPhoneResumeMessage) },
+ { &handle_call_picked_up,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP,
+ sizeof (struct ClientPhonePickedupMessage) },
+ { &handle_call_hangup,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
+ sizeof (struct ClientPhoneHangupMessage) },
+ { &handle_call_audio_message,
+ GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
+ 0 },
+ { NULL, 0, 0 }
+ };
+ struct GNUNET_CRYPTO_EcdsaPublicKey my_zone;
+
+ if (CS_ACTIVE == call->state)
+ {
+ call->speaker->disable_speaker (call->speaker->cls);
+ call->mic->disable_microphone (call->mic->cls);
+ }
+ if (NULL != call->mq)
+ {
+ GNUNET_MQ_destroy (call->mq);
+ call->mq = NULL;
+ }
+ if (NULL != call->client)
+ {
+ GNUNET_CLIENT_disconnect (call->client);
+ call->client = NULL;
+ }
+ call->state = CS_SHUTDOWN;
+ call->client = GNUNET_CLIENT_connect ("conversation", call->cfg);
+ if (NULL == call->client)
+ return;
+ call->mq = GNUNET_MQ_queue_for_connection_client (call->client,
+ handlers,
+ &call_error_handler,
+ call);
+ call->state = CS_LOOKUP;
+ GNUNET_IDENTITY_ego_get_public_key (call->caller_id,
+ &my_zone);
+ call->gns_lookup = GNUNET_GNS_lookup (call->gns,
+ call->callee,
+ &my_zone,
+ GNUNET_GNSRECORD_TYPE_PHONE,
+ GNUNET_NO,
+ NULL /* FIXME: add shortening support
*/,
+ &handle_gns_response, call);
+ GNUNET_assert (NULL != call->gns_lookup);
+}
+
+
+/**
+ * Call the phone of another user.
+ *
+ * @param cfg configuration to use, specifies our phone service
+ * @param caller_id identity of the caller
+ * @param callee GNS name of the callee (used to locate the callee's record)
+ * @param speaker speaker to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT
generate
+ * a ring tone on the speaker
+ * @param mic microphone to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated)
+ * @param event_handler how to notify the owner of the phone about events
+ * @param event_handler_cls closure for @a event_handler
+ */
+struct GNUNET_CONVERSATION_Call *
+GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_IDENTITY_Ego *caller_id,
+ const char *callee,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic,
+ GNUNET_CONVERSATION_CallEventHandler
event_handler,
+ void *event_handler_cls)
+{
+ struct GNUNET_CONVERSATION_Call *call;
+
+ call = GNUNET_new (struct GNUNET_CONVERSATION_Call);
+ call->cfg = cfg;
+ call->caller_id = caller_id;
+ call->callee = GNUNET_strdup (callee);
+ call->speaker = speaker;
+ call->mic = mic;
+ call->event_handler = event_handler;
+ call->event_handler_cls = event_handler_cls;
+ call->gns = GNUNET_GNS_connect (cfg);
+ reconnect_call (call);
+
+ if ( (NULL == call->client) ||
+ (NULL == call->gns) )
+ {
+ GNUNET_CONVERSATION_call_stop (call);
+ return NULL;
+ }
+ return call;
+}
+
+
+/**
+ * We've sent the hang up message, now finish terminating the call.
+ *
+ * @param cls the `struct GNUNET_CONVERSATION_Call` to terminate
+ */
+static void
+finish_stop (void *cls)
+{
+ struct GNUNET_CONVERSATION_Call *call = cls;
+
+ GNUNET_assert (CS_SHUTDOWN == call->state);
+ GNUNET_CONVERSATION_call_stop (call);
+}
+
+
+/**
+ * Terminate a call. The call may be ringing or ready at this time.
+ *
+ * @param call call to terminate
+ * @param reason if the call was active (ringing or ready) this will be the
+ * reason given to the other user for why we hung up
+ */
+void
+GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call)
+{
+ struct GNUNET_MQ_Envelope *e;
+ struct ClientPhoneHangupMessage *hang;
+
+ if ( (NULL != call->speaker) &&
+ (CS_ACTIVE == call->state) )
+ call->speaker->disable_speaker (call->speaker->cls);
+ if ( (NULL != call->mic) &&
+ (CS_ACTIVE == call->state) )
+ call->mic->disable_microphone (call->mic->cls);
+ if (CS_SHUTDOWN != call->state)
+ {
+ e = GNUNET_MQ_msg (hang,
GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
+ GNUNET_MQ_notify_sent (e, &finish_stop, call);
+ GNUNET_MQ_send (call->mq, e);
+ call->state = CS_SHUTDOWN;
+ return;
+ }
+ if (NULL != call->mq)
+ {
+ GNUNET_MQ_destroy (call->mq);
+ call->mq = NULL;
+ }
+ if (NULL != call->client)
+ {
+ GNUNET_CLIENT_disconnect (call->client);
+ call->client = NULL;
+ }
+ if (NULL != call->gns_lookup)
+ {
+ GNUNET_GNS_lookup_cancel (call->gns_lookup);
+ call->gns_lookup = NULL;
+ }
+ if (NULL != call->gns)
+ {
+ GNUNET_GNS_disconnect (call->gns);
+ call->gns = NULL;
+ }
+ GNUNET_free (call->callee);
+ GNUNET_free (call);
+}
+
+
+/**
+ * Pause a call. Temporarily suspends the use of speaker and
+ * microphone.
+ *
+ * @param call call to pause
+ */
+void
+GNUNET_CONVERSATION_call_suspend (struct GNUNET_CONVERSATION_Call *call)
+{
+ GNUNET_break (0);
+}
+
+
+/**
+ * Resumes a call after #GNUNET_CONVERSATION_call_pause.
+ *
+ * @param call call to resume
+ * @param speaker speaker to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT
generate
+ * a ring tone on the speaker
+ * @param mic microphone to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated)
+ */
+void
+GNUNET_CONVERSATION_call_resume (struct GNUNET_CONVERSATION_Call *call,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic)
+{
+ GNUNET_break (0);
+}
+
+
+/* end of conversation_api_call.c */
Modified: gnunet/src/conversation/gnunet-conversation.c
===================================================================
--- gnunet/src/conversation/gnunet-conversation.c 2013-11-15 17:00:41 UTC
(rev 30733)
+++ gnunet/src/conversation/gnunet-conversation.c 2013-11-15 19:06:55 UTC
(rev 30734)
@@ -86,16 +86,64 @@
/**
+ * List of incoming calls
+ */
+struct CallList
+{
+
+ /**
+ * A DLL.
+ */
+ struct CallList *prev;
+
+ /**
+ * A DLL.
+ */
+ struct CallList *next;
+
+ /**
+ * Handle to hang up or activate.
+ */
+ struct GNUNET_CONVERSATION_Caller *caller;
+
+ /**
+ * String identifying the caller.
+ */
+ const char *caller_id;
+
+ /**
+ * Unique number of the call.
+ */
+ unsigned int caller_num;
+};
+
+
+/**
* Phone handle
*/
static struct GNUNET_CONVERSATION_Phone *phone;
/**
- * Call handle
+ * Call handle (for active outgoing call).
*/
static struct GNUNET_CONVERSATION_Call *call;
/**
+ * Caller handle (for active incoming call).
+ */
+static struct CallList *cl_active;
+
+/**
+ * Head of calls waiting to be accepted.
+ */
+static struct CallList *cl_head;
+
+/**
+ * Tail of calls waiting to be accepted.
+ */
+static struct CallList *cl_tail;
+
+/**
* Desired phone line.
*/
static unsigned int line;
@@ -151,6 +199,11 @@
static enum ConversationState state;
/**
+ * Counts the number of incoming calls we have had so far.
+ */
+static unsigned int caller_num_gen;
+
+/**
* GNS address for this phone.
*/
static char *address;
@@ -165,54 +218,59 @@
* Function called with an event emitted by a phone.
*
* @param cls closure
- * @param code type of the event on the phone
- * @param ... additional information, depends on @a code
+ * @param code type of the event
+ * @param caller handle for the caller
+ * @param caller_id name of the caller in GNS
*/
static void
phone_event_handler (void *cls,
- enum GNUNET_CONVERSATION_EventCode code,
- ...)
+ enum GNUNET_CONVERSATION_PhoneEventCode code,
+ struct GNUNET_CONVERSATION_Caller *caller,
+ const char *caller_id)
{
- va_list va;
-
- va_start (va, code);
switch (code)
{
- case GNUNET_CONVERSATION_EC_RING:
- GNUNET_break (CS_LISTEN == state);
- GNUNET_free_non_null (peer_name);
- peer_name = GNUNET_strdup (va_arg (va, const char *));
+ case GNUNET_CONVERSATION_EC_PHONE_RING:
+ // FIXME: update state!
FPRINTF (stdout,
- _("Incoming call from `%s'.\nPlease /accept or /cancel the
call.\n"),
- peer_name);
- state = CS_RING;
+ _("Incoming call from `%s'.\nPlease /accept #%u or /cancel %u the
call.\n"),
+ caller_id,
+ caller_num_gen,
+ caller_num_gen);
break;
- case GNUNET_CONVERSATION_EC_RINGING:
- GNUNET_break (0);
- break;
- case GNUNET_CONVERSATION_EC_READY:
- GNUNET_break (0);
- break;
- case GNUNET_CONVERSATION_EC_GNS_FAIL:
- GNUNET_break (0);
- break;
- case GNUNET_CONVERSATION_EC_BUSY:
- GNUNET_break (0);
- break;
- case GNUNET_CONVERSATION_EC_TERMINATED:
- GNUNET_break ( (CS_RING == state) ||
- (CS_ACCEPTED == state) );
+ case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
+ // FIXME: update state!
FPRINTF (stdout,
_("Call terminated: %s\n"),
- va_arg (va, const char *));
- state = CS_LISTEN;
+ caller_id);
break;
}
- va_end (va);
}
/**
+ * Function called with an event emitted by a caller.
+ *
+ * @param cls closure with the `struct CallList` of the caller
+ * @param code type of the event issued by the caller
+ */
+static void
+caller_event_handler (void *cls,
+ enum GNUNET_CONVERSATION_CallerEventCode code)
+{
+ switch (code)
+ {
+ case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
+ // FIXME: notify user!
+ break;
+ case GNUNET_CONVERSATION_EC_CALLER_RESUME:
+ // FIXME: notify user!
+ break;
+ }
+}
+
+
+/**
* Start our phone.
*/
static void
@@ -257,26 +315,18 @@
/**
- * Function called with an event emitted by a phone.
+ * Function called with an event emitted by a call.
*
* @param cls closure
- * @param code type of the event on the phone
- * @param ... additional information, depends on @a code
+ * @param code type of the event on the call
*/
static void
call_event_handler (void *cls,
- enum GNUNET_CONVERSATION_EventCode code,
- ...)
+ enum GNUNET_CONVERSATION_CallEventCode code)
{
- va_list va;
-
- va_start (va, code);
switch (code)
{
- case GNUNET_CONVERSATION_EC_RING:
- GNUNET_break (0);
- break;
- case GNUNET_CONVERSATION_EC_RINGING:
+ case GNUNET_CONVERSATION_EC_CALL_RINGING:
GNUNET_break (CS_RESOLVING == state);
if (verbose)
FPRINTF (stdout,
@@ -284,41 +334,37 @@
_("Resolved address. Now ringing other party.\n"));
state = CS_RINGING;
break;
- case GNUNET_CONVERSATION_EC_READY:
+ case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
GNUNET_break (CS_RINGING == state);
FPRINTF (stdout,
- _("Connection established to `%s': %s\n"),
- peer_name,
- va_arg (va, const char *));
+ _("Connection established to `%s'\n"),
+ peer_name);
state = CS_CONNECTED;
break;
- case GNUNET_CONVERSATION_EC_GNS_FAIL:
+ case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
GNUNET_break (CS_RESOLVING == state);
FPRINTF (stdout,
_("Failed to resolve `%s'\n"),
ego_name);
call = NULL;
- start_phone ();
+ state = CS_LISTEN;
break;
- case GNUNET_CONVERSATION_EC_BUSY:
- GNUNET_break (CS_RINGING == state);
+ case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
FPRINTF (stdout,
"%s",
- _("Line busy\n"));
+ _("Call terminated\n"));
call = NULL;
- start_phone ();
+ state = CS_LISTEN;
break;
- case GNUNET_CONVERSATION_EC_TERMINATED:
- GNUNET_break ( (CS_RINGING == state) ||
- (CS_CONNECTED == state) );
- FPRINTF (stdout,
- _("Call terminated: %s\n"),
- va_arg (va, const char *));
- call = NULL;
- start_phone ();
+ case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
+ // FIXME: notify user
+ // state = CS_SUSPENDED_CALL;
break;
+ case GNUNET_CONVERSATION_EC_CALL_RESUMED:
+ // FIXME: notify user
+ // state = CS_CONNECTED;
+ break;
}
- va_end (va);
}
@@ -417,7 +463,7 @@
_("Hanging up on incoming phone call from `%s' to call `%s'.\n"),
peer_name,
arg);
- GNUNET_CONVERSATION_phone_hang_up (phone, NULL);
+ // GNUNET_CONVERSATION_caller_hang_up (caller);
break;
case CS_ACCEPTED:
FPRINTF (stderr,
@@ -430,7 +476,8 @@
FPRINTF (stderr,
_("Aborting call to `%s'\n"),
peer_name);
- GNUNET_CONVERSATION_call_stop (call, NULL);
+ // GNUNET_CONVERSATION_caller_hang_up (caller);
+ // GNUNET_CONVERSATION_call_stop (call);
call = NULL;
break;
case CS_CONNECTED:
@@ -497,11 +544,12 @@
peer_name);
return;
}
- GNUNET_assert (NULL != phone);
- GNUNET_CONVERSATION_phone_pick_up (phone,
- args,
- speaker,
- mic);
+ GNUNET_assert (NULL != cl_active);
+ GNUNET_CONVERSATION_caller_pick_up (cl_active->caller,
+ &caller_event_handler,
+ cl_active,
+ speaker,
+ mic);
state = CS_ACCEPTED;
}
@@ -604,14 +652,15 @@
}
if (NULL == call)
{
- GNUNET_assert (NULL != phone);
- GNUNET_CONVERSATION_phone_hang_up (phone,
- args);
+#if 0
+ GNUNET_assert (NULL != caller);
+ GNUNET_CONVERSATION_caller_hang_up (caller);
+#endif
state = CS_LISTEN;
}
else
{
- GNUNET_CONVERSATION_call_stop (call, args);
+ GNUNET_CONVERSATION_call_stop (call);
call = NULL;
start_phone ();
}
@@ -699,7 +748,7 @@
{
if (NULL != call)
{
- GNUNET_CONVERSATION_call_stop (call, NULL);
+ GNUNET_CONVERSATION_call_stop (call);
call = NULL;
}
if (NULL != phone)
Modified: gnunet/src/include/gnunet_conversation_service.h
===================================================================
--- gnunet/src/include/gnunet_conversation_service.h 2013-11-15 17:00:41 UTC
(rev 30733)
+++ gnunet/src/include/gnunet_conversation_service.h 2013-11-15 19:06:55 UTC
(rev 30734)
@@ -37,17 +37,10 @@
* using a separate service; CONVERSATION is supposed to be just
* the "bare bones" voice service.
*
- * Meta data passing is supported so that advanced services
- * can identify themselves appropriately.
- *
* As this is supposed to be a "secure" service, caller ID is of
* course provided as part of the basic implementation, as only the
* CONVERSATION service can know for sure who it is that we are
* talking to.
- *
- * TODO:
- * - call waiting
- * - put on hold
*/
#ifndef GNUNET_CONVERSATION_SERVICE_H
#define GNUNET_CONVERSATION_SERVICE_H
@@ -70,9 +63,19 @@
/**
* Version of the conversation API.
*/
-#define GNUNET_CONVERSATION_VERSION 0x00000002
+#define GNUNET_CONVERSATION_VERSION 0x00000003
+/**
+ * Handle to identify a particular caller. A caller is an entity that
+ * initiate a call to a phone. This struct identifies the caller to
+ * the user operating the phone. The entity that initiated the call
+ * will have a `struct GNUNET_CONVERSATION_Call`.
+ */
+struct GNUNET_CONVERSATION_Caller;
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
/**
* A phone record specifies which peer is hosting a given user and
* may also specify the phone line that is used (typically zero).
@@ -100,67 +103,77 @@
};
+GNUNET_NETWORK_STRUCT_END
/**
- * Information about the current status of a call. Each call
- * progresses from ring over ready to terminated. Steps may
- * be skipped.
+ * Information about active callers to a phone.
*/
-enum GNUNET_CONVERSATION_EventCode
+enum GNUNET_CONVERSATION_PhoneEventCode
{
/**
- * The phone is ringing, caller ID is provided in the varargs as
- * a `const char *`. The caller ID will be a GNS name.
+ * We are the callee and the phone is ringing.
+ * We should accept the call or hang up.
*/
- GNUNET_CONVERSATION_EC_RING,
+ GNUNET_CONVERSATION_EC_PHONE_RING,
/**
- * We are the caller and are now ringing the other party.
- * The varargs will be empty.
+ * The conversation was terminated by the caller.
+ * We must no longer use the caller's handle.
*/
- GNUNET_CONVERSATION_EC_RINGING,
+ GNUNET_CONVERSATION_EC_PHONE_HUNG_UP
- /**
- * We are ready to talk, metadata about the call may be supplied
- * as a `const char *` in the varargs.
- */
- GNUNET_CONVERSATION_EC_READY,
+};
- /**
- * We failed to locate a phone record in GNS. After this invocation,
- * the respective call handle will be automatically destroyed and the
- * client must no longer call #GNUNET_CONVERSATION_call_stop.
- */
- GNUNET_CONVERSATION_EC_GNS_FAIL,
+/**
+ * Function called with an event emitted by a phone.
+ *
+ * @param cls closure
+ * @param code type of the event
+ * @param caller handle for the caller
+ * @param caller_id name of the caller in GNS
+ */
+typedef void (*GNUNET_CONVERSATION_PhoneEventHandler)(void *cls,
+ enum
GNUNET_CONVERSATION_PhoneEventCode code,
+ struct
GNUNET_CONVERSATION_Caller *caller,
+ const char *caller_id);
+
+
+/**
+ * Information about the current status of a call. Each call
+ * progresses from ring over ready to terminated. Steps may
+ * be skipped.
+ */
+enum GNUNET_CONVERSATION_CallerEventCode
+{
+
/**
- * The phone is busy. Varargs will be empty. After this invocation,
- * the respective call handle will be automatically destroyed and the
- * client must no longer call #GNUNET_CONVERSATION_call_stop.
+ * We are the callee and the caller suspended the call. Note that
+ * both sides can independently suspend and resume calls; a call is
+ * only "working" of both sides are active.
*/
- GNUNET_CONVERSATION_EC_BUSY,
+ GNUNET_CONVERSATION_EC_CALLER_SUSPEND,
/**
- * The conversation was terminated, a reason may be supplied as a
- * `const char *` in the varargs. After this invocation, the
- * respective call handle will be automatically destroyed and the
- * client must no longer call #GNUNET_CONVERSATION_call_stop.
+ * We are the callee and the caller resumed the call. Note that
+ * both sides can independently suspend and resume calls; a call is
+ * only "working" of both sides are active.
*/
- GNUNET_CONVERSATION_EC_TERMINATED
+ GNUNET_CONVERSATION_EC_CALLER_RESUME
};
/**
- * Function called with an event emitted by a phone.
+ * Function called with an event emitted by a caller.
+ * These events are only generated after the phone is
+ * picked up.
*
* @param cls closure
- * @param code type of the event on the phone
- * @param ... additional information, depends on @a code
+ * @param code type of the event for this caller
*/
-typedef void (*GNUNET_CONVERSATION_EventHandler)(void *cls,
- enum
GNUNET_CONVERSATION_EventCode code,
- ...);
+typedef void (*GNUNET_CONVERSATION_CallerEventHandler)(void *cls,
+ enum
GNUNET_CONVERSATION_CallerEventCode code);
/**
@@ -189,7 +202,7 @@
struct GNUNET_CONVERSATION_Phone *
GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle
*cfg,
const struct GNUNET_IDENTITY_Ego *ego,
- GNUNET_CONVERSATION_EventHandler
event_handler,
+ GNUNET_CONVERSATION_PhoneEventHandler
event_handler,
void *event_handler_cls);
@@ -207,31 +220,55 @@
/**
- * Picks up a (ringing) phone. This will connect the speaker
+ * Picks up a (ringing) phone call. This will connect the speaker
* to the microphone of the other party, and vice versa.
*
- * @param phone phone to pick up
- * @param metadata meta data to give to the other user about the pick up event
+ * @param caller handle that identifies which caller should be answered
+ * @param event_handler how to notify about events by the caller
+ * @param event_handler_cls closure for @a event_handler
* @param speaker speaker to use
* @param mic microphone to use
*/
void
-GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone,
- const char *metadata,
+GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
+ GNUNET_CONVERSATION_CallerEventHandler
event_handler,
+ void *event_handler_cls,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic);
+
+
+/**
+ * Pause conversation of an active call. This will disconnect the speaker
+ * and the microphone. The call can later be resumed with
+ * #GNUNET_CONVERSATION_caller_resume.
+ *
+ * @param phone phone to pause
+ */
+void
+GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller);
+
+
+/**
+ * Resume suspended conversation of a phone.
+ *
+ * @param phone phone to resume
+ * @param speaker speaker to use
+ * @param mic microphone to use
+ */
+void
+GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
struct GNUNET_SPEAKER_Handle *speaker,
struct GNUNET_MICROPHONE_Handle *mic);
/**
- * Hang up up a (possibly ringing) phone. This will notify the other
- * party that we are no longer interested in talking with them.
+ * Hang up up a (possibly ringing or paused) phone. This will notify
+ * the caller that we are no longer interested in talking with them.
*
- * @param phone phone to pick up
- * @param reason text we give to the other party about why we terminated the
conversation
+ * @param caller who should we hang up on
*/
void
-GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone,
- const char *reason);
+GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller);
/**
@@ -243,6 +280,8 @@
GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone);
+/* *********************** CALL API ************************ */
+
/**
* Handle for an outgoing call.
*/
@@ -250,6 +289,66 @@
/**
+ * Information about the current status of a call.
+ */
+enum GNUNET_CONVERSATION_CallEventCode
+{
+ /**
+ * We are the caller and are now ringing the other party (GNS lookup
+ * succeeded).
+ */
+ GNUNET_CONVERSATION_EC_CALL_RINGING,
+
+ /**
+ * We are the caller and are now ready to talk as the callee picked up.
+ */
+ GNUNET_CONVERSATION_EC_CALL_PICKED_UP,
+
+ /**
+ * We are the caller and failed to locate a phone record in GNS.
+ * After this invocation, the respective call handle will be
+ * automatically destroyed and the client must no longer call
+ * #GNUNET_CONVERSATION_call_stop or any other function on the
+ * call object.
+ */
+ GNUNET_CONVERSATION_EC_CALL_GNS_FAIL,
+
+ /**
+ * We are the caller and the callee called
+ * #GNUNET_CONVERSATION_caller_hang_up. After this invocation, the
+ * respective call handle will be automatically destroyed and the
+ * client must no longer call #GNUNET_CONVERSATION_call_stop.
+ */
+ GNUNET_CONVERSATION_EC_CALL_HUNG_UP,
+
+ /**
+ * We are the caller and the callee suspended the call. Note that
+ * both sides can independently suspend and resume calls; a call is
+ * only "working" of both sides are active.
+ */
+ GNUNET_CONVERSATION_EC_CALL_SUSPENDED,
+
+ /**
+ * We are the caller and the callee suspended the call. Note that
+ * both sides can independently suspend and resume calls; a call is
+ * only "working" of both sides are active.
+ */
+ GNUNET_CONVERSATION_EC_CALL_RESUMED
+
+};
+
+
+/**
+ * Function called with an event emitted for a call.
+ *
+ * @param cls closure
+ * @param code type of the event on the call
+ */
+typedef void (*GNUNET_CONVERSATION_CallEventHandler)(void *cls,
+ enum
GNUNET_CONVERSATION_CallEventCode code);
+
+
+/**
* Call the phone of another user.
*
* @param cfg configuration to use, specifies our phone service
@@ -269,20 +368,43 @@
const char *callee,
struct GNUNET_SPEAKER_Handle *speaker,
struct GNUNET_MICROPHONE_Handle *mic,
- GNUNET_CONVERSATION_EventHandler event_handler,
+ GNUNET_CONVERSATION_CallEventHandler
event_handler,
void *event_handler_cls);
/**
+ * Pause a call. Temporarily suspends the use of speaker and
+ * microphone.
+ *
+ * @param call call to pause
+ */
+void
+GNUNET_CONVERSATION_call_suspend (struct GNUNET_CONVERSATION_Call *call);
+
+
+/**
+ * Resumes a call after #GNUNET_CONVERSATION_call_pause.
+ *
+ * @param call call to resume
+ * @param speaker speaker to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated); we will NOT
generate
+ * a ring tone on the speaker
+ * @param mic microphone to use (will be used automatically immediately once
the
+ * #GNUNET_CONVERSATION_EC_READY event is generated)
+ */
+void
+GNUNET_CONVERSATION_call_resume (struct GNUNET_CONVERSATION_Call *call,
+ struct GNUNET_SPEAKER_Handle *speaker,
+ struct GNUNET_MICROPHONE_Handle *mic);
+
+
+/**
* Terminate a call. The call may be ringing or ready at this time.
*
* @param call call to terminate
- * @param reason if the call was active (ringing or ready) this will be the
- * reason given to the other user for why we hung up
*/
void
-GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call,
- const char *reason);
+GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call);
#if 0 /* keep Emacsens' auto-indent happy */
Modified: gnunet/src/include/gnunet_protocols.h
===================================================================
--- gnunet/src/include/gnunet_protocols.h 2013-11-15 17:00:41 UTC (rev
30733)
+++ gnunet/src/include/gnunet_protocols.h 2013-11-15 19:06:55 UTC (rev
30734)
@@ -2174,67 +2174,77 @@
/**
* Client -> Server message register a phone.
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER 730
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER 731
/**
* Client -> Server message to reject/hangup a call
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP 731
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP 732
/**
* Client -> Server message to reject/hangup a call
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP 732
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP 733
/**
* Client <- Server message to indicate a ringing phone
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL 733
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL 734
/**
* Client <- Server message to indicate a ringing phone
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING 734
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING 735
/**
- * Client <-> Server message to send audio data.
+ * Client <-> Server message to suspend connection.
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY 735
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND 736
/**
+ * Client <-> Server message to resume connection.
+ */
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME 737
+
+/**
* Client <-> Server message to send audio data.
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP 736
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP 738
/**
* Client <-> Server message to send audio data.
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO 737
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO 739
/**
* Mesh: call initiation
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING 738
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING 740
/**
* Mesh: hang up / refuse call
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP 739
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP 741
/**
* Mesh: pick up phone (establish audio channel)
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP 740
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP 742
/**
- * Mesh: phone is busy (refuse nicely)
+ * Mesh: phone suspended.
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY 741
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND 743
/**
+ * Mesh: phone resumed.
+ */
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME 744
+
+/**
* Mesh: audio data
*/
-#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO 742
+#define GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO 745
/*******************************************************************************
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r30734 - in gnunet/src: conversation include,
gnunet <=