Exemple #1
0
bool CoreAV::startCall(uint32_t friendNum, bool video)
{
    if (QThread::currentThread() != coreavThread.get()) {
        if (threadSwitchLock.test_and_set(std::memory_order_acquire)) {
            qDebug() << "CoreAV::startCall: Backed off of thread-switch lock";
            return false;
        }

        bool ret;
        QMetaObject::invokeMethod(this, "startCall", Qt::BlockingQueuedConnection,
                                  Q_RETURN_ARG(bool, ret), Q_ARG(uint32_t, friendNum),
                                  Q_ARG(bool, video));

        threadSwitchLock.clear(std::memory_order_release);
        return ret;
    }

    qDebug() << QString("Starting call with %1").arg(friendNum);
    auto it = calls.find(friendNum);
    if (it != calls.end()) {
        qWarning() << QString("Can't start call with %1, we're already in this call!").arg(friendNum);
        return false;
    }

    uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0;
    if (!toxav_call(toxav, friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate, nullptr))
        return false;

    auto ret = calls.insert(std::make_pair(friendNum, ToxFriendCall(friendNum, video, *this)));
    ret.first->second.startTimeout(friendNum);
    return true;
}
Exemple #2
0
bool CoreAV::startCall(uint32_t friendNum, bool video)
{
    if (QThread::currentThread() != coreavThread.get())
    {
        if (threadSwitchLock.test_and_set(std::memory_order_acquire))
        {
            qDebug() << "CoreAV::startCall: Backed off of thread-switch lock";
            return false;
        }

        bool ret;
        QMetaObject::invokeMethod(this, "startCall", Qt::BlockingQueuedConnection,
                                  Q_RETURN_ARG(bool, ret),
                                  Q_ARG(uint32_t, friendNum),
                                  Q_ARG(bool, video));

        threadSwitchLock.clear(std::memory_order_release);
        return ret;
    }

    qDebug() << QString("Starting call with %1").arg(friendNum);
    if (calls.contains(friendNum))
    {
        qWarning() << QString("Can't start call with %1, we're already in this call!").arg(friendNum);
        return false;
    }

    uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0;
    if (!toxav_call(toxav, friendNum, AUDIO_DEFAULT_BITRATE, videoBitrate, nullptr))
        return false;

    auto call = calls.insert({friendNum, video, *this});
    call->startTimeout();
    return true;
}
Exemple #3
0
/*
 * Commands from chat_commands.h
 */
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
    const char *error_str;

    if (argc != 0) {
        error_str = "Unknown arguments.";
        goto on_error;
    }

    if ( !ASettins.av ) {
        error_str = "Audio not supported!";
        goto on_error;
    }

    if (!self->stb->is_online) {
        error_str = "Friend is offline.";
        goto on_error;
    }

    ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, &ASettins.cs, 30);

    if ( error != ErrorNone ) {
        if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!";
        else error_str = "Internal error!";

        goto on_error;
    }

    line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Calling... idx: %d", self->call_idx);

    return;
