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; }
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; }
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; }
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; }
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; }
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; }