URI: 
       tAdd initial outgoing call-support - ratox - FIFO based tox client
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit ec6500034cced8095959c9bf3c74566d0335e000
   DIR parent 66976cfd80dce258a66734e34cf21491b0d4d098
  HTML Author: FRIGN <dev@frign.de>
       Date:   Sat,  4 Oct 2014 11:47:32 +0200
       
       Add initial outgoing call-support
       
       This works, but the audio is a bit muffled up, which takes some
       fine-tuning.
       Also, not all state-transitions are yet taken into account.
       
       Diffstat:
         M config.def.h                        |       2 ++
         M ratox.c                             |     146 ++++++++++++++++++++++++++++---
       
       2 files changed, 134 insertions(+), 14 deletions(-)
       ---
   DIR diff --git a/config.def.h b/config.def.h
       t@@ -2,6 +2,8 @@
        #define DATAFILE ".ratox.data"
        /* connection delay in seconds */
        #define CONNECTDELAY 3
       +/* ringing delay in seconds */
       +#define RINGINGDELAY 9
        #define MAXCALLS 8
        
        static int encryptdatafile = 0;
   DIR diff --git a/ratox.c b/ratox.c
       t@@ -103,28 +103,30 @@ static struct slot gslots[] = {
        enum {
                FTEXT_IN,
                FFILE_IN,
       +        FCALL_IN,
       +        FTEXT_OUT,
                FFILE_OUT,
       +        FCALL_OUT,
                FREMOVE,
                FONLINE,
                FNAME,
                FSTATUS,
       -        FTEXT_OUT,
                FFILE_PENDING,
       -        FCALL_OUT,
                FCALL_PENDING,
        };
        
        static struct file ffiles[] = {
                [FTEXT_IN]      = { .type = FIFO,   .name = "text_in",      .flags = O_RDONLY | O_NONBLOCK         },
                [FFILE_IN]      = { .type = FIFO,   .name = "file_in",      .flags = O_RDONLY | O_NONBLOCK         },
       +        [FCALL_IN]      = { .type = FIFO,   .name = "call_in",      .flags = O_RDONLY | O_NONBLOCK         },
       +        [FTEXT_OUT]     = { .type = STATIC, .name = "text_out",     .flags = O_WRONLY | O_APPEND | O_CREAT },
                [FFILE_OUT]     = { .type = FIFO,   .name = "file_out",     .flags = O_WRONLY | O_NONBLOCK         },
       +        [FCALL_OUT]     = { .type = FIFO,   .name = "call_out",     .flags = O_WRONLY | O_NONBLOCK         },
                [FREMOVE]       = { .type = FIFO,   .name = "remove",       .flags = O_RDONLY | O_NONBLOCK         },
                [FONLINE]       = { .type = STATIC, .name = "online",       .flags = O_WRONLY | O_TRUNC  | O_CREAT },
                [FNAME]         = { .type = STATIC, .name = "name",         .flags = O_WRONLY | O_TRUNC  | O_CREAT },
                [FSTATUS]       = { .type = STATIC, .name = "status",       .flags = O_WRONLY | O_TRUNC  | O_CREAT },
       -        [FTEXT_OUT]     = { .type = STATIC, .name = "text_out",     .flags = O_WRONLY | O_APPEND | O_CREAT },
                [FFILE_PENDING] = { .type = STATIC, .name = "file_pending", .flags = O_WRONLY | O_TRUNC  | O_CREAT },
       -        [FCALL_OUT]     = { .type = FIFO,   .name = "call_out",     .flags = O_WRONLY | O_NONBLOCK         },
                [FCALL_PENDING] = { .type = STATIC, .name = "call_pending", .flags = O_WRONLY | O_TRUNC  | O_CREAT },
        };
        
       t@@ -145,8 +147,12 @@ struct transfer {
        };
        
        struct call {
       -        ToxAvCallState state;
                int num;
       +        ToxAvCallState state;
       +        uint8_t *frame;
       +        uint8_t payload[RTP_PAYLOAD_SIZE];
       +        ssize_t n;
       +        int incompleteframe;
        };
        
        struct friend {
       t@@ -176,6 +182,7 @@ static TAILQ_HEAD(reqhead, request) reqhead = TAILQ_HEAD_INITIALIZER(reqhead);
        static Tox *tox;
        static ToxAv *toxav;
        static ToxAvCSettings toxavconfig;
       +static int framesize;
        static Tox_Options toxopt;
        static uint8_t *passphrase;
        static uint32_t pplen;
       t@@ -201,6 +208,8 @@ static void cbpeertimeout(void *, int32_t, void *);
        static void cbcalltypechange(void *, int32_t, void *);
        static void cbcalldata(ToxAv *, int32_t, int16_t *, int, void *);
        static void cancelrxcall(struct friend *, char *);
       +static void canceltxcall(struct friend *, char *);
       +static void sendfriendcalldata(struct friend *);
        static void cbconnstatus(Tox *, int32_t, uint8_t, void *);
        static void cbfriendmessage(Tox *, int32_t, const uint8_t *, uint16_t, void *);
        static void cbfriendrequest(Tox *, const uint8_t *, const uint8_t *, uint16_t, void *);
       t@@ -375,6 +384,7 @@ cbcallended(void *av, int32_t cnum, void *udata)
                        return;
        
                cancelrxcall(f, "Ended");
       +        canceltxcall(f, "Ended");
        }
        
        static void
       t@@ -389,24 +399,49 @@ cbcallcancelled(void *av, int32_t cnum, void *udata)
                        return;
        
                cancelrxcall(f, "Cancelled");
       +        canceltxcall(f, "Cancelled");
        }
        
        static void
        cbcallrejected(void *av, int32_t cnum, void *udata)
        {
       -        printf("Entered %s\n", __func__);
       +        struct friend *f;
       +
       +        TAILQ_FOREACH(f, &friendhead, entry)
       +                if (f->av.num == cnum)
       +                        break;
       +        if (!f)
       +                return;
       +
       +        canceltxcall(f, "Rejected");
        }
        
        static void
        cbcallringing(void *av, int32_t cnum, void *udata)
        {
       -        printf("Entered %s\n", __func__);
       +        return;
        }
        
        static void
        cbcallstarting(void *av, int32_t cnum, void *udata)
        {
       -        printf("Entered %s\n", __func__);
       +        struct friend *f;
       +
       +        TAILQ_FOREACH(f, &friendhead, entry)
       +                if (f->av.num == cnum)
       +                        break;
       +        if (!f)
       +                return;
       +
       +        printout(" : %s : Tx AV > Started\n", f->name);
       +
       +        f->av.frame = malloc(sizeof(int16_t) * framesize);
       +        if (!f->av.frame)
       +                eprintf("malloc:");
       +        f->av.n = 0;
       +        f->av.incompleteframe = 0;
       +        f->av.state = av_CallActive;
       +        toxav_prepare_transmission(toxav, cnum, av_jbufdc, av_VADd, 0);
        }
        
        static void
       t@@ -421,11 +456,21 @@ cbcallending(void *av, int32_t cnum, void *udata)
                        return;
        
                cancelrxcall(f, "Ending");
       +        canceltxcall(f, "Ending");
        }
        
        static void
        cbreqtimeout(void *av, int32_t cnum, void *udata)
        {
       +        struct friend *f;
       +
       +        TAILQ_FOREACH(f, &friendhead, entry)
       +                if (f->av.num == cnum)
       +                        break;
       +        if (!f)
       +                return;
       +        cancelrxcall(f, "Timeout");
       +        canceltxcall(f, "Timeout");
                printf("Entered %s\n", __func__);
        }
        
       t@@ -490,6 +535,57 @@ cancelrxcall(struct friend *f, char *action)
        }
        
        static void
       +canceltxcall(struct friend *f, char *action)
       +{
       +        printout(": %s : Tx AV > %s\n", f->name, action);
       +        f->av.state = av_CallNonExistant;
       +        f->av.num = -1;
       +        free(f->av.frame);
       +        f->av.frame = NULL;
       +        fiforeset(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN]);
       +}
       +
       +static void
       +sendfriendcalldata(struct friend *f)
       +{
       +        ssize_t n, payloadsize;
       +
       +        n = fiforead(f->dirfd, &f->fd[FCALL_IN], ffiles[FCALL_IN],
       +                     f->av.frame + f->av.incompleteframe * f->av.n,
       +                     framesize * sizeof(int16_t) - f->av.incompleteframe * f->av.n);
       +        if (n == 0) {
       +                memset(f->av.frame + f->av.incompleteframe * f->av.n, 0,
       +                       framesize * sizeof(int16_t) - f->av.incompleteframe * f->av.n);
       +        } else if (n == -1) {
       +                return;
       +        } else if (n == (framesize * sizeof(int16_t) - f->av.incompleteframe * f->av.n)) {
       +                f->av.incompleteframe = 0;
       +                f->av.n = 0;
       +        } else {
       +                f->av.n += n;
       +                return;
       +        }
       +
       +        payloadsize = toxav_prepare_audio_frame(toxav, f->av.num,
       +                                                 f->av.payload, sizeof(f->av.payload),
       +                                                 (int16_t *)f->av.frame, framesize);
       +        if (payloadsize < 0)
       +                eprintf("failed to encode payload\n");
       +
       +        toxav_send_audio(toxav, f->av.num, f->av.payload, payloadsize);
       +
       +        if (n == 0) {
       +                cancelrxcall(f, "Ended");
       +                canceltxcall(f, "Ended");
       +                toxav_kill_transmission(toxav, f->av.num);
       +                toxav_hangup(toxav, f->av.num);
       +                f->av.state = av_CallNonExistant;
       +                return;
       +        }
       +
       +}
       +
       +static void
        cbconnstatus(Tox *m, int32_t frnum, uint8_t status, void *udata)
        {
                struct friend *f;
       t@@ -1062,6 +1158,7 @@ toxinit(void)
                        eprintf("Failed to initialize toxav\n");
        
                toxavconfig = av_DefaultSettings;
       +        framesize = (toxavconfig.audio_sample_rate * toxavconfig.audio_frame_duration / 1000);
        
                tox_callback_connection_status(tox, cbconnstatus, NULL);
                tox_callback_friend_message(tox, cbfriendmessage, NULL);
       t@@ -1204,6 +1301,7 @@ friendcreate(int32_t frnum)
                ftruncate(f->fd[FCALL_PENDING], 0);
                dprintf(f->fd[FCALL_PENDING], "0\n");
        
       +        free(f->av.frame);
                f->av.state = av_CallNonExistant;
                f->av.num = -1;
        
       t@@ -1433,12 +1531,18 @@ loop(void)
                                        FD_SET(f->fd[FTEXT_IN], &rfds);
                                        if (f->fd[FTEXT_IN] > fdmax)
                                                fdmax = f->fd[FTEXT_IN];
       -                                if (f->tx.state == TRANSFER_INITIATED ||
       -                                    f->tx.state == TRANSFER_PAUSED)
       -                                        continue;
       -                                FD_SET(f->fd[FFILE_IN], &rfds);
       -                                if (f->fd[FFILE_IN] > fdmax)
       -                                        fdmax = f->fd[FFILE_IN];
       +                                if (f->tx.state == TRANSFER_NONE ||
       +                                    f->tx.state == TRANSFER_INPROGRESS) {
       +                                        FD_SET(f->fd[FFILE_IN], &rfds);
       +                                        if (f->fd[FFILE_IN] > fdmax)
       +                                                fdmax = f->fd[FFILE_IN];
       +                                }
       +                                if (f->av.state == av_CallNonExistant ||
       +                                    f->av.state == av_CallActive) {
       +                                        FD_SET(f->fd[FCALL_IN], &rfds);
       +                                        if (f->fd[FCALL_IN] > fdmax)
       +                                                fdmax = f->fd[FCALL_IN];
       +                                }
                                }
                                FD_SET(f->fd[FREMOVE], &rfds);
                                if (f->fd[FREMOVE] > fdmax)
       t@@ -1582,6 +1686,20 @@ loop(void)
                                                break;
                                        }
                                }
       +                        if (FD_ISSET(f->fd[FCALL_IN], &rfds)) {
       +                                switch (f->av.state) {
       +                                case av_CallNonExistant:
       +                                        toxav_call(toxav, &f->av.num, f->num, &toxavconfig, RINGINGDELAY);
       +                                        f->av.state = av_CallInviting;
       +                                        printout(": %s : Tx AV > Calling\n", f->name);
       +                                        break;
       +                                case av_CallActive:
       +                                        sendfriendcalldata(f);
       +                                        break;
       +                                default:
       +                                        break;
       +                                }
       +                        }
                                if (FD_ISSET(f->fd[FREMOVE], &rfds))
                                        removefriend(f);
                        }