diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 261ea97502..581b2cbe43 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1283,6 +1283,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(_In_ switch SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(_In_ switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(switch_core_session_t *session, + switch_frame_t *frame, switch_io_flag_t flags, int stream_id); + SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp); SWITCH_DECLARE(switch_status_t) switch_core_session_set_write_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp); SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_read_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp); diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index ef9869f95f..51f4dd6ffe 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -143,6 +143,9 @@ SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t *img, unsigned int w, unsigned int h); + +SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y); + /*!\brief Copy image to a new image * * if new_img is NULL, a new image is allocated diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 7535ac27de..80ddd0886c 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -353,6 +353,7 @@ typedef struct mcu_layer_s { mcu_layer_geometry_t geometry; int member_id; switch_image_t *img; + switch_image_t *cur_img; } mcu_layer_t; typedef struct bgcolor_yuv_s @@ -584,6 +585,8 @@ struct conference_member { al_handle_t *al; int last_speech_channels; int video_layer_id; + int video_codec_index; + int video_codec_id; }; typedef enum { @@ -893,36 +896,6 @@ static void set_bgcolor(bgcolor_yuv_t *bgcolor, char *bgcolor_str) bgcolor->v = v; } -// simple implementation to patch a small img to a big IMG at position x,y -static void patch_image(switch_image_t *IMG, switch_image_t *img, int x, int y) -{ - int i, j, k; - int W = IMG->d_w; - int H = IMG->d_h; - int w = img->d_w; - int h = img->d_h; - - switch_assert(img->fmt == SWITCH_IMG_FMT_I420); - switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420); - - for (i = y; i < (y + h) && i < H; i++) { - for (j = x; j < (x + w) && j < W; j++) { - IMG->planes[0][i * IMG->stride[0] + j] = img->planes[0][(i - y) * img->stride[0] + (j - x)]; - } - } - - for (i = y; i < (y + h) && i < H; i+=4) { - for (j = x; j < (x + w) && j < W; j+=4) { - for (k = 1; k <= 2; k++) { - IMG->planes[k][i/2 * IMG->stride[k] + j/2] = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2]; - IMG->planes[k][i/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2 + 1]; - IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2]; - IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2 + 1]; - } - } - } -} - #define SCALE_FACTOR 360 static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) @@ -947,13 +920,17 @@ static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) switch_assert(layer->img); reset_image(layer->img, &canvas->bgcolor); - patch_image(canvas->img, layer->img, x, y); + switch_img_patch(canvas->img, layer->img, x, y); + switch_img_free(&layer->cur_img); + } -static void scale_and_patch(switch_image_t *IMG, switch_image_t *img, mcu_layer_t *layer) +static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer) { int ret; int x = 0, y = 0; + switch_image_t *IMG = conference->canvas->img, *img = layer->cur_img; + if (layer->geometry.scale) { int screen_w = 0, screen_h = 0, img_w = 0, img_h = 0; @@ -1014,11 +991,11 @@ static void scale_and_patch(switch_image_t *IMG, switch_image_t *img, mcu_layer_ if (ret != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret); } else { - patch_image(IMG, layer->img, x, y); + switch_img_patch(IMG, layer->img, x, y); } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "insert at %d,%d\n", x, y); - patch_image(IMG, img, x, y); + switch_img_patch(IMG, img, x, y); } } @@ -1053,9 +1030,7 @@ static void init_canvas(conference_obj_t *conference, layout_node_t *lnode) switch_mutex_init(&conference->canvas->cond2_mutex, SWITCH_MUTEX_NESTED, conference->pool); } - if (conference->canvas->img) { - switch_img_free(&conference->canvas->img); - } + switch_img_free(&conference->canvas->img); conference->canvas->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvas_width, conference->canvas_height, 0); @@ -1070,9 +1045,7 @@ static void destroy_canvas(mcu_canvas_t **canvasP) { int i; mcu_canvas_t *canvas = *canvasP; - if (canvas->img) { - switch_img_free(&canvas->img); - } + switch_img_free(&canvas->img); for (i = 0; i < MCU_MAX_LAYERS; i++) { switch_img_free(&canvas->layers[i].img); @@ -1081,22 +1054,112 @@ static void destroy_canvas(mcu_canvas_t **canvasP) { *canvasP = NULL; } +typedef struct codec_set_s { + switch_codec_t codec; + switch_frame_t frame; + uint8_t *packet; +} codec_set_t; + +static void write_canvas_image_to_codec_group(conference_obj_t *conference, codec_set_t *codec_set, + int codec_index, uint32_t timestamp, switch_bool_t need_refresh, switch_bool_t need_keyframe) + +{ + conference_member_t *imember; + switch_frame_t write_frame = { 0 }, *frame = NULL; + switch_status_t encode_status = SWITCH_STATUS_FALSE; + + write_frame = codec_set->frame; + frame = &write_frame; + frame->img = codec_set->frame.img; + frame->packet = codec_set->frame.packet; + + switch_clear_flag(frame, SFF_SAME_IMAGE); + frame->m = 0; + frame->timestamp = timestamp; + + if (need_refresh || need_keyframe) { + switch_core_codec_control(&codec_set->codec, SCC_VIDEO_REFRESH, SCCT_NONE, NULL, NULL, NULL); + } + + do { + + frame->data = ((unsigned char *)frame->packet) + 12; + frame->datalen = SWITCH_DEFAULT_VIDEO_SIZE; + + encode_status = switch_core_codec_encode_video(&codec_set->codec, frame); + + if (encode_status == SWITCH_STATUS_SUCCESS || encode_status == SWITCH_STATUS_MORE_DATA) { + + switch_assert((encode_status == SWITCH_STATUS_SUCCESS && frame->m) || !frame->m); + + switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME); + frame->packetlen = frame->datalen + 12; + + switch_mutex_lock(conference->member_mutex); + for (imember = conference->members; imember; imember = imember->next) { + switch_channel_t *ichannel = switch_core_session_get_channel(imember->session); + + if (imember->video_codec_index != codec_index) { + continue; + } + + if (!imember->session || !switch_channel_test_flag(ichannel, CF_VIDEO) || + switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } + + if (need_refresh) { + switch_core_session_request_video_refresh(imember->session); + } + + switch_core_session_write_encoded_video_frame(imember->session, frame, 0, 0); + + switch_core_session_rwunlock(imember->session); + } + switch_mutex_unlock(conference->member_mutex); + } + + } while(encode_status == SWITCH_STATUS_MORE_DATA); +} + +#define MAX_MUX_CODECS 10 +//#define TRACK_FPS + static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj) { conference_obj_t *conference = (conference_obj_t *) obj; conference_member_t *imember; - switch_frame_t write_frame = { 0 }; - uint8_t *packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE); layout_node_t *lnode = switch_core_hash_find(conference->layout_hash, conference->video_layout_name); + switch_codec_t *check_codec = NULL; + codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 }; + int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2; + switch_timer_t timer = { 0 }; + int i = 0; + int used = 0, remaining = 0; + uint32_t video_key_freq = 10000000; + switch_time_t last_key_time = 0; + mcu_layer_t *layer = NULL; +#ifdef TRACK_FPS + uint64_t frames = 0; + switch_time_t started = switch_micro_time_now(); +#endif switch_assert(lnode); init_canvas(conference, lnode); + switch_core_timer_init(&timer, "soft", 1, 90, conference->pool); + switch_mutex_lock(conference->canvas->cond_mutex); while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT) && switch_test_flag(conference, CFLAG_VIDEO_MUXING)) { + switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE; + + top: + switch_mutex_lock(conference->member_mutex); + remaining = 0; + used = 0; for (imember = conference->members; imember; imember = imember->next) { switch_channel_t *ichannel = switch_core_session_get_channel(imember->session); @@ -1109,25 +1172,73 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread continue; } + + if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) { + switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ); + need_refresh = SWITCH_TRUE; + } + + if (imember->video_codec_index < 0 && (check_codec = switch_core_session_get_video_write_codec(imember->session))) { + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + if (check_codec->implementation->codec_id == write_codecs[i]->codec.implementation->codec_id) { + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + break; + } + } + + if (imember->video_codec_index < 0) { + write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t)); + + if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, conference->pool) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i); + + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + + write_codecs[i]->frame.packet = switch_core_alloc(conference->pool, buflen); + write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12; + write_codecs[i]->frame.packetlen = 0; + write_codecs[i]->frame.buflen = buflen - 12; + switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP); + + } + } + } + + if (imember->video_codec_index < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Codec Error\n"); + continue; + } + + img = NULL; + size = 0; + do { - if (switch_queue_trypop(imember->video_queue, &pop) == SWITCH_STATUS_SUCCESS) { - if (img) switch_img_free(&img); + if (switch_queue_trypop(imember->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { + switch_img_free(&img); img = (switch_image_t *)pop; + //remaining += switch_queue_size(imember->video_queue); + //break; } else { break; } size = switch_queue_size(imember->video_queue); - } while(size > 1); + } while(size > 0); if (img) { - mcu_layer_t *layer = NULL; int i; + layer = NULL; + used++; + switch_mutex_lock(conference->canvas->mutex); if (imember->video_layer_id > -1) { if (imember->video_layer_id >= conference->canvas->total_layers) { conference->canvas->layers[imember->video_layer_id].member_id = 0; + reset_layer(conference->canvas, &conference->canvas->layers[imember->video_layer_id]); imember->video_layer_id = -1; conference->canvas->layers_used--; } else { @@ -1148,12 +1259,15 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } switch_mutex_unlock(conference->canvas->mutex); + if (layer) { - scale_and_patch(conference->canvas->img, img, layer); + switch_img_free(&layer->cur_img); + layer->cur_img = img; + scale_and_patch(conference, layer); } - switch_img_free(&img); + } if (imember->session) { @@ -1161,39 +1275,53 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } - for (imember = conference->members; imember; imember = imember->next) { - switch_channel_t *ichannel = switch_core_session_get_channel(imember->session); - - if (!imember->session || !switch_channel_test_flag(ichannel, CF_VIDEO) || - switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { - continue; - } - - switch_set_flag(&write_frame, SFF_RAW_RTP); - write_frame.img = conference->canvas->img; - write_frame.packet = packet; - write_frame.data = packet + 12; - write_frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12; - write_frame.buflen = write_frame.datalen; - write_frame.packetlen = SWITCH_RECOMMENDED_BUFFER_SIZE; - - switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0); - - if (imember->session) { - switch_core_session_rwunlock(imember->session); - } - } - switch_mutex_unlock(conference->member_mutex); + if (remaining) goto top; + + if (used) { + switch_time_t now = switch_micro_time_now(); + +#ifdef TRACK_FPS + uint64_t diff = ((now - started) / 1000000); + + if (!diff) diff = 1; + frames++; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "foo %ld %ld %ld\n", frames, diff, frames / diff); +#endif + + if (video_key_freq && (now - last_key_time) > video_key_freq) { + need_keyframe = SWITCH_TRUE; + last_key_time = now; + } + + + switch_core_timer_sync(&timer); + + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + write_codecs[i]->frame.img = conference->canvas->img; + write_canvas_image_to_codec_group(conference, write_codecs[i], i, timer.samplecount, need_refresh, need_keyframe); + } + } + switch_mutex_lock(conference->canvas->cond2_mutex); switch_thread_cond_wait(conference->canvas->cond, conference->canvas->cond_mutex); switch_mutex_unlock(conference->canvas->cond2_mutex); - } switch_mutex_unlock(conference->canvas->cond_mutex); + for (i = 0; i < MCU_MAX_LAYERS; i++) { + layer = &conference->canvas->layers[i]; + + switch_img_free(&layer->cur_img); + switch_img_free(&layer->img); + } + + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + switch_core_codec_destroy(&write_codecs[i]->codec); + } + destroy_canvas(&conference->canvas); return NULL; @@ -2862,6 +2990,8 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe member->score_iir = 0; member->verbose_events = conference->verbose_events; member->video_layer_id = -1; + member->video_codec_index = -1; + switch_queue_create(&member->dtmf_queue, 100, member->pool); if (conference->video_layout_name) { switch_queue_create(&member->video_queue, 2000, member->pool); @@ -7288,8 +7418,10 @@ static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, swi return SWITCH_STATUS_SUCCESS; } - reset_image(conference->canvas->img, &conference->canvas->bgcolor); + switch_mutex_lock(conference->member_mutex); init_canvas_layers(conference, lnode); + reset_image(conference->canvas->img, &conference->canvas->bgcolor); + switch_mutex_unlock(conference->member_mutex); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 7be5edcad4..a807c4c777 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -7319,8 +7319,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } /* DFF nack pli etc */ - //nack = v_engine->nack = 0; - //pli = v_engine->pli = 0; + nack = v_engine->nack = 0; + pli = v_engine->pli = 0; for (pmap = v_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) { @@ -8130,7 +8130,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se if (v_engine->rtp_session) { if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PLI)) { switch_rtp_video_loss(v_engine->rtp_session); - } else if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) { + } + + if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) { switch_rtp_video_refresh(v_engine->rtp_session); } } @@ -9744,6 +9746,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess smh->last_codec_refresh = now; } + + switch_channel_set_flag(session->channel, CF_VIDEO_REFRESH_REQ); return switch_core_codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data); } @@ -9751,7 +9755,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess } -static switch_status_t raw_write_video(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(switch_core_session_t *session, + switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { switch_io_event_hook_video_write_frame_t *ptr; switch_status_t status = SWITCH_STATUS_FALSE; @@ -9835,7 +9840,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor } if (!img) { - return raw_write_video(session, frame, flags, stream_id); + return switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id); } write_frame = *frame; @@ -9849,7 +9854,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor if (!smh->video_timer.timer_interface) { switch_core_timer_init(&smh->video_timer, "soft", 1, 90, switch_core_session_get_pool(session)); } - + switch_core_timer_sync(&smh->video_timer); timer = &smh->video_timer; } @@ -9873,7 +9878,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor } switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME); - status = raw_write_video(session, frame, flags, stream_id); + status = switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id); } } while(status == SWITCH_STATUS_SUCCESS && encode_status == SWITCH_STATUS_MORE_DATA); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index d4ffe5120f..2e90ae73a3 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -72,9 +72,41 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img) } } +// simple implementation to patch a small img to a big IMG at position x,y +SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y) +{ + int i, j, k; + int W = IMG->d_w; + int H = IMG->d_h; + int w = img->d_w; + int h = img->d_h; + + switch_assert(img->fmt == SWITCH_IMG_FMT_I420); + switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420); + + for (i = y; i < (y + h) && i < H; i++) { + for (j = x; j < (x + w) && j < W; j++) { + IMG->planes[0][i * IMG->stride[0] + j] = img->planes[0][(i - y) * img->stride[0] + (j - x)]; + } + } + + for (i = y; i < (y + h) && i < H; i+=4) { + for (j = x; j < (x + w) && j < W; j+=4) { + for (k = 1; k <= 2; k++) { + IMG->planes[k][i/2 * IMG->stride[k] + j/2] = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2]; + IMG->planes[k][i/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2 + 1]; + IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2]; + IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2 + 1]; + } + } + } +} + + + SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img) { - int i; + int i = 0; switch_assert(img); switch_assert(new_img); @@ -101,6 +133,7 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i memcpy((*new_img)->planes[SWITCH_PLANE_U] + (*new_img)->stride[SWITCH_PLANE_U] * i, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i, img->d_w / 2); memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w /2); } + } /* For Emacs: diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 471d84b6c0..b9db435eae 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -5242,6 +5242,7 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack) switch_size_t bytes = 0; rtp_msg_t send_msg[1] = {{{0}}}; uint16_t seq = (uint16_t) (nack & 0xFFFF); + uint16_t blp = (uint16_t) (nack >> 16); int i; const char *tx_host = NULL; const char *old_host = NULL; @@ -5278,10 +5279,11 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Cannot send NACK for seq %u\n", ntohs(seq)); } + blp = ntohs(blp); for (i = 0; i < 16; i++) { - if ((nack & (1 << (16 + i)))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Also Got NACK for seq %u\n", ntohs(seq) + i); - if (switch_vb_get_packet_by_seq(rtp_session->vbw, htons(ntohs(seq) + i), (switch_rtp_packet_t *) &send_msg, &bytes) == SWITCH_STATUS_SUCCESS) { + if (blp & (1 << i)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Also Got NACK for seq %u\n", ntohs(seq) + i + 1); + if (switch_vb_get_packet_by_seq(rtp_session->vbw, htons(ntohs(seq) + i + 1), (switch_rtp_packet_t *) &send_msg, &bytes) == SWITCH_STATUS_SUCCESS) { if (rtp_session->flags[SWITCH_RTP_FLAG_DEBUG_RTP_WRITE]) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(rtp_session->session), SWITCH_LOG_CONSOLE, "X %s b=%4ld %s:%u %s:%u %s:%u pt=%d ts=%u seq=%u m=%d\n", diff --git a/src/switch_vidderbuffer.c b/src/switch_vidderbuffer.c index 1c6ffb86eb..9553ded9ab 100644 --- a/src/switch_vidderbuffer.c +++ b/src/switch_vidderbuffer.c @@ -383,6 +383,7 @@ SWITCH_DECLARE(uint32_t) switch_vb_pop_nack(switch_vb_t *vb) { switch_hash_index_t *hi = NULL; uint32_t nack = 0; + uint16_t blp = 0; uint16_t least = 0; int i = 0; @@ -405,15 +406,18 @@ SWITCH_DECLARE(uint32_t) switch_vb_pop_nack(switch_vb_t *vb) if (least && switch_core_inthash_delete(vb->missing_seq_hash, (uint32_t)htons(least))) { vb_debug(vb, 3, "Found smallest NACKABLE seq %u\n", least); nack = (uint32_t) htons(least); - - for (i = 1; i > 17; i++) { + + for(i = 0; i < 16; i++) { if (switch_core_inthash_delete(vb->missing_seq_hash, (uint32_t)htons(least + i))) { - vb_debug(vb, 3, "Found addtl NACKABLE seq %u\n", least + i); - nack |= (1 << (16 + i)); + vb_debug(vb, 3, "Found addtl NACKABLE seq %u\n", least + i + 1); + blp |= (1 << i); } else { break; } } + + blp = htons(blp); + nack |= (uint32_t) blp << 16; } switch_mutex_unlock(vb->mutex);