on_error:
    print_err(self, error_str);
}
Exemple #4
0
void Cyanide::av_call(int fid)
{
    Friend *f = &friends[fid];
    if(f->callstate != 0)
        notify_error("already in a call", "");

    ToxAvCSettings csettings = av_DefaultSettings;

    toxav_call(toxav, &f->call_index, fid, &csettings, 15);
    emit signal_friend_callstate(fid, (f->callstate = -1));
}
Exemple #5
0
void Core::startCall(int friendId, bool video)
{
    int callId;
    ToxAvCSettings cSettings = av_DefaultSettings;
    cSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
    cSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
    if (video)
    {
        qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
        cSettings.call_type = TypeVideo;
        toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
        calls[callId].videoEnabled=true;
    }
    else
    {
        qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
        cSettings.call_type = TypeAudio;
        toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
        calls[callId].videoEnabled=false;
    }
}
Exemple #6
0
void Core::startCall(uint32_t friendId, bool video)
{
    int32_t callId;
    ToxAvCSettings cSettings = av_DefaultSettings;
    cSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
    cSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
    if (video)
    {
        qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
        cSettings.call_type = av_TypeVideo;
        if (toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME) == 0)
        {
            calls[callId].videoEnabled=true;
        }
        else
        {
            qWarning() << QString("Core: Failed to start new video call with %1").arg(friendId);
            emit avCallFailed(friendId);
            return;
        }
    }
    else
    {
        qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
        cSettings.call_type = av_TypeAudio;
        if (toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME) == 0)
        {
            calls[callId].videoEnabled=false;
        }
        else
        {
            qWarning() << QString("Core: Failed to start new audio call with %1").arg(friendId);
            emit avCallFailed(friendId);
            return;
        }
    }
}
    TERMINATE_SCOPE()



    /*************************************************************************************************
     * Other flows
     */

    /*
     * Call and reject
     */
    {
        int step = 0;
        int running = 1;

        while (running) {
            tox_do(bootstrap_node);
            tox_do(Alice);
            tox_do(Bob);

            switch ( step ) {
                case 0: /* Alice */
                    printf("Alice is calling...\n");
                    toxav_call(status_control.Alice.av, 0, TypeAudio, 10);
                    step++;
                    break;
                    \

                case 1: /* Bob */
                    if (status_control.Bob.status == Ringing) {
                        printf("Bob rejects...\n");
                        toxav_reject(status_control.Bob.av, "Who likes D's anyway?");
                        step++;
                    }

                    break;

                case 2:  /* Wait for Both to have status ended */
                    if (status_control.Alice.status == Rejected && status_control.Bob.status == Ended) running = 0;

                    break;
            }

            c_sleep(20);
        }

        printf("\n");
    }
Exemple #8
0
/*
 * Commands from chat_commands.h
 */
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
    TOXAV_ERR_CALL error;
    const char *error_str;

    if ( argc != 0 ) {
        error_str = "Unknown arguments.";
        goto on_error;
    }

    if ( !CallControl.av ) {
        error_str = "ToxAV not supported!";
        goto on_error;
    }

    if ( !self->stb->connection ) {
        error_str = "Friend is offline.";
        goto on_error;
    }

    if ( CallControl.pending_call ) {
        error_str = "Already a pending call!";
        goto on_error;
    }

    toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
    if ( error != TOXAV_ERR_CALL_OK ) {
        if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
        else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
        else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND ) error_str = "Friend number invalid";
        else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED ) error_str = "Friend is valid but not currently connected";
        else error_str = "Internal error!";

        goto on_error;
    }

    CallControl.pending_call = true;
    callback_recv_ringing(self->num);

    return;
on_error:
    print_err(self, error_str);
}
Exemple #9
0
/*
 * Commands from chat_commands.h
 */
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
    uint8_t msg[MAX_STR_SIZE];
    uint8_t *error_str;

    if (argc != 0) {
        error_str = "Invalid syntax!";
        goto on_error;
    }

    if ( !ASettins.av ) {
        error_str = "Audio not supported!";
        goto on_error;
    }

    if (!self->stb->is_online) {
        error_str = "Friend is offline.";
        goto on_error;
    }

    ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, TypeAudio, 30);

    if ( error != ErrorNone ) {
        if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!";
        else error_str = "Internal error!";

        goto on_error;
    }

    snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_idx);
    line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);

    return;
on_error:
    snprintf(msg, sizeof(msg), "%s", error_str);
    line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
