int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self){ if(!self || !*self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_list_lock(__audioUnitInstances); if(tsk_object_get_refcount(*self)==1){ tsk_list_remove_item_by_data(__audioUnitInstances, *self); } else { tsk_object_unref(*self); } tsk_list_unlock(__audioUnitInstances); *self = tsk_null; return 0; }
const tnet_ice_candidate_t* tnet_ice_candidate_find_by_fd(tnet_ice_candidates_L_t* candidates, tnet_fd_t fd) { if(candidates){ const tsk_list_item_t *item; const tnet_ice_candidate_t* candidate; tsk_list_lock(candidates); tsk_list_foreach(item, candidates){ if(!(candidate = item->data)){ continue; } if(candidate->socket && (candidate->socket->fd == fd)){ tsk_list_unlock(candidates); return candidate; } } } return tsk_null; }
int tdav_video_jb_put(tdav_video_jb_t* self, trtp_rtp_packet_t* rtp_pkt) { #if TDAV_VIDEO_JB_DISABLE self->cb_data_rtp.rtp.pkt = rtp_pkt; self->callback(&self->cb_data_rtp); #else const tdav_video_frame_t* old_frame; tsk_bool_t pt_matched = tsk_false, is_frame_late_or_dup = tsk_false, is_restarted = tsk_false; uint16_t* seq_num; if(!self || !rtp_pkt || !rtp_pkt->header){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!self->started){ TSK_DEBUG_INFO("Video jitter buffer not started"); return 0; } seq_num = &self->seq_nums[rtp_pkt->header->payload_type]; tsk_safeobj_lock(self); //TSK_DEBUG_INFO("receive seqnum=%u", rtp_pkt->header->seq_num); if(self->decode_last_timestamp && (self->decode_last_timestamp > rtp_pkt->header->timestamp)){ if((self->decode_last_timestamp - rtp_pkt->header->timestamp) < TDAV_VIDEO_JB_MAX_DROPOUT){ TSK_DEBUG_INFO("--------Frame already Decoded [seqnum=%u]------------", rtp_pkt->header->seq_num); tsk_safeobj_unlock(self); return 0; } } old_frame = _tdav_video_jb_get_frame(self, rtp_pkt->header->timestamp, rtp_pkt->header->payload_type, &pt_matched); if((*seq_num && *seq_num != 0xFFFF) && (*seq_num + 1) != rtp_pkt->header->seq_num){ int32_t diff = ((int32_t)rtp_pkt->header->seq_num - (int32_t)*seq_num); tsk_bool_t is_frame_loss = (diff > 0); is_restarted = (TSK_ABS(diff) > TDAV_VIDEO_JB_MAX_DROPOUT); is_frame_late_or_dup = !is_frame_loss; tdav_video_jb_reset_fps_prob(self); TSK_DEBUG_INFO("Packet %s (from JB) [%hu - %hu]", is_frame_loss ? "loss" : "late/duplicated/nack", *seq_num, rtp_pkt->header->seq_num); if(is_frame_loss && !is_restarted){ if(self->callback){ self->cb_data_any.type = tdav_video_jb_cb_data_type_fl; self->cb_data_any.ssrc = rtp_pkt->header->ssrc; self->cb_data_any.fl.seq_num = (*seq_num + 1); self->cb_data_any.fl.count = diff - 1; self->callback(&self->cb_data_any); } } } if(!old_frame){ tdav_video_frame_t* new_frame; if(pt_matched){ // if we have a frame with the same payload type but without this timestamp this means that we moved to a new frame // this happens if the frame is waiting to be decoded or the marker is lost } if((new_frame = tdav_video_frame_create(rtp_pkt))){ // compute avg frame duration if(self->last_timestamp && self->last_timestamp < rtp_pkt->header->timestamp){ uint32_t duration = (rtp_pkt->header->timestamp - self->last_timestamp)/self->rate; self->avg_duration = self->avg_duration ? ((self->avg_duration + duration) >> 1) : duration; --self->fps_prob; } self->last_timestamp = rtp_pkt->header->timestamp; tsk_list_lock(self->frames); if(self->frames_count >= self->tail_max){ if(++self->conseq_frame_drop >= self->tail_max){ TSK_DEBUG_ERROR("Too many frames dropped and fps=%d", self->fps); tsk_list_clear_items(self->frames); self->conseq_frame_drop = 0; self->frames_count = 1; if(self->callback){ self->cb_data_any.type = tdav_video_jb_cb_data_type_tmfr; self->cb_data_any.ssrc = rtp_pkt->header->ssrc; self->callback(&self->cb_data_any); } } else{ TSK_DEBUG_INFO("Dropping video frame because frames_count(%lld)>=tail_max(%d)", self->frames_count, self->tail_max); tsk_list_remove_first_item(self->frames); } tdav_video_jb_reset_fps_prob(self); } else{ ++self->frames_count; } tsk_list_push_ascending_data(self->frames, (void**)&new_frame); tsk_list_unlock(self->frames); }
tdav_audiounit_handle_t* tdav_audiounit_handle_create(uint64_t session_id) { tdav_audiounit_instance_t* inst = tsk_null; // create audio unit component if(!__audioSystem){ AudioComponentDescription audioDescription; audioDescription.componentType = kAudioUnitType_Output; audioDescription.componentSubType = kDoubangoAudioUnitSubType; audioDescription.componentManufacturer = kAudioUnitManufacturer_Apple; audioDescription.componentFlags = 0; audioDescription.componentFlagsMask = 0; if((__audioSystem = AudioComponentFindNext(NULL, &audioDescription))){ // leave blank } else { TSK_DEBUG_ERROR("Failed to find new audio component"); goto done; } } // create list used to hold instances if(!__audioUnitInstances && !(__audioUnitInstances = tsk_list_create())){ TSK_DEBUG_ERROR("Failed to create new list"); goto done; } //= lock the list tsk_list_lock(__audioUnitInstances); // For iOS we are using full-duplex AudioUnit and to keep it unique for both // the consumer and producer we use the session id. #if TARGET_OS_IPHONE // find the instance from the list const tsk_list_item_t* item; tsk_list_foreach(item,__audioUnitInstances){ if(((tdav_audiounit_instance_t*)item->data)->session_id == session_id){ inst = tsk_object_ref(item->data); goto done; } } #endif // create instance object and put it into the list if((inst = tsk_object_new(tdav_audiounit_instance_def_t))){ OSStatus status = noErr; tdav_audiounit_instance_t* _inst; // create new instance if((status= AudioComponentInstanceNew(__audioSystem, &inst->audioUnit)) != noErr){ TSK_DEBUG_ERROR("AudioComponentInstanceNew() failed with status=%ld", (signed long)status); TSK_OBJECT_SAFE_FREE(inst); goto done; } _inst = inst, _inst->session_id = session_id; tsk_list_push_back_data(__audioUnitInstances, (void**)&_inst); } done: //= unlock the list tsk_list_unlock(__audioUnitInstances); return (tdav_audiounit_handle_t*)inst; }