PJ_DEF(int) session_info_buildSoftNackList(Session_Info *session_info, int *seq_num_list, int seq_num_list_len, pj_uint32_t rtt_ms) { if(seq_num_list_len == 0) return 0; int empty_low_seq_num = session_info->empty_low_seq_num; int empty_high_seq_num = session_info->empty_high_seq_num; //clear empty packets if(empty_low_seq_num != -1) ClearEmptyPackets(session_info, seq_num_list, seq_num_list_len); JTPacket *packet = session_info->packetList.next; printf("check if has packets in session\n"); if(packet == &session_info->packetList ) //empty return 0; int media_seq_num_low, media_seq_num_high; pj_bool_t session_nacked = PJ_TRUE; //if not key frame and previous frame lost, don't retransmit if(session_info->previous_frame_loss && !session_info->isKeyFrame) { session_nacked = PJ_FALSE; } //if (now + rtt) > (ts + FRAME_MAX_DELAY), don't retransmit //use ntp time, but ts in rtp is not ntp time in current, so substitute received time for ts //if (now + rtt * 1.5) > (received + FRAME_MAX_DELAY), don't retransmit if(session_info->frame_type != PJMEDIA_FRAME_TYPE_NONE && session_info->frame_type != PJMEDIA_FRAME_TYPE_EMPTY) { //has media packets pj_timestamp now, received; pj_get_timestamp(&now); pj_add_timestamp32(&now, rtt_ms * 1000 * 3 / 2); memcpy(&received, &session_info->oldest_media_packet, sizeof(pj_timestamp)); pj_add_timestamp32(&received, FRAME_MAX_DELAY * 1000); if(pj_cmp_timestamp(&now, &received) > 0) { session_nacked = PJ_FALSE; } } if(!session_nacked) { media_seq_num_low = session_info->packetList.next->isFirst? session_info->packetList.next->seq: session_info->packetList.next->seq - 1; media_seq_num_high = session_info->packetList.prev->isMarket? session_info->packetList.prev->seq: session_info->packetList.prev->seq + 1; ClearPackets(seq_num_list, seq_num_list_len, media_seq_num_low, media_seq_num_high, -1); return 0; } return session_info_buildHardNackList(session_info, seq_num_list, seq_num_list_len); }
pjmedia_clock_src_get_current_timestamp( const pjmedia_clock_src *clocksrc, pj_timestamp *timestamp) { pj_timestamp now; unsigned elapsed_ms; PJ_ASSERT_RETURN(clocksrc && timestamp, PJ_EINVAL); pj_get_timestamp(&now); elapsed_ms = pj_elapsed_msec(&clocksrc->last_update, &now); pj_memcpy(timestamp, &clocksrc->timestamp, sizeof(pj_timestamp)); pj_add_timestamp32(timestamp, elapsed_ms * clocksrc->clock_rate / 1000); return PJ_SUCCESS; }
PJ_DEF(Frame_Buffer *) jitter_buffer_getCompleteFrameForDecoding(Jitter_Buffer *jitter_buffer, pj_uint32_t max_wait_time_ms) { //running if(!jitter_buffer->running) return NULL; if(pj_mutex_lock(jitter_buffer->jb_mutex) != PJ_SUCCESS) { //error return NULL; } /*{ char buf[1024]; getFrameInfo(&jitter_buffer->frameList, &jitter_buffer->decode_state, buf, 1024); PJ_LOG(4, (THIS_FILE, "jb status:\n%s\n", buf)); }*/ //the first frame must be a key frame if(jitter_buffer->decode_state.inited == PJ_FALSE) jitter_buffer->waiting_for_key_frame == PJ_TRUE; //clean old frames CleanOldFrames(jitter_buffer); //get complete , continuous frame Frame_Buffer * frame = findOldestCompleteContinuousFrame(jitter_buffer); //if not got, try to wait a frame if(frame == NULL) { if(max_wait_time_ms == 0) goto ON_RET; pj_timestamp current ; pj_get_timestamp(¤t); pj_timestamp end = current; pj_add_timestamp32(&end, max_wait_time_ms); pj_int32_t wait_time_ms = max_wait_time_ms; event_reset(jitter_buffer->packet_event); while(wait_time_ms > 0) { pj_mutex_unlock(jitter_buffer->jb_mutex); if(event_wait(jitter_buffer->packet_event, wait_time_ms) == WAIT_RET_SIGNAL) { //incoming a packet pj_mutex_lock(jitter_buffer->jb_mutex); if(!jitter_buffer->running) //jitter buffer stoped goto ON_RET; CleanOldFrames(jitter_buffer); frame = findOldestCompleteContinuousFrame(jitter_buffer); if(frame != NULL) break; pj_get_timestamp(¤t); int elapsed_msec = pj_elapsed_msec(¤t, &end); wait_time_ms = elapsed_msec; } else { pj_mutex_lock(jitter_buffer->jb_mutex); //error or timeout break; } } } else event_reset(jitter_buffer->packet_event); if(frame == NULL) goto ON_RET; /*if(jitter_buffer->waiting_for_key_frame && !frame->session_info.isKeyFrame) { frame = NULL; //not a key frame goto ON_RET; }*/ //got one, update jitter if(frame->nack_count > 0) { jitter_estimator_frameNacked(&jitter_buffer->jitter_estimator); //nacked } else { //update jitter estimator UpdateJitterEstimatorForFrame(jitter_buffer, frame); } //set frame status frame_buffer_setStatus(frame, FRAME_STATUS_DECODING); //update decode state decode_state_updateFrame(frame, &jitter_buffer->decode_state); //waiting for key frame if(frame->session_info.isKeyFrame) jitter_buffer->waiting_for_key_frame = PJ_FALSE; //clean old frames CleanOldFrames(jitter_buffer); //return frame ON_RET: pj_mutex_unlock(jitter_buffer->jb_mutex); return frame; }