diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-11-15 19:06:55 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-11-15 19:06:55 +0000 |
commit | dd594a4b0a7dbc57ea49f8a797a7a412e53baa53 (patch) | |
tree | 6a651b061395ebd9370cef01f14655ff50e81a66 /src/conversation/conversation_api.c | |
parent | 1c405f3fb76f509113526678dbe9a5736dfce394 (diff) | |
download | gnunet-dd594a4b0a7dbc57ea49f8a797a7a412e53baa53.tar.gz gnunet-dd594a4b0a7dbc57ea49f8a797a7a412e53baa53.zip |
-towards enabling call waiting in conversation -- creates FTBFS
Diffstat (limited to 'src/conversation/conversation_api.c')
-rw-r--r-- | src/conversation/conversation_api.c | 1115 |
1 files changed, 400 insertions, 715 deletions
diff --git a/src/conversation/conversation_api.c b/src/conversation/conversation_api.c index 63b072fc0..9dfc6e913 100644 --- a/src/conversation/conversation_api.c +++ b/src/conversation/conversation_api.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file conversation/conversation_api.c | 22 | * @file conversation/conversation_api.c |
23 | * @brief API to the conversation service | 23 | * @brief phone and caller API to the conversation service |
24 | * @author Simon Dieterle | 24 | * @author Simon Dieterle |
25 | * @author Andreas Fuchs | 25 | * @author Andreas Fuchs |
26 | * @author Christian Grothoff | 26 | * @author Christian Grothoff |
@@ -33,29 +33,127 @@ | |||
33 | 33 | ||
34 | 34 | ||
35 | /** | 35 | /** |
36 | * Possible states of the phone. | 36 | * Possible states of a caller. |
37 | */ | 37 | */ |
38 | enum PhoneState | 38 | enum CallerState |
39 | { | 39 | { |
40 | /** | 40 | /** |
41 | * We still need to register the phone. | 41 | * We still need to reverse lookup the caller ID. |
42 | */ | 42 | */ |
43 | PS_REGISTER = 0, | 43 | CS_RESOLVE, |
44 | 44 | ||
45 | /** | 45 | /** |
46 | * We are waiting for a call. | 46 | * The phone is ringing (user knows about incoming call). |
47 | */ | 47 | */ |
48 | PS_WAITING, | 48 | CS_RINGING, |
49 | 49 | ||
50 | /** | 50 | /** |
51 | * The phone is ringing. | 51 | * The phone is in an active conversation. |
52 | */ | 52 | */ |
53 | PS_RINGING, | 53 | CS_ACTIVE, |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * The phone is in an active conversation. | 56 | * We suspended the conversation. |
57 | */ | ||
58 | CS_CALLEE_SUSPENDED, | ||
59 | |||
60 | /** | ||
61 | * Caller suspended the conversation. | ||
62 | */ | ||
63 | CS_CALLER_SUSPENDED, | ||
64 | |||
65 | /** | ||
66 | * Both sides suspended the conversation. | ||
57 | */ | 67 | */ |
58 | PS_ACTIVE | 68 | CS_BOTH_SUSPENDED |
69 | }; | ||
70 | |||
71 | |||
72 | |||
73 | /** | ||
74 | * A caller is the handle we have for an incoming call. | ||
75 | */ | ||
76 | struct GNUNET_CONVERSATION_Caller | ||
77 | { | ||
78 | |||
79 | /** | ||
80 | * We keep all callers in a DLL. | ||
81 | */ | ||
82 | struct GNUNET_CONVERSATION_Caller *next; | ||
83 | |||
84 | /** | ||
85 | * We keep all callers in a DLL. | ||
86 | */ | ||
87 | struct GNUNET_CONVERSATION_Caller *prev; | ||
88 | |||
89 | /** | ||
90 | * Our phone. | ||
91 | */ | ||
92 | struct GNUNET_CONVERSATION_Phone *phone; | ||
93 | |||
94 | /** | ||
95 | * Function to call for phone events. | ||
96 | */ | ||
97 | GNUNET_CONVERSATION_CallerEventHandler event_handler; | ||
98 | |||
99 | /** | ||
100 | * Closure for @e event_handler | ||
101 | */ | ||
102 | void *event_handler_cls; | ||
103 | |||
104 | /** | ||
105 | * Speaker, or NULL if none is attached. | ||
106 | */ | ||
107 | struct GNUNET_SPEAKER_Handle *speaker; | ||
108 | |||
109 | /** | ||
110 | * Microphone, or NULL if none is attached. | ||
111 | */ | ||
112 | struct GNUNET_MICROPHONE_Handle *mic; | ||
113 | |||
114 | /** | ||
115 | * Active NAMESTORE lookup (or NULL). | ||
116 | */ | ||
117 | struct GNUNET_NAMESTORE_QueueEntry *qe; | ||
118 | |||
119 | /** | ||
120 | * Identity of the person calling us (valid while in state #PS_RINGING). | ||
121 | */ | ||
122 | struct GNUNET_CRYPTO_EcdsaPublicKey caller_id; | ||
123 | |||
124 | /** | ||
125 | * Caller ID of the person calling us as a string. | ||
126 | */ | ||
127 | char *caller_id_str; | ||
128 | |||
129 | /** | ||
130 | * Internal handle to identify the caller with the service. | ||
131 | */ | ||
132 | uint32_t cid; | ||
133 | |||
134 | /** | ||
135 | * State machine for the phone. | ||
136 | */ | ||
137 | enum CallerState state; | ||
138 | |||
139 | }; | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Possible states of a phone. | ||
144 | */ | ||
145 | enum PhoneState | ||
146 | { | ||
147 | /** | ||
148 | * We still need to register the phone. | ||
149 | */ | ||
150 | PS_REGISTER = 0, | ||
151 | |||
152 | /** | ||
153 | * We are waiting for calls. | ||
154 | */ | ||
155 | PS_READY | ||
156 | |||
59 | }; | 157 | }; |
60 | 158 | ||
61 | 159 | ||
@@ -83,24 +181,24 @@ struct GNUNET_CONVERSATION_Phone | |||
83 | struct GNUNET_CLIENT_Connection *client; | 181 | struct GNUNET_CLIENT_Connection *client; |
84 | 182 | ||
85 | /** | 183 | /** |
86 | * Function to call for phone events. | 184 | * We keep all callers in a DLL. |
87 | */ | 185 | */ |
88 | GNUNET_CONVERSATION_EventHandler event_handler; | 186 | struct GNUNET_CONVERSATION_Caller *caller_head; |
89 | 187 | ||
90 | /** | 188 | /** |
91 | * Closure for @e event_handler | 189 | * We keep all callers in a DLL. |
92 | */ | 190 | */ |
93 | void *event_handler_cls; | 191 | struct GNUNET_CONVERSATION_Caller *caller_tail; |
94 | 192 | ||
95 | /** | 193 | /** |
96 | * Speaker, or NULL if none is attached. | 194 | * Function to call for phone events. |
97 | */ | 195 | */ |
98 | struct GNUNET_SPEAKER_Handle *speaker; | 196 | GNUNET_CONVERSATION_PhoneEventHandler event_handler; |
99 | 197 | ||
100 | /** | 198 | /** |
101 | * Microphone, or NULL if none is attached. | 199 | * Closure for @e event_handler |
102 | */ | 200 | */ |
103 | struct GNUNET_MICROPHONE_Handle *mic; | 201 | void *event_handler_cls; |
104 | 202 | ||
105 | /** | 203 | /** |
106 | * Connection to NAMESTORE (for reverse lookup). | 204 | * Connection to NAMESTORE (for reverse lookup). |
@@ -108,11 +206,6 @@ struct GNUNET_CONVERSATION_Phone | |||
108 | struct GNUNET_NAMESTORE_Handle *ns; | 206 | struct GNUNET_NAMESTORE_Handle *ns; |
109 | 207 | ||
110 | /** | 208 | /** |
111 | * Active NAMESTORE lookup (or NULL). | ||
112 | */ | ||
113 | struct GNUNET_NAMESTORE_QueueEntry *qe; | ||
114 | |||
115 | /** | ||
116 | * Handle for transmitting to the CONVERSATION service. | 209 | * Handle for transmitting to the CONVERSATION service. |
117 | */ | 210 | */ |
118 | struct GNUNET_MQ_Handle *mq; | 211 | struct GNUNET_MQ_Handle *mq; |
@@ -128,11 +221,6 @@ struct GNUNET_CONVERSATION_Phone | |||
128 | struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone; | 221 | struct GNUNET_CRYPTO_EcdsaPrivateKey my_zone; |
129 | 222 | ||
130 | /** | 223 | /** |
131 | * Identity of the person calling us (valid while in state #PS_RINGING). | ||
132 | */ | ||
133 | struct GNUNET_CRYPTO_EcdsaPublicKey caller_id; | ||
134 | |||
135 | /** | ||
136 | * State machine for the phone. | 224 | * State machine for the phone. |
137 | */ | 225 | */ |
138 | enum PhoneState state; | 226 | enum PhoneState state; |
@@ -152,7 +240,7 @@ reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone); | |||
152 | /** | 240 | /** |
153 | * We have resolved the caller ID using our name service. | 241 | * We have resolved the caller ID using our name service. |
154 | * | 242 | * |
155 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | 243 | * @param cls the `struct GNUNET_CONVERSATION_Caller` |
156 | * @param zone our zone used for resolution | 244 | * @param zone our zone used for resolution |
157 | * @param label name of the caller | 245 | * @param label name of the caller |
158 | * @param rd_count number of records we have in @a rd | 246 | * @param rd_count number of records we have in @a rd |
@@ -165,18 +253,47 @@ handle_caller_name (void *cls, | |||
165 | unsigned int rd_count, | 253 | unsigned int rd_count, |
166 | const struct GNUNET_GNSRECORD_Data *rd) | 254 | const struct GNUNET_GNSRECORD_Data *rd) |
167 | { | 255 | { |
168 | struct GNUNET_CONVERSATION_Phone *phone = cls; | 256 | struct GNUNET_CONVERSATION_Caller *caller = cls; |
257 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
169 | char *name; | 258 | char *name; |
170 | 259 | ||
171 | phone->qe = NULL; | 260 | caller->qe = NULL; |
172 | if (NULL == label) | 261 | if (NULL == label) |
173 | name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&phone->caller_id)); | 262 | name = GNUNET_strdup (GNUNET_GNSRECORD_pkey_to_zkey (&caller->caller_id)); |
174 | else | 263 | else |
175 | GNUNET_asprintf (&name, "%.gnu", label); | 264 | GNUNET_asprintf (&name, "%.gnu", label); |
265 | caller->caller_id_str = name; | ||
266 | caller->state = CS_RINGING; | ||
176 | phone->event_handler (phone->event_handler_cls, | 267 | phone->event_handler (phone->event_handler_cls, |
177 | GNUNET_CONVERSATION_EC_RING, | 268 | GNUNET_CONVERSATION_EC_PHONE_RING, |
269 | caller, | ||
178 | name); | 270 | name); |
179 | GNUNET_free (name); | 271 | } |
272 | |||
273 | |||
274 | /** | ||
275 | * Process recorded audio data. | ||
276 | * | ||
277 | * @param cls closure with the `struct GNUNET_CONVERSATION_Caller` | ||
278 | * @param data_size number of bytes in @a data | ||
279 | * @param data audio data to play | ||
280 | */ | ||
281 | static void | ||
282 | transmit_phone_audio (void *cls, | ||
283 | size_t data_size, | ||
284 | const void *data) | ||
285 | { | ||
286 | struct GNUNET_CONVERSATION_Caller *caller = cls; | ||
287 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
288 | struct GNUNET_MQ_Envelope *e; | ||
289 | struct ClientAudioMessage *am; | ||
290 | |||
291 | e = GNUNET_MQ_msg_extra (am, | ||
292 | data_size, | ||
293 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO); | ||
294 | am->cid = caller->cid; | ||
295 | memcpy (&am[1], data, data_size); | ||
296 | GNUNET_MQ_send (phone->mq, e); | ||
180 | } | 297 | } |
181 | 298 | ||
182 | 299 | ||
@@ -192,6 +309,7 @@ handle_phone_ring (void *cls, | |||
192 | { | 309 | { |
193 | struct GNUNET_CONVERSATION_Phone *phone = cls; | 310 | struct GNUNET_CONVERSATION_Phone *phone = cls; |
194 | const struct ClientPhoneRingMessage *ring; | 311 | const struct ClientPhoneRingMessage *ring; |
312 | struct GNUNET_CONVERSATION_Caller *caller; | ||
195 | 313 | ||
196 | ring = (const struct ClientPhoneRingMessage *) msg; | 314 | ring = (const struct ClientPhoneRingMessage *) msg; |
197 | switch (phone->state) | 315 | switch (phone->state) |
@@ -199,22 +317,20 @@ handle_phone_ring (void *cls, | |||
199 | case PS_REGISTER: | 317 | case PS_REGISTER: |
200 | GNUNET_assert (0); | 318 | GNUNET_assert (0); |
201 | break; | 319 | break; |
202 | case PS_WAITING: | 320 | case PS_READY: |
203 | phone->state = PS_RINGING; | 321 | caller = GNUNET_new (struct GNUNET_CONVERSATION_Caller); |
204 | phone->caller_id = ring->caller_id; | 322 | caller->phone = phone; |
205 | phone->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns, | 323 | GNUNET_CONTAINER_DLL_insert (phone->caller_head, |
206 | &phone->my_zone, | 324 | phone->caller_tail, |
207 | &ring->caller_id, | 325 | caller); |
208 | &handle_caller_name, | 326 | caller->state = CS_RESOLVE; |
209 | phone); | 327 | caller->caller_id = ring->caller_id; |
210 | break; | 328 | caller->cid = ring->cid; |
211 | case PS_RINGING: | 329 | caller->qe = GNUNET_NAMESTORE_zone_to_name (phone->ns, |
212 | GNUNET_break (0); | 330 | &phone->my_zone, |
213 | reconnect_phone (phone); | 331 | &ring->caller_id, |
214 | break; | 332 | &handle_caller_name, |
215 | case PS_ACTIVE: | 333 | caller); |
216 | GNUNET_break (0); | ||
217 | reconnect_phone (phone); | ||
218 | break; | 334 | break; |
219 | } | 335 | } |
220 | } | 336 | } |
@@ -232,49 +348,144 @@ handle_phone_hangup (void *cls, | |||
232 | { | 348 | { |
233 | struct GNUNET_CONVERSATION_Phone *phone = cls; | 349 | struct GNUNET_CONVERSATION_Phone *phone = cls; |
234 | const struct ClientPhoneHangupMessage *hang; | 350 | const struct ClientPhoneHangupMessage *hang; |
235 | size_t len; | 351 | struct GNUNET_CONVERSATION_Caller *caller; |
236 | const char *reason; | ||
237 | 352 | ||
238 | hang = (const struct ClientPhoneHangupMessage *) msg; | 353 | hang = (const struct ClientPhoneHangupMessage *) msg; |
239 | reason = (const char *) &hang[1]; | 354 | for (caller = phone->caller_head; NULL != caller; caller = caller->next) |
240 | len = htons (hang->header.size) - sizeof (struct ClientPhoneHangupMessage); | 355 | if (hang->cid == caller->cid) |
241 | if ( (0 == len) || | 356 | break; |
242 | ('\0' != reason[len-1]) ) | 357 | if (NULL == caller) |
243 | { | ||
244 | GNUNET_break (0); | ||
245 | reconnect_phone (phone); | ||
246 | return; | 358 | return; |
247 | } | 359 | |
248 | switch (phone->state) | 360 | switch (caller->state) |
249 | { | 361 | { |
250 | case PS_REGISTER: | 362 | case CS_RESOLVE: |
251 | GNUNET_assert (0); | 363 | GNUNET_NAMESTORE_cancel (caller->qe); |
364 | caller->qe = NULL; | ||
252 | break; | 365 | break; |
253 | case PS_WAITING: | 366 | case CS_RINGING: |
254 | GNUNET_break (0); | 367 | phone->event_handler (phone->event_handler_cls, |
255 | reconnect_phone (phone); | 368 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, |
369 | caller, | ||
370 | caller->caller_id_str); | ||
256 | break; | 371 | break; |
257 | case PS_RINGING: | 372 | case CS_ACTIVE: |
258 | if (NULL != phone->qe) | 373 | caller->speaker->disable_speaker (caller->speaker->cls); |
259 | { | 374 | caller->mic->disable_microphone (caller->mic->cls); |
260 | GNUNET_NAMESTORE_cancel (phone->qe); | ||
261 | phone->qe = NULL; | ||
262 | phone->state = PS_WAITING; | ||
263 | break; | ||
264 | } | ||
265 | phone->state = PS_WAITING; | ||
266 | phone->event_handler (phone->event_handler_cls, | 375 | phone->event_handler (phone->event_handler_cls, |
267 | GNUNET_CONVERSATION_EC_TERMINATED, | 376 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, |
268 | reason); | 377 | caller, |
378 | caller->caller_id_str); | ||
269 | break; | 379 | break; |
270 | case PS_ACTIVE: | 380 | case CS_CALLEE_SUSPENDED: |
271 | GNUNET_break (NULL == phone->qe); | 381 | case CS_CALLER_SUSPENDED: |
272 | phone->state = PS_WAITING; | 382 | case CS_BOTH_SUSPENDED: |
273 | phone->event_handler (phone->event_handler_cls, | 383 | phone->event_handler (phone->event_handler_cls, |
274 | GNUNET_CONVERSATION_EC_TERMINATED, | 384 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, |
275 | reason); | 385 | caller, |
276 | phone->speaker->disable_speaker (phone->speaker->cls); | 386 | caller->caller_id_str); |
277 | phone->mic->disable_microphone (phone->mic->cls); | 387 | break; |
388 | } | ||
389 | GNUNET_CONTAINER_DLL_remove (phone->caller_head, | ||
390 | phone->caller_tail, | ||
391 | caller); | ||
392 | GNUNET_free (caller); | ||
393 | } | ||
394 | |||
395 | |||
396 | /** | ||
397 | * We received a `struct ClientPhoneSuspendMessage`. | ||
398 | * | ||
399 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
400 | * @param msg the message | ||
401 | */ | ||
402 | static void | ||
403 | handle_phone_suspend (void *cls, | ||
404 | const struct GNUNET_MessageHeader *msg) | ||
405 | { | ||
406 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
407 | struct GNUNET_CONVERSATION_Caller *caller; | ||
408 | const struct ClientPhoneSuspendMessage *suspend; | ||
409 | |||
410 | suspend = (const struct ClientPhoneSuspendMessage *) msg; | ||
411 | for (caller = phone->caller_head; NULL != caller; caller = caller->next) | ||
412 | if (suspend->cid == caller->cid) | ||
413 | break; | ||
414 | if (NULL == caller) | ||
415 | return; | ||
416 | switch (caller->state) | ||
417 | { | ||
418 | case CS_RESOLVE: | ||
419 | GNUNET_break_op (0); | ||
420 | break; | ||
421 | case CS_RINGING: | ||
422 | GNUNET_break_op (0); | ||
423 | break; | ||
424 | case CS_ACTIVE: | ||
425 | caller->state = CS_CALLER_SUSPENDED; | ||
426 | caller->speaker->disable_speaker (caller->speaker->cls); | ||
427 | caller->mic->disable_microphone (caller->mic->cls); | ||
428 | caller->event_handler (caller->event_handler_cls, | ||
429 | GNUNET_CONVERSATION_EC_CALLER_SUSPEND); | ||
430 | break; | ||
431 | case CS_CALLEE_SUSPENDED: | ||
432 | caller->state = CS_BOTH_SUSPENDED; | ||
433 | caller->event_handler (caller->event_handler_cls, | ||
434 | GNUNET_CONVERSATION_EC_CALLER_SUSPEND); | ||
435 | break; | ||
436 | case CS_CALLER_SUSPENDED: | ||
437 | case CS_BOTH_SUSPENDED: | ||
438 | GNUNET_break_op (0); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | |||
444 | /** | ||
445 | * We received a `struct ClientPhoneResumeMessage`. | ||
446 | * | ||
447 | * @param cls the `struct GNUNET_CONVERSATION_Phone` | ||
448 | * @param msg the message | ||
449 | */ | ||
450 | static void | ||
451 | handle_phone_resume (void *cls, | ||
452 | const struct GNUNET_MessageHeader *msg) | ||
453 | { | ||
454 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
455 | struct GNUNET_CONVERSATION_Caller *caller; | ||
456 | const struct ClientPhoneResumeMessage *resume; | ||
457 | |||
458 | resume = (const struct ClientPhoneResumeMessage *) msg; | ||
459 | for (caller = phone->caller_head; NULL != caller; caller = caller->next) | ||
460 | if (resume->cid == caller->cid) | ||
461 | break; | ||
462 | if (NULL == caller) | ||
463 | return; | ||
464 | switch (caller->state) | ||
465 | { | ||
466 | case CS_RESOLVE: | ||
467 | GNUNET_break_op (0); | ||
468 | break; | ||
469 | case CS_RINGING: | ||
470 | GNUNET_break_op (0); | ||
471 | break; | ||
472 | case CS_ACTIVE: | ||
473 | case CS_CALLEE_SUSPENDED: | ||
474 | GNUNET_break_op (0); | ||
475 | break; | ||
476 | case CS_CALLER_SUSPENDED: | ||
477 | caller->state = CS_ACTIVE; | ||
478 | caller->speaker->enable_speaker (caller->speaker->cls); | ||
479 | caller->mic->enable_microphone (caller->mic->cls, | ||
480 | &transmit_phone_audio, | ||
481 | caller); | ||
482 | caller->event_handler (caller->event_handler_cls, | ||
483 | GNUNET_CONVERSATION_EC_CALLER_RESUME); | ||
484 | break; | ||
485 | case CS_BOTH_SUSPENDED: | ||
486 | caller->state = CS_CALLEE_SUSPENDED; | ||
487 | caller->event_handler (caller->event_handler_cls, | ||
488 | GNUNET_CONVERSATION_EC_CALLER_RESUME); | ||
278 | break; | 489 | break; |
279 | } | 490 | } |
280 | } | 491 | } |
@@ -292,25 +503,30 @@ handle_phone_audio_message (void *cls, | |||
292 | { | 503 | { |
293 | struct GNUNET_CONVERSATION_Phone *phone = cls; | 504 | struct GNUNET_CONVERSATION_Phone *phone = cls; |
294 | const struct ClientAudioMessage *am; | 505 | const struct ClientAudioMessage *am; |
506 | struct GNUNET_CONVERSATION_Caller *caller; | ||
295 | 507 | ||
296 | am = (const struct ClientAudioMessage *) msg; | 508 | am = (const struct ClientAudioMessage *) msg; |
297 | switch (phone->state) | 509 | for (caller = phone->caller_head; NULL != caller; caller = caller->next) |
510 | if (am->cid == caller->cid) | ||
511 | break; | ||
512 | if (NULL == caller) | ||
513 | return; | ||
514 | switch (caller->state) | ||
298 | { | 515 | { |
299 | case PS_REGISTER: | 516 | case CS_RESOLVE: |
300 | GNUNET_assert (0); | 517 | GNUNET_break_op (0); |
301 | break; | 518 | break; |
302 | case PS_WAITING: | 519 | case CS_RINGING: |
303 | GNUNET_break (0); | 520 | GNUNET_break_op (0); |
304 | reconnect_phone (phone); | ||
305 | break; | 521 | break; |
306 | case PS_RINGING: | 522 | case CS_ACTIVE: |
307 | GNUNET_break (0); | 523 | caller->speaker->play (caller->speaker->cls, |
308 | reconnect_phone (phone); | 524 | ntohs (msg->size) - sizeof (struct ClientAudioMessage), |
525 | &am[1]); | ||
309 | break; | 526 | break; |
310 | case PS_ACTIVE: | 527 | case CS_CALLEE_SUSPENDED: |
311 | phone->speaker->play (phone->speaker->cls, | 528 | case CS_CALLER_SUSPENDED: |
312 | ntohs (msg->size) - sizeof (struct ClientAudioMessage), | 529 | case CS_BOTH_SUSPENDED: |
313 | &am[1]); | ||
314 | break; | 530 | break; |
315 | } | 531 | } |
316 | } | 532 | } |
@@ -329,9 +545,9 @@ phone_error_handler (void *cls, | |||
329 | struct GNUNET_CONVERSATION_Phone *phone = cls; | 545 | struct GNUNET_CONVERSATION_Phone *phone = cls; |
330 | 546 | ||
331 | GNUNET_break (0); | 547 | GNUNET_break (0); |
332 | FPRINTF (stderr, | 548 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
333 | _("Internal error %d\n"), | 549 | _("Internal MQ error %d\n"), |
334 | error); | 550 | error); |
335 | reconnect_phone (phone); | 551 | reconnect_phone (phone); |
336 | } | 552 | } |
337 | 553 | ||
@@ -351,7 +567,13 @@ reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone) | |||
351 | sizeof (struct ClientPhoneRingMessage) }, | 567 | sizeof (struct ClientPhoneRingMessage) }, |
352 | { &handle_phone_hangup, | 568 | { &handle_phone_hangup, |
353 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, | 569 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, |
354 | 0 }, | 570 | sizeof (struct ClientPhoneHangupMessage) }, |
571 | { &handle_phone_suspend, | ||
572 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND, | ||
573 | sizeof (struct ClientPhoneSuspendMessage) }, | ||
574 | { &handle_phone_resume, | ||
575 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME, | ||
576 | sizeof (struct ClientPhoneResumeMessage) }, | ||
355 | { &handle_phone_audio_message, | 577 | { &handle_phone_audio_message, |
356 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, | 578 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, |
357 | 0 }, | 579 | 0 }, |
@@ -359,11 +581,15 @@ reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone) | |||
359 | }; | 581 | }; |
360 | struct GNUNET_MQ_Envelope *e; | 582 | struct GNUNET_MQ_Envelope *e; |
361 | struct ClientPhoneRegisterMessage *reg; | 583 | struct ClientPhoneRegisterMessage *reg; |
584 | struct GNUNET_CONVERSATION_Caller *caller; | ||
362 | 585 | ||
363 | if (PS_ACTIVE == phone->state) | 586 | while (NULL != (caller = phone->caller_head)) |
364 | { | 587 | { |
365 | phone->speaker->disable_speaker (phone->speaker->cls); | 588 | phone->event_handler (phone->event_handler_cls, |
366 | phone->mic->disable_microphone (phone->mic->cls); | 589 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, |
590 | caller, | ||
591 | caller->caller_id_str); | ||
592 | GNUNET_CONVERSATION_caller_hang_up (caller); | ||
367 | } | 593 | } |
368 | if (NULL != phone->mq) | 594 | if (NULL != phone->mq) |
369 | { | 595 | { |
@@ -386,7 +612,7 @@ reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone) | |||
386 | e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER); | 612 | e = GNUNET_MQ_msg (reg, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER); |
387 | reg->line = phone->my_record.line; | 613 | reg->line = phone->my_record.line; |
388 | GNUNET_MQ_send (phone->mq, e); | 614 | GNUNET_MQ_send (phone->mq, e); |
389 | phone->state = PS_WAITING; | 615 | phone->state = PS_READY; |
390 | } | 616 | } |
391 | 617 | ||
392 | 618 | ||
@@ -402,7 +628,7 @@ reconnect_phone (struct GNUNET_CONVERSATION_Phone *phone) | |||
402 | struct GNUNET_CONVERSATION_Phone * | 628 | struct GNUNET_CONVERSATION_Phone * |
403 | GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg, | 629 | GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg, |
404 | const struct GNUNET_IDENTITY_Ego *ego, | 630 | const struct GNUNET_IDENTITY_Ego *ego, |
405 | GNUNET_CONVERSATION_EventHandler event_handler, | 631 | GNUNET_CONVERSATION_PhoneEventHandler event_handler, |
406 | void *event_handler_cls) | 632 | void *event_handler_cls) |
407 | { | 633 | { |
408 | struct GNUNET_CONVERSATION_Phone *phone; | 634 | struct GNUNET_CONVERSATION_Phone *phone; |
@@ -463,61 +689,39 @@ GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone, | |||
463 | 689 | ||
464 | 690 | ||
465 | /** | 691 | /** |
466 | * Process recorded audio data. | ||
467 | * | ||
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 | ||
471 | */ | ||
472 | static void | ||
473 | transmit_phone_audio (void *cls, | ||
474 | size_t data_size, | ||
475 | const void *data) | ||
476 | { | ||
477 | struct GNUNET_CONVERSATION_Phone *phone = cls; | ||
478 | struct GNUNET_MQ_Envelope *e; | ||
479 | struct ClientAudioMessage *am; | ||
480 | |||
481 | GNUNET_assert (PS_ACTIVE == phone->state); | ||
482 | e = GNUNET_MQ_msg_extra (am, | ||
483 | data_size, | ||
484 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO); | ||
485 | memcpy (&am[1], data, data_size); | ||
486 | GNUNET_MQ_send (phone->mq, e); | ||
487 | } | ||
488 | |||
489 | |||
490 | /** | ||
491 | * Picks up a (ringing) phone. This will connect the speaker | 692 | * Picks up a (ringing) phone. This will connect the speaker |
492 | * to the microphone of the other party, and vice versa. | 693 | * to the microphone of the other party, and vice versa. |
493 | * | 694 | * |
494 | * @param phone phone to pick up | 695 | * @param caller handle that identifies which caller should be answered |
495 | * @param metadata meta data to give to the other user about the pick up event | 696 | * @param event_handler how to notify about events by the caller |
697 | * @param event_handler_cls closure for @a event_handler | ||
496 | * @param speaker speaker to use | 698 | * @param speaker speaker to use |
497 | * @param mic microphone to use | 699 | * @param mic microphone to use |
498 | */ | 700 | */ |
499 | void | 701 | void |
500 | GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone, | 702 | GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller, |
501 | const char *metadata, | 703 | GNUNET_CONVERSATION_CallerEventHandler event_handler, |
502 | struct GNUNET_SPEAKER_Handle *speaker, | 704 | void *event_handler_cls, |
503 | struct GNUNET_MICROPHONE_Handle *mic) | 705 | struct GNUNET_SPEAKER_Handle *speaker, |
706 | struct GNUNET_MICROPHONE_Handle *mic) | ||
504 | { | 707 | { |
708 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
505 | struct GNUNET_MQ_Envelope *e; | 709 | struct GNUNET_MQ_Envelope *e; |
506 | struct ClientPhonePickupMessage *pick; | 710 | struct ClientPhonePickupMessage *pick; |
507 | size_t slen; | 711 | |
508 | 712 | GNUNET_assert (CS_RINGING == caller->state); | |
509 | GNUNET_assert (PS_RINGING == phone->state); | 713 | caller->speaker = speaker; |
510 | phone->speaker = speaker; | 714 | caller->mic = mic; |
511 | phone->mic = mic; | 715 | e = GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP); |
512 | slen = strlen (metadata) + 1; | 716 | pick->cid = caller->cid; |
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); | 717 | GNUNET_MQ_send (phone->mq, e); |
516 | phone->state = PS_ACTIVE; | 718 | caller->state = CS_ACTIVE; |
517 | phone->speaker->enable_speaker (phone->speaker->cls); | 719 | caller->event_handler = event_handler; |
518 | phone->mic->enable_microphone (phone->mic->cls, | 720 | caller->event_handler_cls = event_handler_cls; |
519 | &transmit_phone_audio, | 721 | caller->speaker->enable_speaker (caller->speaker->cls); |
520 | phone); | 722 | caller->mic->enable_microphone (caller->mic->cls, |
723 | &transmit_phone_audio, | ||
724 | caller); | ||
521 | } | 725 | } |
522 | 726 | ||
523 | 727 | ||
@@ -525,28 +729,35 @@ GNUNET_CONVERSATION_phone_pick_up (struct GNUNET_CONVERSATION_Phone *phone, | |||
525 | * Hang up up a (possibly ringing) phone. This will notify the other | 729 | * Hang up up a (possibly ringing) phone. This will notify the other |
526 | * party that we are no longer interested in talking with them. | 730 | * party that we are no longer interested in talking with them. |
527 | * | 731 | * |
528 | * @param phone phone to pick up | 732 | * @param caller conversation to hang up on |
529 | * @param reason text we give to the other party about why we terminated the conversation | ||
530 | */ | 733 | */ |
531 | void | 734 | void |
532 | GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone, | 735 | GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller) |
533 | const char *reason) | ||
534 | { | 736 | { |
737 | struct GNUNET_CONVERSATION_Phone *phone = caller->phone; | ||
535 | struct GNUNET_MQ_Envelope *e; | 738 | struct GNUNET_MQ_Envelope *e; |
536 | struct ClientPhoneHangupMessage *hang; | 739 | struct ClientPhoneHangupMessage *hang; |
537 | size_t slen; | 740 | |
538 | 741 | switch (caller->state) | |
539 | GNUNET_assert ( (PS_RINGING == phone->state) || | 742 | { |
540 | (PS_ACTIVE == phone->state) ); | 743 | case CS_RESOLVE: |
541 | phone->speaker->disable_speaker (phone->speaker->cls); | 744 | GNUNET_NAMESTORE_cancel (caller->qe); |
542 | phone->mic->disable_microphone (phone->mic->cls); | 745 | caller->qe = NULL; |
543 | phone->speaker = NULL; | 746 | break; |
544 | phone->mic = NULL; | 747 | case CS_ACTIVE: |
545 | slen = strlen (reason) + 1; | 748 | caller->speaker->disable_speaker (caller->speaker->cls); |
546 | e = GNUNET_MQ_msg_extra (hang, slen, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP); | 749 | caller->mic->disable_microphone (caller->mic->cls); |
547 | memcpy (&hang[1], reason, slen); | 750 | break; |
751 | default: | ||
752 | break; | ||
753 | } | ||
754 | GNUNET_CONTAINER_DLL_remove (phone->caller_head, | ||
755 | phone->caller_tail, | ||
756 | caller); | ||
757 | GNUNET_free_non_null (caller->caller_id_str); | ||
758 | GNUNET_free (caller); | ||
759 | e = GNUNET_MQ_msg (hang, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP); | ||
548 | GNUNET_MQ_send (phone->mq, e); | 760 | GNUNET_MQ_send (phone->mq, e); |
549 | phone->state = PS_WAITING; | ||
550 | } | 761 | } |
551 | 762 | ||
552 | 763 | ||
@@ -558,20 +769,15 @@ GNUNET_CONVERSATION_phone_hang_up (struct GNUNET_CONVERSATION_Phone *phone, | |||
558 | void | 769 | void |
559 | GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone) | 770 | GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone) |
560 | { | 771 | { |
561 | if (NULL != phone->speaker) | 772 | struct GNUNET_CONVERSATION_Caller *caller; |
562 | { | 773 | |
563 | phone->speaker->disable_speaker (phone->speaker->cls); | 774 | while (NULL != (caller = phone->caller_head)) |
564 | phone->speaker = NULL; | ||
565 | } | ||
566 | if (NULL != phone->mic) | ||
567 | { | ||
568 | phone->mic->disable_microphone (phone->mic->cls); | ||
569 | phone->mic = NULL; | ||
570 | } | ||
571 | if (NULL != phone->qe) | ||
572 | { | 775 | { |
573 | GNUNET_NAMESTORE_cancel (phone->qe); | 776 | phone->event_handler (phone->event_handler_cls, |
574 | phone->qe = NULL; | 777 | GNUNET_CONVERSATION_EC_PHONE_HUNG_UP, |
778 | caller, | ||
779 | caller->caller_id_str); | ||
780 | GNUNET_CONVERSATION_caller_hang_up (caller); | ||
575 | } | 781 | } |
576 | if (NULL != phone->ns) | 782 | if (NULL != phone->ns) |
577 | { | 783 | { |
@@ -592,554 +798,33 @@ GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone) | |||
592 | } | 798 | } |
593 | 799 | ||
594 | 800 | ||
595 | /* ******************************* Call API *************************** */ | ||
596 | |||
597 | /** | ||
598 | * Possible states of the phone. | ||
599 | */ | ||
600 | enum CallState | ||
601 | { | ||
602 | /** | ||
603 | * We still need to lookup the callee. | ||
604 | */ | ||
605 | CS_LOOKUP = 0, | ||
606 | |||
607 | /** | ||
608 | * The call is ringing. | ||
609 | */ | ||
610 | CS_RINGING, | ||
611 | |||
612 | /** | ||
613 | * The call is in an active conversation. | ||
614 | */ | ||
615 | CS_ACTIVE, | ||
616 | |||
617 | /** | ||
618 | * The call is in termination. | ||
619 | */ | ||
620 | CS_SHUTDOWN | ||
621 | }; | ||
622 | |||
623 | |||
624 | /** | ||
625 | * Handle for an outgoing call. | ||
626 | */ | ||
627 | struct GNUNET_CONVERSATION_Call | ||
628 | { | ||
629 | |||
630 | /** | ||
631 | * Our configuration. | ||
632 | */ | ||
633 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
634 | |||
635 | /** | ||
636 | * Handle to talk with CONVERSATION service. | ||
637 | */ | ||
638 | struct GNUNET_CLIENT_Connection *client; | ||
639 | |||
640 | /** | ||
641 | * Our caller identity. | ||
642 | */ | ||
643 | struct GNUNET_IDENTITY_Ego *caller_id; | ||
644 | |||
645 | /** | ||
646 | * Target callee as a GNS address/name. | ||
647 | */ | ||
648 | char *callee; | ||
649 | |||
650 | /** | ||
651 | * Our speaker. | ||
652 | */ | ||
653 | struct GNUNET_SPEAKER_Handle *speaker; | ||
654 | |||
655 | /** | ||
656 | * Our microphone. | ||
657 | */ | ||
658 | struct GNUNET_MICROPHONE_Handle *mic; | ||
659 | |||
660 | /** | ||
661 | * Function to call with events. | ||
662 | */ | ||
663 | GNUNET_CONVERSATION_EventHandler event_handler; | ||
664 | |||
665 | /** | ||
666 | * Closure for @e event_handler | ||
667 | */ | ||
668 | void *event_handler_cls; | ||
669 | |||
670 | /** | ||
671 | * Handle for transmitting to the CONVERSATION service. | ||
672 | */ | ||
673 | struct GNUNET_MQ_Handle *mq; | ||
674 | |||
675 | /** | ||
676 | * Connection to GNS (can be NULL). | ||
677 | */ | ||
678 | struct GNUNET_GNS_Handle *gns; | ||
679 | |||
680 | /** | ||
681 | * Active GNS lookup (or NULL). | ||
682 | */ | ||
683 | struct GNUNET_GNS_LookupRequest *gns_lookup; | ||
684 | |||
685 | /** | ||
686 | * Target phone record, only valid after the lookup is done. | ||
687 | */ | ||
688 | struct GNUNET_CONVERSATION_PhoneRecord phone_record; | ||
689 | |||
690 | /** | ||
691 | * State machine for the call. | ||
692 | */ | ||
693 | enum CallState state; | ||
694 | |||
695 | }; | ||
696 | |||
697 | |||
698 | /** | ||
699 | * The call got disconnected, reconnect to the service. | ||
700 | * | ||
701 | * @param call call to reconnect | ||
702 | */ | ||
703 | static void | ||
704 | reconnect_call (struct GNUNET_CONVERSATION_Call *call); | ||
705 | |||
706 | |||
707 | /** | ||
708 | * We received a `struct ClientPhoneBusyMessage` | ||
709 | * | ||
710 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
711 | * @param msg the message | ||
712 | */ | ||
713 | static void | ||
714 | handle_call_busy (void *cls, | ||
715 | const struct GNUNET_MessageHeader *msg) | ||
716 | { | ||
717 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
718 | |||
719 | switch (call->state) | ||
720 | { | ||
721 | case CS_LOOKUP: | ||
722 | GNUNET_break (0); | ||
723 | reconnect_call (call); | ||
724 | break; | ||
725 | case CS_RINGING: | ||
726 | call->event_handler (call->event_handler_cls, | ||
727 | GNUNET_CONVERSATION_EC_BUSY); | ||
728 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
729 | break; | ||
730 | case CS_ACTIVE: | ||
731 | GNUNET_break (0); | ||
732 | reconnect_call (call); | ||
733 | break; | ||
734 | case CS_SHUTDOWN: | ||
735 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
736 | break; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | |||
741 | /** | ||
742 | * Process recorded audio data. | ||
743 | * | ||
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 | ||
747 | */ | ||
748 | static void | ||
749 | transmit_call_audio (void *cls, | ||
750 | size_t data_size, | ||
751 | const void *data) | ||
752 | { | ||
753 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
754 | struct GNUNET_MQ_Envelope *e; | ||
755 | struct ClientAudioMessage *am; | ||
756 | |||
757 | GNUNET_assert (CS_ACTIVE == call->state); | ||
758 | e = GNUNET_MQ_msg_extra (am, | ||
759 | data_size, | ||
760 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO); | ||
761 | memcpy (&am[1], data, data_size); | ||
762 | GNUNET_MQ_send (call->mq, e); | ||
763 | } | ||
764 | |||
765 | |||
766 | /** | ||
767 | * We received a `struct ClientPhonePickedupMessage` | ||
768 | * | ||
769 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
770 | * @param msg the message | ||
771 | */ | ||
772 | static void | ||
773 | handle_call_picked_up (void *cls, | ||
774 | const struct GNUNET_MessageHeader *msg) | ||
775 | { | ||
776 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
777 | const struct ClientPhonePickedupMessage *am; | ||
778 | const char *metadata; | ||
779 | size_t size; | ||
780 | |||
781 | am = (const struct ClientPhonePickedupMessage *) msg; | ||
782 | size = ntohs (am->header.size) - sizeof (struct ClientPhonePickedupMessage); | ||
783 | metadata = (const char *) &am[1]; | ||
784 | if ( (0 == size) || | ||
785 | ('\0' != metadata[size - 1]) ) | ||
786 | metadata = NULL; | ||
787 | switch (call->state) | ||
788 | { | ||
789 | case CS_LOOKUP: | ||
790 | GNUNET_break (0); | ||
791 | reconnect_call (call); | ||
792 | break; | ||
793 | case CS_RINGING: | ||
794 | call->state = CS_ACTIVE; | ||
795 | call->event_handler (call->event_handler_cls, | ||
796 | GNUNET_CONVERSATION_EC_READY, | ||
797 | metadata); | ||
798 | call->speaker->enable_speaker (call->speaker->cls); | ||
799 | call->mic->enable_microphone (call->mic->cls, | ||
800 | &transmit_call_audio, | ||
801 | call); | ||
802 | break; | ||
803 | case CS_ACTIVE: | ||
804 | GNUNET_break (0); | ||
805 | reconnect_call (call); | ||
806 | break; | ||
807 | case CS_SHUTDOWN: | ||
808 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
809 | break; | ||
810 | } | ||
811 | } | ||
812 | |||
813 | |||
814 | /** | ||
815 | * We received a `struct ClientPhoneHangupMessage` | ||
816 | * | ||
817 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
818 | * @param msg the message | ||
819 | */ | ||
820 | static void | ||
821 | handle_call_hangup (void *cls, | ||
822 | const struct GNUNET_MessageHeader *msg) | ||
823 | { | ||
824 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
825 | const struct ClientPhoneHangupMessage *am; | ||
826 | const char *reason; | ||
827 | size_t size; | ||
828 | |||
829 | am = (const struct ClientPhoneHangupMessage *) msg; | ||
830 | size = ntohs (am->header.size) - sizeof (struct ClientPhoneHangupMessage); | ||
831 | reason = (const char *) &am[1]; | ||
832 | if ( (0 == size) || | ||
833 | ('\0' != reason[size - 1]) ) | ||
834 | reason = NULL; | ||
835 | switch (call->state) | ||
836 | { | ||
837 | case CS_LOOKUP: | ||
838 | GNUNET_break (0); | ||
839 | reconnect_call (call); | ||
840 | break; | ||
841 | case CS_RINGING: | ||
842 | call->event_handler (call->event_handler_cls, | ||
843 | GNUNET_CONVERSATION_EC_TERMINATED, | ||
844 | reason); | ||
845 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
846 | return; | ||
847 | case CS_ACTIVE: | ||
848 | call->event_handler (call->event_handler_cls, | ||
849 | GNUNET_CONVERSATION_EC_TERMINATED, | ||
850 | reason); | ||
851 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
852 | return; | ||
853 | case CS_SHUTDOWN: | ||
854 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
855 | break; | ||
856 | } | ||
857 | } | ||
858 | |||
859 | |||
860 | /** | ||
861 | * We received a `struct ClientAudioMessage` | ||
862 | * | ||
863 | * @param cls the `struct GNUNET_CONVERSATION_Call` | ||
864 | * @param msg the message | ||
865 | */ | ||
866 | static void | ||
867 | handle_call_audio_message (void *cls, | ||
868 | const struct GNUNET_MessageHeader *msg) | ||
869 | { | ||
870 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
871 | const struct ClientAudioMessage *am; | ||
872 | |||
873 | am = (const struct ClientAudioMessage *) msg; | ||
874 | switch (call->state) | ||
875 | { | ||
876 | case CS_LOOKUP: | ||
877 | GNUNET_break (0); | ||
878 | reconnect_call (call); | ||
879 | break; | ||
880 | case CS_RINGING: | ||
881 | GNUNET_break (0); | ||
882 | reconnect_call (call); | ||
883 | break; | ||
884 | case CS_ACTIVE: | ||
885 | call->speaker->play (call->speaker->cls, | ||
886 | ntohs (msg->size) - sizeof (struct ClientAudioMessage), | ||
887 | &am[1]); | ||
888 | break; | ||
889 | case CS_SHUTDOWN: | ||
890 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
891 | break; | ||
892 | |||
893 | } | ||
894 | } | ||
895 | |||
896 | |||
897 | /** | ||
898 | * Iterator called on obtained result for a GNS lookup. | ||
899 | * | ||
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 | ||
903 | */ | ||
904 | static void | ||
905 | handle_gns_response (void *cls, | ||
906 | uint32_t rd_count, | ||
907 | const struct GNUNET_GNSRECORD_Data *rd) | ||
908 | { | ||
909 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
910 | uint32_t i; | ||
911 | struct GNUNET_MQ_Envelope *e; | ||
912 | struct ClientCallMessage *ccm; | ||
913 | |||
914 | call->gns_lookup = NULL; | ||
915 | for (i=0;i<rd_count;i++) | ||
916 | { | ||
917 | if (GNUNET_GNSRECORD_TYPE_PHONE == rd[i].record_type) | ||
918 | { | ||
919 | if (rd[i].data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord)) | ||
920 | { | ||
921 | GNUNET_break_op (0); | ||
922 | continue; | ||
923 | } | ||
924 | memcpy (&call->phone_record, | ||
925 | rd[i].data, | ||
926 | rd[i].data_size); | ||
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); | ||
935 | return; | ||
936 | } | ||
937 | } | ||
938 | /* not found */ | ||
939 | call->event_handler (call->event_handler_cls, | ||
940 | GNUNET_CONVERSATION_EC_GNS_FAIL); | ||
941 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
942 | } | ||
943 | |||
944 | |||
945 | /** | 801 | /** |
946 | * We encountered an error talking with the conversation service. | 802 | * Pause conversation of an active call. This will disconnect the speaker |
803 | * and the microphone. The call can later be resumed with | ||
804 | * #GNUNET_CONVERSATION_caller_resume. | ||
947 | * | 805 | * |
948 | * @param cls the `struct GNUNET_CONVERSATION_Call` | 806 | * @param phone phone to pause |
949 | * @param error details about the error | ||
950 | */ | 807 | */ |
951 | static void | 808 | void |
952 | call_error_handler (void *cls, | 809 | GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller) |
953 | enum GNUNET_MQ_Error error) | ||
954 | { | 810 | { |
955 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
956 | |||
957 | GNUNET_break (0); | 811 | GNUNET_break (0); |
958 | FPRINTF (stderr, | ||
959 | _("Internal error %d\n"), | ||
960 | error); | ||
961 | reconnect_call (call); | ||
962 | } | 812 | } |
963 | 813 | ||
964 | 814 | ||
965 | /** | 815 | /** |
966 | * The call got disconnected, reconnect to the service. | 816 | * Resume suspended conversation of a phone. |
967 | * | 817 | * |
968 | * @param call call to reconnect | 818 | * @param phone phone to resume |
969 | */ | 819 | * @param speaker speaker to use |
970 | static void | 820 | * @param mic microphone to use |
971 | reconnect_call (struct GNUNET_CONVERSATION_Call *call) | ||
972 | { | ||
973 | static struct GNUNET_MQ_MessageHandler handlers[] = | ||
974 | { | ||
975 | { &handle_call_busy, | ||
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, | ||
980 | 0 }, | ||
981 | { &handle_call_hangup, | ||
982 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP, | ||
983 | 0 }, | ||
984 | { &handle_call_audio_message, | ||
985 | GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO, | ||
986 | 0 }, | ||
987 | { NULL, 0, 0 } | ||
988 | }; | ||
989 | struct GNUNET_CRYPTO_EcdsaPublicKey my_zone; | ||
990 | |||
991 | if (CS_ACTIVE == call->state) | ||
992 | { | ||
993 | call->speaker->disable_speaker (call->speaker->cls); | ||
994 | call->mic->disable_microphone (call->mic->cls); | ||
995 | } | ||
996 | if (NULL != call->mq) | ||
997 | { | ||
998 | GNUNET_MQ_destroy (call->mq); | ||
999 | call->mq = NULL; | ||
1000 | } | ||
1001 | if (NULL != call->client) | ||
1002 | { | ||
1003 | GNUNET_CLIENT_disconnect (call->client); | ||
1004 | call->client = NULL; | ||
1005 | } | ||
1006 | call->state = CS_SHUTDOWN; | ||
1007 | call->client = GNUNET_CLIENT_connect ("conversation", call->cfg); | ||
1008 | if (NULL == call->client) | ||
1009 | return; | ||
1010 | call->mq = GNUNET_MQ_queue_for_connection_client (call->client, | ||
1011 | handlers, | ||
1012 | &call_error_handler, | ||
1013 | call); | ||
1014 | call->state = CS_LOOKUP; | ||
1015 | GNUNET_IDENTITY_ego_get_public_key (call->caller_id, | ||
1016 | &my_zone); | ||
1017 | call->gns_lookup = GNUNET_GNS_lookup (call->gns, | ||
1018 | call->callee, | ||
1019 | &my_zone, | ||
1020 | GNUNET_GNSRECORD_TYPE_PHONE, | ||
1021 | GNUNET_NO, | ||
1022 | NULL /* FIXME: add shortening support */, | ||
1023 | &handle_gns_response, call); | ||
1024 | GNUNET_assert (NULL != call->gns_lookup); | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | /** | ||
1029 | * Call the phone of another user. | ||
1030 | * | ||
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 | ||
1041 | */ | ||
1042 | struct GNUNET_CONVERSATION_Call * | ||
1043 | GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1044 | struct GNUNET_IDENTITY_Ego *caller_id, | ||
1045 | const char *callee, | ||
1046 | struct GNUNET_SPEAKER_Handle *speaker, | ||
1047 | struct GNUNET_MICROPHONE_Handle *mic, | ||
1048 | GNUNET_CONVERSATION_EventHandler event_handler, | ||
1049 | void *event_handler_cls) | ||
1050 | { | ||
1051 | struct GNUNET_CONVERSATION_Call *call; | ||
1052 | |||
1053 | call = GNUNET_new (struct GNUNET_CONVERSATION_Call); | ||
1054 | call->cfg = cfg; | ||
1055 | call->caller_id = caller_id; | ||
1056 | call->callee = GNUNET_strdup (callee); | ||
1057 | call->speaker = speaker; | ||
1058 | call->mic = mic; | ||
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); | ||
1063 | |||
1064 | if ( (NULL == call->client) || | ||
1065 | (NULL == call->gns) ) | ||
1066 | { | ||
1067 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
1068 | return NULL; | ||
1069 | } | ||
1070 | return call; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /** | ||
1075 | * We've sent the hang up message, now finish terminating the call. | ||
1076 | * | ||
1077 | * @param cls the `struct GNUNET_CONVERSATION_Call` to terminate | ||
1078 | */ | ||
1079 | static void | ||
1080 | finish_stop (void *cls) | ||
1081 | { | ||
1082 | struct GNUNET_CONVERSATION_Call *call = cls; | ||
1083 | |||
1084 | GNUNET_assert (CS_SHUTDOWN == call->state); | ||
1085 | GNUNET_CONVERSATION_call_stop (call, NULL); | ||
1086 | } | ||
1087 | |||
1088 | |||
1089 | /** | ||
1090 | * Terminate a call. The call may be ringing or ready at this time. | ||
1091 | * | ||
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 | ||
1095 | */ | 821 | */ |
1096 | void | 822 | void |
1097 | GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call, | 823 | GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller, |
1098 | const char *reason) | 824 | struct GNUNET_SPEAKER_Handle *speaker, |
825 | struct GNUNET_MICROPHONE_Handle *mic) | ||
1099 | { | 826 | { |
1100 | struct GNUNET_MQ_Envelope *e; | 827 | GNUNET_break (0); |
1101 | struct ClientPhoneHangupMessage *hang; | ||
1102 | size_t slen; | ||
1103 | |||
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); | ||
1110 | if (NULL != reason) | ||
1111 | { | ||
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; | ||
1118 | return; | ||
1119 | } | ||
1120 | if (NULL != call->mq) | ||
1121 | { | ||
1122 | GNUNET_MQ_destroy (call->mq); | ||
1123 | call->mq = NULL; | ||
1124 | } | ||
1125 | if (NULL != call->client) | ||
1126 | { | ||
1127 | GNUNET_CLIENT_disconnect (call->client); | ||
1128 | call->client = NULL; | ||
1129 | } | ||
1130 | if (NULL != call->gns_lookup) | ||
1131 | { | ||
1132 | GNUNET_GNS_lookup_cancel (call->gns_lookup); | ||
1133 | call->gns_lookup = NULL; | ||
1134 | } | ||
1135 | if (NULL != call->gns) | ||
1136 | { | ||
1137 | GNUNET_GNS_disconnect (call->gns); | ||
1138 | call->gns = NULL; | ||
1139 | } | ||
1140 | GNUNET_free (call->callee); | ||
1141 | GNUNET_free (call); | ||
1142 | } | 828 | } |
1143 | 829 | ||
1144 | |||
1145 | /* end of conversation_api.c */ | 830 | /* end of conversation_api.c */ |