Example #1
0
void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
{
    // We might be running in the FFmpeg thread and holding the CameraSource lock
    // So be careful not to deadlock with anything while toxav locks in toxav_video_send_frame
    auto it = calls.find(callId);
    if (it == calls.end()) {
        return;
    }

    ToxFriendCall& call = it->second;

    if (!call.getVideoEnabled() || !call.isActive()
        || !(call.getState() & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V)) {
        return;
    }

    if (call.getNullVideoBitrate()) {
        qDebug() << "Restarting video stream to friend" << callId;
#if TOX_VERSION_IS_API_COMPATIBLE(0, 2, 0)
        toxav_video_set_bit_rate(toxav, callId, VIDEO_DEFAULT_BITRATE, nullptr);
#else
        toxav_bit_rate_set(toxav, callId, -1, VIDEO_DEFAULT_BITRATE, nullptr);
#endif
        call.setNullVideoBitrate(false);
    }

    ToxYUVFrame frame = vframe->toToxYUVFrame();

    if (!frame) {
        return;
    }

    // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case
    // We don't want to be dropping iframes because of some lock held by toxav_iterate
    TOXAV_ERR_SEND_FRAME err;
    int retries = 0;
    do {
        if (!toxav_video_send_frame(toxav, callId, frame.width, frame.height, frame.y, frame.u,
                                    frame.v, &err)) {
            if (err == TOXAV_ERR_SEND_FRAME_SYNC) {
                ++retries;
                QThread::usleep(500);
            } else {
                qDebug() << "toxav_video_send_frame error: " << err;
            }
        }
    } while (err == TOXAV_ERR_SEND_FRAME_SYNC && retries < 5);
    if (err == TOXAV_ERR_SEND_FRAME_SYNC) {
        qDebug() << "toxav_video_send_frame error: Lock busy, dropping frame";
    }
}
Example #2
0
void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
{
    // We might be running in the FFmpeg thread and holding the CameraSource lock
    // So be careful not to deadlock with anything while toxav locks in toxav_video_send_frame
    if (!calls.contains(callId))
        return;

    ToxFriendCall& call = calls[callId];

    if (!call.videoEnabled || call.inactive
            || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V))
        return;

    if (call.nullVideoBitrate)
    {
        qDebug() << "Restarting video stream to friend"<<callId;
        toxav_bit_rate_set(toxav, call.callId, -1, VIDEO_DEFAULT_BITRATE, nullptr);
        call.nullVideoBitrate = false;
    }

    ToxYUVFrame frame = vframe->toToxYUVFrame();

    if(!frame)
    {
        return;
    }

    // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case
    // We don't want to be dropping iframes because of some lock held by toxav_iterate
    TOXAV_ERR_SEND_FRAME err;
    int retries = 0;
    do {
        if (!toxav_video_send_frame(toxav, callId, frame.width, frame.height,
                                    frame.y, frame.u, frame.v, &err))
        {
            if (err == TOXAV_ERR_SEND_FRAME_SYNC)
            {
                ++retries;
                QThread::usleep(500);
            }
            else
            {
                qDebug() << "toxav_video_send_frame error: "<<err;
            }
        }
    } while (err == TOXAV_ERR_SEND_FRAME_SYNC && retries < 5);
    if (err == TOXAV_ERR_SEND_FRAME_SYNC)
        qDebug() << "toxav_video_send_frame error: Lock busy, dropping frame";
}
Example #3
0
void utox_video_thread(void *args) {
    ToxAV *av = args;

    pthread_mutex_init(&video_thread_lock, NULL);

    init_video_devices();

    utox_video_thread_init = 1;

    while (1) {
        if (video_thread_msg) {
            if (!video_msg.msg || video_msg.msg == UTOXVIDEO_KILL) {
                break;
            }

            switch (video_msg.msg) {
                case UTOXVIDEO_NEW_AV_INSTANCE: {
                    av = video_msg.data;
                    init_video_devices();
                    break;
                }
            }
            video_thread_msg = false;
        }

        if (video_active) {
            pthread_mutex_lock(&video_thread_lock);
            // capturing is enabled, capture frames
            const int r = native_video_getframe(utox_video_frame.y, utox_video_frame.u, utox_video_frame.v,
                                                utox_video_frame.w, utox_video_frame.h);
            if (r == 1) {
                if (settings.video_preview) {
                    /* Make a copy of the video frame for uTox to display */
                    UTOX_FRAME_PKG *frame = malloc(sizeof(UTOX_FRAME_PKG));
                    frame->w              = utox_video_frame.w;
                    frame->h              = utox_video_frame.h;
                    frame->img            = malloc(utox_video_frame.w * utox_video_frame.h * 4);

                    yuv420tobgr(utox_video_frame.w, utox_video_frame.h, utox_video_frame.y, utox_video_frame.u,
                                utox_video_frame.v, utox_video_frame.w, (utox_video_frame.w / 2),
                                (utox_video_frame.w / 2), frame->img);

                    postmessage_utox(AV_VIDEO_FRAME, UINT16_MAX, 1, (void *)frame);
                }

                size_t active_video_count = 0;
                for (size_t i = 0; i < self.friend_list_count; i++) {
                    if (SEND_VIDEO_FRAME(i)) {
                        LOG_TRACE("uToxVideo", "sending video frame to friend %lu" , i);
                        active_video_count++;
                        TOXAV_ERR_SEND_FRAME error = 0;
                        toxav_video_send_frame(av, get_friend(i)->number, utox_video_frame.w, utox_video_frame.h,
                                               utox_video_frame.y, utox_video_frame.u, utox_video_frame.v, &error);
                        // LOG_TRACE("uToxVideo", "Sent video frame to friend %u" , i);
                        if (error) {
                            if (error == TOXAV_ERR_SEND_FRAME_SYNC) {
                                LOG_ERR("uToxVideo", "Vid Frame sync error: w=%u h=%u", utox_video_frame.w, utox_video_frame.h);
                            } else if (error == TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED) {
                                LOG_ERR("uToxVideo",
                                    "ToxAV disagrees with our AV state for friend %lu, self %u, friend %u",
                                        i, get_friend(i)->call_state_self, get_friend(i)->call_state_friend);
                            } else {
                                LOG_ERR("uToxVideo", "toxav_send_video error friend: %i error: %u",
                                        get_friend(i)->number, error);
                            }
                        } else {
                            if (active_video_count >= UTOX_MAX_CALLS) {
                                LOG_ERR("uToxVideo", "Trying to send video frame to too many peers. Please report this bug!");
                                break;
                            }
                        }
                    }
                }
            } else if (r == -1) {
                LOG_ERR("uToxVideo", "Err... something really bad happened trying to get this frame, I'm just going "
                            "to plots now!");
                video_device_stop();
                close_video_device(video_device);
            }

            pthread_mutex_unlock(&video_thread_lock);
            yieldcpu(1000 / settings.video_fps); /* 60fps = 16.666ms || 25 fps = 40ms || the data quality is SO much better at 25... */
            continue;     /* We're running video, so don't sleep for an extra 100 ms */
        }

        yieldcpu(100);
    }

    video_device_count   = 0;
    video_device_current = 0;
    video_active         = false;

    for (uint8_t i = 0; i < 16; ++i) {
        video_device[i] = NULL;
    }

    video_thread_msg       = 0;
    utox_video_thread_init = 0;
    LOG_TRACE("uToxVideo", "Clean thread exit!");
}
Example #4
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);
}