Exemple #10
0
void do_phone ( av_session_t *_phone )
{
    INFO("Welcome to tox_phone version: " _USERAGENT "\n"
         "Usage: \n"
         "f [pubkey] (add friend)\n"
         "c [a/v] (type) [friend] (friend id) (calls friend if online)\n"
         "h (if call is active hang up)\n"
         "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
         "r (reject incoming call)\n"
         "q (quit)\n"
         "================================================================================"
        );

    while ( 1 ) {
        char _line [ 1500 ];
        int _len;

        if ( -1 == getinput(_line, 1500, &_len) ) {
            printf(" >> ");
            fflush(stdout);
            continue;
        }

        if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) {
            INFO("Invalid input!");
            continue;
        }

        switch (_line[0]) {

            case 'f': {
                char _id [128];
                strncpy(_id, _line + 2, 128);

                av_add_friend(_phone, _id);

            }
            break;

            case 'c': {
                ToxAvCallType _ctype;

                if ( _len < 5 ) {
                    INFO("Invalid input; usage: c a/v [friend]");
                    break;
                } else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */
                    _ctype = TypeAudio;
                } else { /* video */
                    _ctype = TypeVideo;
                }

                char *_end;
                int _friend = strtol(_line + 4, &_end, 10);

                if ( *_end ) {
                    INFO("Friend num has to be numerical value");
                    break;
                }

                if ( toxav_call(_phone->av, _friend, _ctype, 30) == ErrorAlreadyInCall ) {
                    INFO("Already in a call");
                    break;
                } else INFO("Calling friend: %d!", _friend);

            }
            break;

            case 'h': {
                if ( toxav_hangup(_phone->av) == ErrorNoCall ) {
                    INFO("No call!");
                    break;
                } else INFO("Hung up...");

            }
            break;

            case 'a': {
                ToxAvError rc;

                if ( _len > 1 && _line[2] == 'v' ) {
                    rc = toxav_answer(_phone->av, TypeVideo);
                } else
                    rc = toxav_answer(_phone->av, TypeAudio);

                if ( rc == ErrorInvalidState ) {
                    INFO("No call to answer!");
                }

            }
            break;

            case 'r': {
                if ( toxav_reject(_phone->av, "User action") == ErrorInvalidState )
                    INFO("No state to cancel!");
                else INFO("Call Rejected...");

            }
            break;

            case 'q': {
                INFO("Quitting!");
                return;
            }

            case '\n': {
            }

            default: {
            } break;

        }

    }
}
Exemple #11
0
void *in_thread_call (void *arg)
{
#define call_print(call, what, args...) printf("[%d] " what "\n", call, ##args)

    ACall *this_call = arg;
    uint64_t start = 0;
    int step = 0;
    int call_idx;

    const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
    int16_t sample_payload[frame_size];
    randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);

    uint8_t prepared_payload[RTP_PAYLOAD_SIZE];

    register_callbacks(this_call->Caller.av, &status_control);
    register_callbacks(this_call->Callee.av, arg);

    /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
    pthread_mutex_lock(&muhmutex);

    while (call_running[this_call->idx]) {

        pthread_mutex_unlock(&muhmutex);

        switch ( step ) {
            case 0: /* CALLER */
                toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, &av_DefaultSettings, 10);
                call_print(call_idx, "Calling ...");
                step++;
                break;

            case 1: /* CALLEE */
                pthread_mutex_lock(&muhmutex);

                if (this_call->Caller.status == Ringing) {
                    call_print(call_idx, "Callee answers ...");
                    pthread_mutex_unlock(&muhmutex);
                    toxav_answer(this_call->Callee.av, 0, &av_DefaultSettings);
                    step++;
                    start = time(NULL);
                    pthread_mutex_lock(&muhmutex);
                }

                pthread_mutex_unlock(&muhmutex);
                break;

            case 2: /* Rtp transmission */
                pthread_mutex_lock(&muhmutex);

                if (this_call->Caller.status == InCall) { /* I think this is okay */
                    call_print(call_idx, "Sending rtp ...");
                    pthread_mutex_unlock(&muhmutex);

                    c_sleep(1000); /* We have race condition here */
                    toxav_prepare_transmission(this_call->Callee.av, 0, 1);
                    toxav_prepare_transmission(this_call->Caller.av, call_idx, 1);

                    int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE,
                                       sample_payload, frame_size);

                    if ( payload_size < 0 ) {
                        ck_assert_msg ( 0, "Failed to encode payload" );
                    }


                    while (time(NULL) - start < 10) { /* 10 seconds */
                        /* Both send */
                        toxav_send_audio(this_call->Caller.av, call_idx, prepared_payload, payload_size);

                        toxav_send_audio(this_call->Callee.av, 0, prepared_payload, payload_size);

                        /* Both receive */
                        int16_t storage[RTP_PAYLOAD_SIZE];
                        int recved;

                        c_sleep(20);
                    }

                    step++; /* This terminates the loop */

                    pthread_mutex_lock(&muhmutex);
                    toxav_kill_transmission(this_call->Callee.av, 0);
                    toxav_kill_transmission(this_call->Caller.av, call_idx);
                    pthread_mutex_unlock(&muhmutex);

                    /* Call over CALLER hangs up */
                    toxav_hangup(this_call->Caller.av, call_idx);
                    call_print(call_idx, "Hanging up ...");

                    pthread_mutex_lock(&muhmutex);
                }

                pthread_mutex_unlock(&muhmutex);
                break;

            case 3: /* Wait for Both to have status ended */
                pthread_mutex_lock(&muhmutex);

                if (this_call->Caller.status == Ended) {
                    pthread_mutex_unlock(&muhmutex);
                    c_sleep(1000); /* race condition */
                    pthread_mutex_lock(&muhmutex);
                    this_call->Callee.status = Ended;
                    call_running[this_call->idx] = 0;
                }

                pthread_mutex_unlock(&muhmutex);

                break;

        }

        c_sleep(20);

        pthread_mutex_lock(&muhmutex);
    }

    pthread_mutex_unlock(&muhmutex);
    call_print(call_idx, "Call ended successfully!");
    pthread_exit(NULL);
}
Exemple #12
0
static void tox_thread_message(Tox *tox, ToxAv *av, uint64_t time, uint8_t msg, uint16_t param1, uint16_t param2, void *data)
{
    switch(msg) {
    case TOX_SETNAME: {
        /* param1: name length
         * data: name
         */
        tox_set_name(tox, data, param1);
        break;
    }

    case TOX_SETSTATUSMSG: {
        /* param1: status length
         * data: status message
         */
        tox_set_status_message(tox, data, param1);
        break;
    }

    case TOX_SETSTATUS: {
        /* param1: status
         */
        tox_set_user_status(tox, param1);
        break;
    }

    case TOX_ADDFRIEND: {
        /* param1: length of message
         * data: friend id + message
         */
        int r;

        if(!param1) {
            STRING* default_add_msg = SPTR(DEFAULT_FRIEND_REQUEST_MESSAGE);
            r = tox_add_friend(tox, data, default_add_msg->str, default_add_msg->length);
        } else {
            r = tox_add_friend(tox, data, data + TOX_FRIEND_ADDRESS_SIZE, param1);
        }

        if(r < 0) {
            uint8_t addf_error;
            switch(r) {
            case TOX_FAERR_TOOLONG:
                addf_error = ADDF_TOOLONG; break;
            case TOX_FAERR_NOMESSAGE:
                addf_error = ADDF_NOMESSAGE; break;
            case TOX_FAERR_OWNKEY:
                addf_error = ADDF_OWNKEY; break;
            case TOX_FAERR_ALREADYSENT:
                addf_error = ADDF_ALREADYSENT; break;
            case TOX_FAERR_BADCHECKSUM:
                addf_error = ADDF_BADCHECKSUM; break;
            case TOX_FAERR_SETNEWNOSPAM:
                addf_error = ADDF_SETNEWNOSPAM; break;
            case TOX_FAERR_NOMEM:
                addf_error = ADDF_NOMEM; break;
            case TOX_FAERR_UNKNOWN:
            default:
                addf_error = ADDF_UNKNOWN; break;
            }
            postmessage(FRIEND_ADD, 1, addf_error, data);
        } else {
            postmessage(FRIEND_ADD, 0, r, data);
        }
        break;
    }

    case TOX_DELFRIEND: {
        /* param1: friend #
         */
        tox_del_friend(tox, param1);
        postmessage(FRIEND_DEL, 0, 0, data);
        break;
    }

    case TOX_ACCEPTFRIEND: {
        /* data: FRIENDREQ
         */
        FRIENDREQ *req = data;
        int r = tox_add_friend_norequest(tox, req->id);
        postmessage(FRIEND_ACCEPT, (r < 0), (r < 0) ? 0 : r, req);
        break;
    }

    case TOX_SENDMESSAGE: {
        /* param1: friend #
         * param2: message length
         * data: message
         */
        log_write(tox, param1, data, param2, 1, LOG_FILE_MSG_TYPE_TEXT);

        void *p = data;
        while(param2 > TOX_MAX_MESSAGE_LENGTH) {
            uint16_t len = TOX_MAX_MESSAGE_LENGTH - utf8_unlen(p + TOX_MAX_MESSAGE_LENGTH);
            tox_send_message(tox, param1, p, len);
            param2 -= len;
            p += len;
        }

        tox_send_message(tox, param1, p, param2);
        free(data);
        break;
    }

    case TOX_SENDACTION: {
        /* param1: friend #
         * param2: message length
         * data: message
         */

        log_write(tox, param1, data, param2, 1, LOG_FILE_MSG_TYPE_ACTION);

        void *p = data;
        while(param2 > TOX_MAX_MESSAGE_LENGTH) {
            uint16_t len = TOX_MAX_MESSAGE_LENGTH - utf8_unlen(p + TOX_MAX_MESSAGE_LENGTH);
            tox_send_action(tox, param1, p, len);
            param2 -= len;
            p += len;
        }

        tox_send_action(tox, param1, p, param2);
        free(data);
        break;
    }

    case TOX_SENDMESSAGEGROUP: {
        /* param1: group #
         * param2: message length
         * data: message
         */
        tox_group_message_send(tox, param1, data, param2);
        free(data);
        break;
    }

    case TOX_SENDACTIONGROUP: {
        /* param1: group #
         * param2: message length
         * data: message
         */
        tox_group_action_send(tox, param1, data, param2);
        free(data);
    }

    case TOX_SET_TYPING: {
        /* param1: friend #
         */

        // Check if user has switched to another friend window chat.
        // Take care not to react on obsolete data from old Tox instance.
        _Bool need_resetting = (typing_state.tox == tox) &&
            (typing_state.friendnumber != param1) &&
            (typing_state.sent_value);

        if(need_resetting) {
            // Tell previous friend that he's betrayed.
            tox_set_user_is_typing(tox, typing_state.friendnumber, 0);
            // Mark that new friend doesn't know that we're typing yet.
            typing_state.sent_value = 0;
        }

        // Mark us as typing to this friend at the moment.
        // utox_thread_work_for_typing_notifications() will
        // send a notification if it deems necessary.
        typing_state.tox = tox;
        typing_state.friendnumber = param1;
        typing_state.time = time;

        //debug("Set typing state for friend (%d): %d\n", typing_state.friendnumber, typing_state.sent_value);
        break;
    }

    case TOX_CALL: {
        /* param1: friend #
         */
        int32_t id;
        toxav_call(av, &id, param1, &av_DefaultSettings, 10);

        postmessage(FRIEND_CALL_STATUS, param1, id, (void*)CALL_RINGING);
        break;
    }

    case TOX_CALL_VIDEO: {
        /* param1: friend #
         */
        ToxAvCSettings settings = av_DefaultSettings;
        settings.call_type = av_TypeVideo;
        settings.max_video_width = max_video_width;
        settings.max_video_height = max_video_height;

        int32_t id;
        toxav_call(av, &id, param1, &settings, 10);

        postmessage(FRIEND_CALL_STATUS, param1, id, (void*)CALL_RINGING_VIDEO);
        break;
    }

    case TOX_CALL_VIDEO_ON: {
        /* param1: friend #
         * param2: call #
         */
        ToxAvCSettings settings = av_DefaultSettings;
        settings.call_type = av_TypeVideo;
        settings.max_video_width = max_video_width;
        settings.max_video_height = max_video_height;

        toxav_change_settings(av, param2, &settings);
        postmessage(FRIEND_CALL_START_VIDEO, param1, param2, NULL);
        break;
    }

    case TOX_CALL_VIDEO_OFF: {
        /* param1: friend #
         * param2: call #
         */
        toxav_change_settings(av, param2, &av_DefaultSettings);
        postmessage(FRIEND_CALL_STOP_VIDEO, param1, param2, NULL);
        break;
    }

    case TOX_ACCEPTCALL: {
        /* param1: call #
         */
        ToxAvCSettings settings = av_DefaultSettings;
        if(param2) {
            settings.call_type = av_TypeVideo;
            settings.max_video_width = max_video_width;
            settings.max_video_height = max_video_height;
        }

        toxav_answer(av, param1, &settings);
        break;
    }

    case TOX_HANGUP: {
        /* param1: call #
         */
        toxav_hangup(av, param1);
        break;
    }

    case TOX_NEWGROUP: {
        /*
         */
        int g = -1;
        if (param1) {
            g = toxav_add_av_groupchat(tox, &callback_av_group_audio, NULL);
        } else {
            g = tox_add_groupchat(tox);
        }
        if(g != -1) {
            postmessage(GROUP_ADD, g, 0, tox);
        }

        break;
    }

    case TOX_LEAVEGROUP: {
        /* param1: group #
         */
        tox_del_groupchat(tox, param1);
        break;
    }

    case TOX_GROUPINVITE: {
        /* param1: group #
         * param2: friend #
         */
        tox_invite_friend(tox, param2, param1);
        break;
    }

    case TOX_GROUPCHANGETOPIC: {
        /* param1: group #
         * param2: topic length
         * data: topic
         */
        tox_group_set_title(tox, param1, data, param2);
        postmessage(GROUP_TITLE, param1, param2, data);
        break;
    }

    case TOX_GROUP_AUDIO_START:{
        /* param1: group #
         */
        postmessage(GROUP_AUDIO_START, param1, 0, NULL);
        break;
    }

    case TOX_GROUP_AUDIO_END:{
        /* param1: group #
         */
        postmessage(GROUP_AUDIO_END, param1, 0, NULL);
        break;
    }

    case TOX_SENDFILES: {
        /* param1: friend #
         * param2: offset of first file name in data
         * data: file names
         */

        if(param2 == 0xFFFF) {
            //paths with line breaks
            uint8_t *name = data, *p = data, *s = name;
            while(*p) {
                _Bool end = 1;
                while(*p) {
                    if(*p == '\n') {
                        *p = 0;
                        end = 0;
                        break;
                    }

                    if(*p == '/' || *p == '\\') {
                        s = p + 1;
                    }
                    p++;
                }

                if(strcmp2(name, "file://") == 0) {
                    name += 7;
                }

                utox_transfer_start_file(tox, param1, name, s, p - s);
                p++;
                s = name = p;

                if(end) {
                    break;
                }
            }
        } else {
            //windows path list
            uint8_t *name = data;
            _Bool multifile = (name[param2 - 1] == 0);
            if(!multifile) {
                utox_transfer_start_file(tox, param1, data, data + param2, strlen(data) - param2);
            } else {
                uint8_t *p = name + param2;
                name += param2 - 1;
                if(*(name - 1) != '\\') {
                    *name++ = '\\';
                }
                while(*p) {
                    int len = strlen((char*)p) + 1;
                    memmove(name, p, len);
                    p += len;
                    utox_transfer_start_file(tox, param1, data, name, len - 1);
                }
            }
        }

        free(data);

        break;
    }

    case TOX_SEND_INLINE: {
        /* param1: friend id
           data: pointer to a TOX_SEND_INLINE_MSG struct
         */
        struct TOX_SEND_INLINE_MSG *tsim = data;
        utox_transfer_start_memory(tox, param1, tsim->image->png_data, tsim->image_size);
        free(tsim);

        break;
    }

    case TOX_ACCEPTFILE: {
        /* param1: friend #
         * param2: file #
         * data: path to write file
         */
        FILE_T *ft = &friend[param1].incoming[param2];
        ft->data = fopen(data, "wb");
        if(!ft->data) {
            free(data);
            break;
        }

        ft->path = data;
        ft->status = FT_SEND;

        tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_ACCEPT, NULL, 0);

        postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_OK);
        break;
    }

    case TOX_FILE_IN_CANCEL:
    {
        /* param1: friend #
         * param2: file #
         */
        FILE_T *ft = &friend[param1].incoming[param2];
        if(ft->data) {
            if(ft->inline_png) {
                free(ft->data);
            } else {
                fclose(ft->data);
                free(ft->path);
            }
        }

        ft->status = FT_NONE;
        tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_KILL, NULL, 0);
        postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_KILLED);
        break;
    }

    case TOX_FILE_OUT_CANCEL:
    {
        /* param1: friend #
         * param2: file #
         */
        FILE_T *ft = &friend[param1].outgoing[param2];
        ft->status = FT_KILL;
        tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_KILL, NULL, 0);
        postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_KILLED);
        break;
    }

    case TOX_FILE_IN_PAUSE:
    {
        /* param1: friend #
         * param2: file #
         */
        tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_PAUSE, NULL, 0);
        postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_PAUSED);
        break;
    }

    case TOX_FILE_OUT_PAUSE:
    {
        /* param1: friend #
         * param2: file #
         */
        FILE_T *ft = &friend[param1].outgoing[param2];
        ft->status = FT_PAUSE;
        tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_PAUSE, NULL, 0);
        postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_PAUSED);
        break;
    }

    case TOX_FILE_IN_RESUME:
    {
        /* param1: friend #
         * param2: file #
         */
        tox_file_send_control(tox, param1, 1, param2, TOX_FILECONTROL_ACCEPT, NULL, 0);
        postmessage(FRIEND_FILE_IN_STATUS, param1, param2, (void*)FILE_OK);
        break;
    }

    case TOX_FILE_OUT_RESUME:
    {
        /* param1: friend #
         * param2: file #
         */
        FILE_T *ft = &friend[param1].outgoing[param2];
        ft->status = FT_SEND;
        tox_file_send_control(tox, param1, 0, param2, TOX_FILECONTROL_ACCEPT, NULL, 0);
        postmessage(FRIEND_FILE_OUT_STATUS, param1, param2, (void*)FILE_OK);
        break;
    }

    }
}
Exemple #13
0
static void *call_thread(void *pd)
{
    ToxAV *AliceAV = ((thread_data *) pd)->AliceAV;
    ToxAV *BobAV = ((thread_data *) pd)->BobAV;
    CallControl *AliceCC = ((thread_data *) pd)->AliceCC;
    CallControl *BobCC = ((thread_data *) pd)->BobCC;
    uint32_t friend_number = ((thread_data *) pd)->friend_number;

    memset(AliceCC, 0, sizeof(CallControl));
    memset(BobCC, 0, sizeof(CallControl));

    { /* Call */
        TOXAV_ERR_CALL rc;
        toxav_call(AliceAV, friend_number, 48, 3000, &rc);

        if (rc != TOXAV_ERR_CALL_OK) {
            printf("toxav_call failed: %d\n", rc);
            ck_assert(0);
        }
    }

    while (!BobCC->incoming) {
        c_sleep(10);
    }

    { /* Answer */
        TOXAV_ERR_ANSWER rc;
        toxav_answer(BobAV, 0, 8, 500, &rc);

        if (rc != TOXAV_ERR_ANSWER_OK) {
            printf("toxav_answer failed: %d\n", rc);
            ck_assert(0);
        }
    }

    c_sleep(30);

    int16_t *PCM = (int16_t *)calloc(960, sizeof(int16_t));
    uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t));
    uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t));
    uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t));

    time_t start_time = time(NULL);

    while (time(NULL) - start_time < 4) {
        toxav_iterate(AliceAV);
        toxav_iterate(BobAV);

        toxav_audio_send_frame(AliceAV, friend_number, PCM, 960, 1, 48000, NULL);
        toxav_audio_send_frame(BobAV, 0, PCM, 960, 1, 48000, NULL);

        toxav_video_send_frame(AliceAV, friend_number, 800, 600, video_y, video_u, video_v, NULL);
        toxav_video_send_frame(BobAV, 0, 800, 600, video_y, video_u, video_v, NULL);

        c_sleep(10);
    }

    { /* Hangup */
        TOXAV_ERR_CALL_CONTROL rc;
        toxav_call_control(AliceAV, friend_number, TOXAV_CALL_CONTROL_CANCEL, &rc);

        if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
            printf("toxav_call_control failed: %d %p %p\n", rc, (void *)AliceAV, (void *)BobAV);
        }
    }

    c_sleep(30);

    free(PCM);
    free(video_y);
    free(video_u);
    free(video_v);

    printf("Closing thread\n");
    pthread_exit(NULL);
}