Esempio n. 1
0
MSISession *msi_new(Messenger *m)
{
    if (m == NULL) {
        return NULL;
    }

    MSISession *retu = (MSISession *)calloc(sizeof(MSISession), 1);

    if (retu == NULL) {
        LOGGER_ERROR(m->log, "Allocation failed! Program might misbehave!");
        return NULL;
    }

    if (create_recursive_mutex(retu->mutex) != 0) {
        LOGGER_ERROR(m->log, "Failed to init mutex! Program might misbehave");
        free(retu);
        return NULL;
    }

    retu->messenger = m;

    m_callback_msi_packet(m, handle_msi_packet, retu);

    /* This is called when remote terminates session */
    m_callback_connectionstatus_internal_av(m, on_peer_status, retu);

    LOGGER_DEBUG(m->log, "New msi session: %p ", retu);
    return retu;
}
Esempio n. 2
0
ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
{
    TOXAV_ERR_NEW rc = TOXAV_ERR_NEW_OK;
    ToxAV *av = NULL;

    if (tox == NULL) {
        rc = TOXAV_ERR_NEW_NULL;
        goto END;
    }

    if (((Messenger *)tox)->msi_packet) {
        rc = TOXAV_ERR_NEW_MULTIPLE;
        goto END;
    }

    av = calloc (sizeof(ToxAV), 1);

    if (av == NULL) {
        LOGGER_WARNING("Allocation failed!");
        rc = TOXAV_ERR_NEW_MALLOC;
        goto END;
    }

    if (create_recursive_mutex(av->mutex) != 0) {
        LOGGER_WARNING("Mutex creation failed!");
        rc = TOXAV_ERR_NEW_MALLOC;
        goto END;
    }

    av->m = (Messenger *)tox;
    av->msi = msi_new(av->m);

    if (av->msi == NULL) {
        pthread_mutex_destroy(av->mutex);
        rc = TOXAV_ERR_NEW_MALLOC;
        goto END;
    }

    av->interval = 200;
    av->msi->av = av;

    msi_register_callback(av->msi, callback_invite, msi_OnInvite);
    msi_register_callback(av->msi, callback_start, msi_OnStart);
    msi_register_callback(av->msi, callback_end, msi_OnEnd);
    msi_register_callback(av->msi, callback_error, msi_OnError);
    msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout);
    msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities);

END:

    if (error)
        *error = rc;

    if (rc != TOXAV_ERR_NEW_OK) {
        free(av);
        av = NULL;
    }

    return av;
}
Esempio n. 3
0
ACSession *ac_new(Logger *log, ToxAV *av, uint32_t friend_number, toxav_audio_receive_frame_cb *cb, void *cb_data)
{
    ACSession *ac = (ACSession *)calloc(sizeof(ACSession), 1);

    if (!ac) {
        LOGGER_WARNING(log, "Allocation failed! Application might misbehave!");
        return NULL;
    }

    if (create_recursive_mutex(ac->queue_mutex) != 0) {
        LOGGER_WARNING(log, "Failed to create recursive mutex!");
        free(ac);
        return NULL;
    }

    int status;
    ac->decoder = opus_decoder_create(48000, 2, &status);

    if (status != OPUS_OK) {
        LOGGER_ERROR(log, "Error while starting audio decoder: %s", opus_strerror(status));
        goto BASE_CLEANUP;
    }

    if (!(ac->j_buf = jbuf_new(3))) {
        LOGGER_WARNING(log, "Jitter buffer creaton failed!");
        opus_decoder_destroy(ac->decoder);
        goto BASE_CLEANUP;
    }

    ac->log = log;

    /* Initialize encoders with default values */
    ac->encoder = create_audio_encoder(log, 48000, 48000, 2);

    if (ac->encoder == NULL) {
        goto DECODER_CLEANUP;
    }

    ac->le_bit_rate = 48000;
    ac->le_sample_rate = 48000;
    ac->le_channel_count = 2;

    ac->ld_channel_count = 2;
    ac->ld_sample_rate = 48000;
    ac->ldrts = 0; /* Make it possible to reconfigure straight away */

    /* These need to be set in order to properly
     * do error correction with opus */
    ac->lp_frame_duration = 120;
    ac->lp_sampling_rate = 48000;
    ac->lp_channel_count = 1;

    ac->av = av;
    ac->friend_number = friend_number;
    ac->acb.first = cb;
    ac->acb.second = cb_data;

    return ac;

DECODER_CLEANUP:
    opus_decoder_destroy(ac->decoder);
    jbuf_free((struct JitterBuffer *)ac->j_buf);
BASE_CLEANUP:
    pthread_mutex_destroy(ac->queue_mutex);
    free(ac);
    return NULL;
}
Esempio n. 4
0
CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video)
{
    CSSession *cs = calloc(sizeof(CSSession), 1);

    if (!cs) {
        LOGGER_WARNING("Allocation failed! Application might misbehave!");
        return NULL;
    }

    if (create_recursive_mutex(cs->queue_mutex) != 0) {
        LOGGER_WARNING("Failed to create recursive mutex!");
        free(cs);
        return NULL;
    }

    if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
        LOGGER_WARNING("Jitter buffer creaton failed!");
        goto error;
    }

    cs->audio_encoder_bitrate        = cs_self->audio_bitrate;
    cs->audio_encoder_sample_rate    = cs_self->audio_sample_rate;
    cs->audio_encoder_channels       = cs_self->audio_channels;
    cs->audio_encoder_frame_duration = cs_self->audio_frame_duration;

    cs->audio_decoder_bitrate        = cs_peer->audio_bitrate;
    cs->audio_decoder_sample_rate    = cs_peer->audio_sample_rate;
    cs->audio_decoder_channels       = cs_peer->audio_channels;
    cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;


    cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0;
    cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0;

    if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error;

    if ((cs->support_video = has_video)) {
        cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
        cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;

        cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
                              cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0;
        cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0;

        if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error;

        if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;

        if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) )
            goto error;

        if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
    }

    return cs;

error:
    LOGGER_WARNING("Error initializing codec session! Application might misbehave!");

    pthread_mutex_destroy(cs->queue_mutex);

    if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);

    if ( cs->audio_decoder ) opus_decoder_destroy(cs->audio_decoder);


    if (has_video) {
        if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder);

        if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder);

        buffer_free(cs->vbuf_raw);

        free(cs->frame_buf);
        free(cs->split_video_frame);
    }

    jbuf_free(cs->j_buf);
    free(cs);

    return NULL;
}
Esempio n. 5
0
VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number,
                  toxav_video_receive_frame_cb *cb, void *cb_data)
{
    VCSession *vc = (VCSession *)calloc(sizeof(VCSession), 1);
    vpx_codec_err_t rc;

    if (!vc) {
        LOGGER_WARNING(log, "Allocation failed! Application might misbehave!");
        return nullptr;
    }

    if (create_recursive_mutex(vc->queue_mutex) != 0) {
        LOGGER_WARNING(log, "Failed to create recursive mutex!");
        free(vc);
        return nullptr;
    }

    int cpu_used_value = VP8E_SET_CPUUSED_VALUE;

    vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE);

    if (!vc->vbuf_raw) {
        goto BASE_CLEANUP;
    }

    /*
     * VPX_CODEC_USE_FRAME_THREADING
     *    Enable frame-based multi-threading
     *
     * VPX_CODEC_USE_ERROR_CONCEALMENT
     *    Conceal errors in decoded frames
     */
    vpx_codec_dec_cfg_t  dec_cfg;
    dec_cfg.threads = VPX_MAX_DECODER_THREADS; // Maximum number of threads to use
    dec_cfg.w = VIDEO_CODEC_DECODER_MAX_WIDTH;
    dec_cfg.h = VIDEO_CODEC_DECODER_MAX_HEIGHT;

    LOGGER_DEBUG(log, "Using VP8 codec for decoder (0)");
    rc = vpx_codec_dec_init(vc->decoder, video_codec_decoder_interface(), &dec_cfg,
                            VPX_CODEC_USE_FRAME_THREADING | VPX_CODEC_USE_POSTPROC);

    if (rc == VPX_CODEC_INCAPABLE) {
        LOGGER_WARNING(log, "Postproc not supported by this decoder (0)");
        rc = vpx_codec_dec_init(vc->decoder, video_codec_decoder_interface(), &dec_cfg, VPX_CODEC_USE_FRAME_THREADING);
    }

    if (rc != VPX_CODEC_OK) {
        LOGGER_ERROR(log, "Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
        goto BASE_CLEANUP;
    }

    if (VIDEO_VP8_DECODER_POST_PROCESSING_ENABLED == 1) {
        vp8_postproc_cfg_t pp = {VP8_DEBLOCK, 1, 0};
        vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp);

        if (cc_res != VPX_CODEC_OK) {
            LOGGER_WARNING(log, "Failed to turn on postproc");
        } else {
            LOGGER_DEBUG(log, "turn on postproc: OK");
        }
    } else {
        vp8_postproc_cfg_t pp = {0, 0, 0};
        vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp);

        if (cc_res != VPX_CODEC_OK) {
            LOGGER_WARNING(log, "Failed to turn OFF postproc");
        } else {
            LOGGER_DEBUG(log, "Disable postproc: OK");
        }
    }

    /* Set encoder to some initial values
     */
    vpx_codec_enc_cfg_t  cfg;
    vc_init_encoder_cfg(log, &cfg, 1);

    LOGGER_DEBUG(log, "Using VP8 codec for encoder (0.1)");
    rc = vpx_codec_enc_init(vc->encoder, video_codec_encoder_interface(), &cfg, VPX_CODEC_USE_FRAME_THREADING);

    if (rc != VPX_CODEC_OK) {
        LOGGER_ERROR(log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
        goto BASE_CLEANUP_1;
    }

    rc = vpx_codec_control(vc->encoder, VP8E_SET_CPUUSED, cpu_used_value);

    if (rc != VPX_CODEC_OK) {
        LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
        vpx_codec_destroy(vc->encoder);
        goto BASE_CLEANUP_1;
    }

    /*
    VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY,  unsigned int)
    control function to set noise sensitivity
      0: off, 1: OnYOnly, 2: OnYUV, 3: OnYUVAggressive, 4: Adaptive
    */
    /*
      rc = vpx_codec_control(vc->encoder, VP8E_SET_NOISE_SENSITIVITY, 2);

      if (rc != VPX_CODEC_OK) {
          LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
          vpx_codec_destroy(vc->encoder);
          goto BASE_CLEANUP_1;
      }
     */
    vc->linfts = current_time_monotonic(mono_time);
    vc->lcfd = 60;
    vc->vcb = cb;
    vc->vcb_user_data = cb_data;
    vc->friend_number = friend_number;
    vc->av = av;
    vc->log = log;
    return vc;
BASE_CLEANUP_1:
    vpx_codec_destroy(vc->decoder);
BASE_CLEANUP:
    pthread_mutex_destroy(vc->queue_mutex);
    rb_kill(vc->vbuf_raw);
    free(vc);
    return nullptr;
}
Esempio n. 6
0
bool call_prepare_transmission(ToxAVCall *call)
{
    /* Assumes mutex locked */

    if (call == NULL)
        return false;

    ToxAV *av = call->av;

    if (!av->acb.first && !av->vcb.first)
        /* It makes no sense to have CSession without callbacks */
        return false;

    if (call->active) {
        LOGGER_WARNING("Call already active!\n");
        return true;
    }

    if (create_recursive_mutex(call->mutex_audio) != 0)
        return false;

    if (create_recursive_mutex(call->mutex_video) != 0)
        goto FAILURE_3;

    if (create_recursive_mutex(call->mutex) != 0)
        goto FAILURE_2;

    /* Prepare bwc */
    call->bwc = bwc_new(av->m, call->friend_number, callback_bwc, call);

    { /* Prepare audio */
        call->audio.second = ac_new(av, call->friend_number, av->acb.first, av->acb.second);

        if (!call->audio.second) {
            LOGGER_ERROR("Failed to create audio codec session");
            goto FAILURE;
        }

        call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_number, call->bwc,
                                    call->audio.second, ac_queue_message);

        if (!call->audio.first) {
            LOGGER_ERROR("Failed to create audio rtp session");;
            goto FAILURE;
        }
    }
    { /* Prepare video */
        call->video.second = vc_new(av, call->friend_number, av->vcb.first, av->vcb.second);

        if (!call->video.second) {
            LOGGER_ERROR("Failed to create video codec session");
            goto FAILURE;
        }

        call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_number, call->bwc,
                                    call->video.second, vc_queue_message);

        if (!call->video.first) {
            LOGGER_ERROR("Failed to create video rtp session");
            goto FAILURE;
        }
    }

    call->active = 1;
    return true;

FAILURE:
    bwc_kill(call->bwc);
    rtp_kill(call->audio.first);
    ac_kill(call->audio.second);
    call->audio.first = NULL;
    call->audio.second = NULL;
    rtp_kill(call->video.first);
    vc_kill(call->video.second);
    call->video.first = NULL;
    call->video.second = NULL;
    pthread_mutex_destroy(call->mutex);
FAILURE_2:
    pthread_mutex_destroy(call->mutex_video);
FAILURE_3:
    pthread_mutex_destroy(call->mutex_audio);
    return false;
}