1 /* $Id$ */
2 /*
3 * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include <pjmedia/vid_stream.h>
20 #include <pjmedia/errno.h>
21 #include <pjmedia/event.h>
22 #include <pjmedia/jbuf.h>
23 #include <pjmedia/rtp.h>
24 #include <pjmedia/rtcp.h>
25 #include <pjmedia/rtcp_fb.h>
26 #include <pj/array.h>
27 #include <pj/assert.h>
28 #include <pj/compat/socket.h>
29 #include <pj/errno.h>
30 #include <pj/ioqueue.h>
31 #include <pj/log.h>
32 #include <pj/os.h>
33 #include <pj/pool.h>
34 #include <pj/rand.h>
35 #include <pj/sock_select.h>
36 #include <pj/string.h> /* memcpy() */
37
38
39 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
40
41
42 #define THIS_FILE "vid_stream.c"
43 #define ERRLEVEL 1
44 #define LOGERR_(expr) PJ_PERROR(4,expr)
45 #define TRC_(expr) PJ_LOG(5,expr)
46 #define SIGNATURE PJMEDIA_SIG_PORT_VID_STREAM
47
48 #define TRACE_RC 0
49
50 /* Tracing jitter buffer operations in a stream session to a CSV file.
51 * The trace will contain JB operation timestamp, frame info, RTP info, and
52 * the JB state right after the operation.
53 */
54 #define TRACE_JB 0 /* Enable/disable trace. */
55 #define TRACE_JB_PATH_PREFIX "" /* Optional path/prefix
56 for the CSV filename. */
57 #if TRACE_JB
58 # include <pj/file_io.h>
59 # define TRACE_JB_INVALID_FD ((pj_oshandle_t)-1)
60 # define TRACE_JB_OPENED(s) (s->trace_jb_fd != TRACE_JB_INVALID_FD)
61 #endif
62
63 #ifndef PJMEDIA_VSTREAM_SIZE
64 # define PJMEDIA_VSTREAM_SIZE 1000
65 #endif
66
67 #ifndef PJMEDIA_VSTREAM_INC
68 # define PJMEDIA_VSTREAM_INC 1000
69 #endif
70
71 /* Due to network MTU limitation, a picture bitstream may be splitted into
72 * several chunks for RTP delivery. The chunk number may vary depend on the
73 * picture resolution and MTU. This constant specifies the minimum chunk
74 * number to be allocated to store a picture bitstream in decoding direction.
75 */
76 #define MIN_CHUNKS_PER_FRM 30
77
78 /* Number of send error before repeat the report. */
79 #define SEND_ERR_COUNT_TO_REPORT 50
80
81 /**
82 * Media channel.
83 */
84 typedef struct pjmedia_vid_channel
85 {
86 pjmedia_vid_stream *stream; /**< Parent stream. */
87 pjmedia_dir dir; /**< Channel direction. */
88 pjmedia_port port; /**< Port interface. */
89 unsigned pt; /**< Payload type. */
90 pj_bool_t paused; /**< Paused?. */
91 void *buf; /**< Output buffer. */
92 unsigned buf_size; /**< Size of output buffer. */
93 pjmedia_rtp_session rtp; /**< RTP session. */
94 } pjmedia_vid_channel;
95
96
97 /**
98 * This structure describes media stream.
99 * A media stream is bidirectional media transmission between two endpoints.
100 * It consists of two channels, i.e. encoding and decoding channels.
101 * A media stream corresponds to a single "m=" line in a SDP session
102 * description.
103 */
104 struct pjmedia_vid_stream
105 {
106 pj_pool_t *own_pool; /**< Internal pool. */
107 pjmedia_endpt *endpt; /**< Media endpoint. */
108 pjmedia_vid_codec_mgr *codec_mgr; /**< Codec manager. */
109 pjmedia_vid_stream_info info; /**< Stream info. */
110
111 pjmedia_vid_channel *enc; /**< Encoding channel. */
112 pjmedia_vid_channel *dec; /**< Decoding channel. */
113
114 pjmedia_dir dir; /**< Stream direction. */
115 void *user_data; /**< User data. */
116 pj_str_t name; /**< Stream name */
117 pj_str_t cname; /**< SDES CNAME */
118
119 pjmedia_transport *transport; /**< Stream transport. */
120
121 pj_mutex_t *jb_mutex;
122 pjmedia_jbuf *jb; /**< Jitter buffer. */
123 char jb_last_frm; /**< Last frame type from jb */
124 unsigned jb_last_frm_cnt;/**< Last JB frame type counter*/
125
126 pjmedia_rtcp_session rtcp; /**< RTCP for incoming RTP. */
127 pj_timestamp rtcp_last_tx; /**< Last RTCP tx time. */
128 pj_timestamp rtcp_fb_last_tx;/**< Last RTCP-FB tx time. */
129 pj_uint32_t rtcp_interval; /**< Interval, in msec. */
130 pj_bool_t initial_rr; /**< Initial RTCP RR sent */
131 pj_bool_t rtcp_sdes_bye_disabled;/**< Send RTCP SDES/BYE?*/
132 void *out_rtcp_pkt; /**< Outgoing RTCP packet. */
133 unsigned out_rtcp_pkt_size;
134 /**< Outgoing RTCP packet size. */
135
136 unsigned dec_max_size; /**< Size of decoded/raw picture*/
137 pjmedia_ratio dec_max_fps; /**< Max fps of decoding dir. */
138 pjmedia_frame dec_frame; /**< Current decoded frame. */
139 unsigned dec_delay_cnt; /**< Decoding delay (in frames).*/
140 pjmedia_event fmt_event; /**< Buffered fmt_changed event
141 to avoid deadlock */
142 pjmedia_event miss_keyframe_event;
143 /**< Buffered missing keyframe
144 event for delayed republish*/
145
146 unsigned frame_size; /**< Size of encoded base frame.*/
147 unsigned frame_ts_len; /**< Frame length in timestamp. */
148
149 unsigned rx_frame_cnt; /**< # of array in rx_frames */
150 pjmedia_frame *rx_frames; /**< Temp. buffer for incoming
151 frame assembly. */
152 pj_bool_t force_keyframe;/**< Forced to encode keyframe? */
153 unsigned num_keyframe; /**< The number of keyframe needed
154 to be sent, e.g: after the
155 stream is created. */
156 pj_timestamp last_keyframe_tx;
157 /**< Timestamp of the last
158 keyframe. */
159
160
161 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
162 pj_bool_t use_ka; /**< Stream keep-alive with non-
163 codec-VAD mechanism is
164 enabled? */
165 pj_timestamp last_frm_ts_sent; /**< Timestamp of last sending
166 packet */
167 unsigned start_ka_count; /**< The number of keep-alive
168 to be sent after it is
169 created */
170 unsigned start_ka_interval;/**< The keepalive sending
171 interval after the stream
172 is created */
173 pj_timestamp last_start_ka_tx; /**< Timestamp of the last
174 keepalive sent */
175 #endif
176
177 #if TRACE_JB
178 pj_oshandle_t trace_jb_fd; /**< Jitter tracing file handle.*/
179 char *trace_jb_buf; /**< Jitter tracing buffer. */
180 #endif
181
182 pjmedia_vid_codec *codec; /**< Codec instance being used. */
183 pj_uint32_t last_dec_ts; /**< Last decoded timestamp. */
184 int last_dec_seq; /**< Last decoded sequence. */
185 pj_uint32_t rtp_tx_err_cnt;/**< The number of RTP
186 send() error */
187 pj_uint32_t rtcp_tx_err_cnt;/**< The number of RTCP
188 send() error */
189
190 pj_timestamp ts_freq; /**< Timestamp frequency. */
191
192 pj_sockaddr rem_rtp_addr; /**< Remote RTP address */
193 unsigned rem_rtp_flag; /**< Indicator flag about
194 packet from this addr.
195 0=no pkt, 1=good ssrc pkts,
196 2=bad ssrc pkts */
197 pj_sockaddr rtp_src_addr; /**< Actual packet src addr. */
198 unsigned rtp_src_cnt; /**< How many pkt from this addr*/
199
200
201 /* RTCP Feedback */
202 pj_bool_t send_rtcp_fb_nack; /**< Send NACK? */
203 int pending_rtcp_fb_nack; /**< Any pending NACK? */
204 int rtcp_fb_nack_cap_idx; /**< RX NACK cap idx. */
205 pjmedia_rtcp_fb_nack rtcp_fb_nack; /**< TX NACK state. */
206
207 pj_bool_t send_rtcp_fb_pli; /**< Send PLI? */
208 int pending_rtcp_fb_pli; /**< Any pending PLI? */
209 int rtcp_fb_pli_cap_idx; /**< RX PLI cap idx. */
210
211 #if TRACE_RC
212 unsigned rc_total_sleep;
213 unsigned rc_total_pkt;
214 unsigned rc_total_img;
215 pj_timestamp tx_start;
216 pj_timestamp tx_end;
217 #endif
218 };
219
220 /* Prototypes */
221 static pj_status_t decode_frame(pjmedia_vid_stream *stream,
222 pjmedia_frame *frame);
223
224
225 static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
226 pj_bool_t with_sdes,
227 pj_bool_t with_bye,
228 pj_bool_t with_fb_nack,
229 pj_bool_t with_fb_pli);
230
231 static void on_rx_rtcp( void *data,
232 void *pkt,
233 pj_ssize_t bytes_read);
234
235 #if TRACE_JB
236
trace_jb_print_timestamp(char ** buf,pj_ssize_t len)237 PJ_INLINE(int) trace_jb_print_timestamp(char **buf, pj_ssize_t len)
238 {
239 pj_time_val now;
240 pj_parsed_time ptime;
241 char *p = *buf;
242
243 if (len < 14)
244 return -1;
245
246 pj_gettimeofday(&now);
247 pj_time_decode(&now, &ptime);
248 p += pj_utoa_pad(ptime.hour, p, 2, '0');
249 *p++ = ':';
250 p += pj_utoa_pad(ptime.min, p, 2, '0');
251 *p++ = ':';
252 p += pj_utoa_pad(ptime.sec, p, 2, '0');
253 *p++ = '.';
254 p += pj_utoa_pad(ptime.msec, p, 3, '0');
255 *p++ = ',';
256
257 *buf = p;
258
259 return 0;
260 }
261
trace_jb_print_state(pjmedia_vid_stream * stream,char ** buf,pj_ssize_t len)262 PJ_INLINE(int) trace_jb_print_state(pjmedia_vid_stream *stream,
263 char **buf, pj_ssize_t len)
264 {
265 char *p = *buf;
266 char *endp = *buf + len;
267 pjmedia_jb_state state;
268
269 pjmedia_jbuf_get_state(stream->jb, &state);
270
271 len = pj_ansi_snprintf(p, endp-p, "%d, %d, %d",
272 state.size, state.burst, state.prefetch);
273 if ((len < 0) || (len >= endp-p))
274 return -1;
275
276 p += len;
277 *buf = p;
278 return 0;
279 }
280
trace_jb_get(pjmedia_vid_stream * stream,pjmedia_jb_frame_type ft,pj_size_t fsize)281 static void trace_jb_get(pjmedia_vid_stream *stream, pjmedia_jb_frame_type ft,
282 pj_size_t fsize)
283 {
284 char *p = stream->trace_jb_buf;
285 char *endp = stream->trace_jb_buf + PJ_LOG_MAX_SIZE;
286 pj_ssize_t len = 0;
287 const char* ft_st;
288
289 if (!TRACE_JB_OPENED(stream))
290 return;
291
292 /* Print timestamp. */
293 if (trace_jb_print_timestamp(&p, endp-p))
294 goto on_insuff_buffer;
295
296 /* Print frame type and size */
297 switch(ft) {
298 case PJMEDIA_JB_MISSING_FRAME:
299 ft_st = "missing";
300 break;
301 case PJMEDIA_JB_NORMAL_FRAME:
302 ft_st = "normal";
303 break;
304 case PJMEDIA_JB_ZERO_PREFETCH_FRAME:
305 ft_st = "prefetch";
306 break;
307 case PJMEDIA_JB_ZERO_EMPTY_FRAME:
308 ft_st = "empty";
309 break;
310 default:
311 ft_st = "unknown";
312 break;
313 }
314
315 /* Print operation, size, frame count, frame type */
316 len = pj_ansi_snprintf(p, endp-p, "GET,%d,1,%s,,,,", fsize, ft_st);
317 if ((len < 0) || (len >= endp-p))
318 goto on_insuff_buffer;
319 p += len;
320
321 /* Print JB state */
322 if (trace_jb_print_state(stream, &p, endp-p))
323 goto on_insuff_buffer;
324
325 /* Print end of line */
326 if (endp-p < 2)
327 goto on_insuff_buffer;
328 *p++ = '\n';
329
330 /* Write and flush */
331 len = p - stream->trace_jb_buf;
332 pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
333 pj_file_flush(stream->trace_jb_fd);
334 return;
335
336 on_insuff_buffer:
337 pj_assert(!"Trace buffer too small, check PJ_LOG_MAX_SIZE!");
338 }
339
trace_jb_put(pjmedia_vid_stream * stream,const pjmedia_rtp_hdr * hdr,unsigned payloadlen,unsigned frame_cnt)340 static void trace_jb_put(pjmedia_vid_stream *stream,
341 const pjmedia_rtp_hdr *hdr,
342 unsigned payloadlen, unsigned frame_cnt)
343 {
344 char *p = stream->trace_jb_buf;
345 char *endp = stream->trace_jb_buf + PJ_LOG_MAX_SIZE;
346 pj_ssize_t len = 0;
347
348 if (!TRACE_JB_OPENED(stream))
349 return;
350
351 /* Print timestamp. */
352 if (trace_jb_print_timestamp(&p, endp-p))
353 goto on_insuff_buffer;
354
355 /* Print operation, size, frame count, RTP info */
356 len = pj_ansi_snprintf(p, endp-p,
357 "PUT,%d,%d,,%d,%d,%d,",
358 payloadlen, frame_cnt,
359 pj_ntohs(hdr->seq), pj_ntohl(hdr->ts), hdr->m);
360 if ((len < 0) || (len >= endp-p))
361 goto on_insuff_buffer;
362 p += len;
363
364 /* Print JB state */
365 if (trace_jb_print_state(stream, &p, endp-p))
366 goto on_insuff_buffer;
367
368 /* Print end of line */
369 if (endp-p < 2)
370 goto on_insuff_buffer;
371 *p++ = '\n';
372
373 /* Write and flush */
374 len = p - stream->trace_jb_buf;
375 pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
376 pj_file_flush(stream->trace_jb_fd);
377 return;
378
379 on_insuff_buffer:
380 pj_assert(!"Trace buffer too small, check PJ_LOG_MAX_SIZE!");
381 }
382
383 #endif /* TRACE_JB */
384
dump_port_info(const pjmedia_vid_channel * chan,const char * event_name)385 static void dump_port_info(const pjmedia_vid_channel *chan,
386 const char *event_name)
387 {
388 const pjmedia_port_info *pi = &chan->port.info;
389 char fourcc_name[5];
390
391 PJ_LOG(5, (pi->name.ptr,
392 " %s format %s: %dx%d %s%s %d/%d(~%d)fps",
393 (chan->dir==PJMEDIA_DIR_DECODING? "Decoding":"Encoding"),
394 event_name,
395 pi->fmt.det.vid.size.w, pi->fmt.det.vid.size.h,
396 pjmedia_fourcc_name(pi->fmt.id, fourcc_name),
397 (chan->dir==PJMEDIA_DIR_ENCODING?"->":"<-"),
398 pi->fmt.det.vid.fps.num, pi->fmt.det.vid.fps.denum,
399 pi->fmt.det.vid.fps.num/pi->fmt.det.vid.fps.denum));
400 }
401
402 /*
403 * Handle events from stream components.
404 */
stream_event_cb(pjmedia_event * event,void * user_data)405 static pj_status_t stream_event_cb(pjmedia_event *event,
406 void *user_data)
407 {
408 pjmedia_vid_stream *stream = (pjmedia_vid_stream*)user_data;
409
410 if (event->epub == stream->codec) {
411 /* This is codec event */
412 switch (event->type) {
413 case PJMEDIA_EVENT_FMT_CHANGED:
414 /* Copy the event to avoid deadlock if we publish the event
415 * now. This happens because fmt_event may trigger restart
416 * while we're still holding the jb_mutex.
417 */
418 pj_memcpy(&stream->fmt_event, event, sizeof(*event));
419 return PJ_SUCCESS;
420
421 case PJMEDIA_EVENT_KEYFRAME_MISSING:
422 /* Republish this event later from get_frame(). */
423 pj_memcpy(&stream->miss_keyframe_event, event, sizeof(*event));
424
425 if (stream->send_rtcp_fb_pli) {
426 /* Schedule sending RTCP-FB PLI to encoder, if configured,
427 * also perhaps better to make it redundant, in case the first
428 * packet is lost.
429 */
430 stream->pending_rtcp_fb_pli = 2;
431 }
432 return PJ_SUCCESS;
433
434 default:
435 break;
436 }
437 } else if (event->epub == &stream->rtcp &&
438 event->type==PJMEDIA_EVENT_RX_RTCP_FB)
439 {
440 /* This is RX RTCP-FB event */
441 pjmedia_event_rx_rtcp_fb_data *data =
442 (pjmedia_event_rx_rtcp_fb_data*)&event->data.rx_rtcp_fb;
443
444 /* Check if configured to listen to the RTCP-FB type */
445 if (data->cap.type == PJMEDIA_RTCP_FB_NACK) {
446 if (data->cap.param.slen == 0 &&
447 stream->rtcp_fb_nack_cap_idx >= 0)
448 {
449 /* Generic NACK */
450
451 /* Update event data capability before republishing */
452 data->cap = stream->info.loc_rtcp_fb.caps[
453 stream->rtcp_fb_nack_cap_idx];
454 }
455 else if (pj_strcmp2(&data->cap.param, "pli") == 0 &&
456 stream->rtcp_fb_pli_cap_idx >= 0)
457 {
458 /* PLI */
459
460 /* Tell encoder to generate keyframe */
461 pjmedia_vid_stream_send_keyframe(stream);
462
463 /* Update event data capability before republishing */
464 data->cap = stream->info.loc_rtcp_fb.caps[
465 stream->rtcp_fb_pli_cap_idx];
466
467 }
468 }
469 }
470
471 /* Republish events */
472 return pjmedia_event_publish(NULL, stream, event,
473 PJMEDIA_EVENT_PUBLISH_POST_EVENT);
474 }
475
476
477 /**
478 * Publish transport error event.
479 */
publish_tp_event(pjmedia_event_type event_type,pj_status_t status,pj_bool_t is_rtp,pjmedia_dir dir,pjmedia_vid_stream * stream)480 static void publish_tp_event(pjmedia_event_type event_type,
481 pj_status_t status,
482 pj_bool_t is_rtp,
483 pjmedia_dir dir,
484 pjmedia_vid_stream *stream)
485 {
486 pjmedia_event ev;
487 pj_timestamp ts_now;
488
489 pj_get_timestamp(&ts_now);
490 pj_bzero(&ev.data.med_tp_err, sizeof(ev.data.med_tp_err));
491
492 /* Publish event. */
493 pjmedia_event_init(&ev, event_type,
494 &ts_now, stream);
495 ev.data.med_tp_err.type = PJMEDIA_TYPE_VIDEO;
496 ev.data.med_tp_err.is_rtp = is_rtp;
497 ev.data.med_tp_err.dir = dir;
498 ev.data.med_tp_err.status = status;
499
500 pjmedia_event_publish(NULL, stream, &ev, 0);
501 }
502
503 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
504 /*
505 * Send keep-alive packet using non-codec frame.
506 */
send_keep_alive_packet(pjmedia_vid_stream * stream)507 static void send_keep_alive_packet(pjmedia_vid_stream *stream)
508 {
509 #if PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_EMPTY_RTP
510
511 /* Keep-alive packet is empty RTP */
512 pjmedia_vid_channel *channel = stream->enc;
513 pj_status_t status;
514 void *pkt;
515 int pkt_len;
516
517 TRC_((channel->port.info.name.ptr,
518 "Sending keep-alive (RTCP and empty RTP)"));
519
520 /* Send RTP */
521 status = pjmedia_rtp_encode_rtp( &stream->enc->rtp,
522 stream->enc->pt, 0,
523 1,
524 0,
525 (const void**)&pkt,
526 &pkt_len);
527 pj_assert(status == PJ_SUCCESS);
528
529 pj_memcpy(stream->enc->buf, pkt, pkt_len);
530 pjmedia_transport_send_rtp(stream->transport, stream->enc->buf,
531 pkt_len);
532
533 /* Send RTCP */
534 send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE, PJ_FALSE);
535
536 /* Update stats in case the stream is paused */
537 stream->rtcp.stat.rtp_tx_last_seq = pj_ntohs(stream->enc->rtp.out_hdr.seq);
538
539 #elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER
540
541 /* Keep-alive packet is defined in PJMEDIA_STREAM_KA_USER_PKT */
542 pjmedia_vid_channel *channel = stream->enc;
543 int pkt_len;
544 const pj_str_t str_ka = PJMEDIA_STREAM_KA_USER_PKT;
545
546 TRC_((channel->port.info.name.ptr,
547 "Sending keep-alive (custom RTP/RTCP packets)"));
548
549 /* Send to RTP port */
550 pj_memcpy(stream->enc->buf, str_ka.ptr, str_ka.slen);
551 pkt_len = str_ka.slen;
552 pjmedia_transport_send_rtp(stream->transport, stream->enc->buf,
553 pkt_len);
554
555 /* Send to RTCP port */
556 pjmedia_transport_send_rtcp(stream->transport, stream->enc->buf,
557 pkt_len);
558
559 #else
560
561 PJ_UNUSED_ARG(stream);
562
563 #endif
564 }
565 #endif /* defined(PJMEDIA_STREAM_ENABLE_KA) */
566
567
send_rtcp(pjmedia_vid_stream * stream,pj_bool_t with_sdes,pj_bool_t with_bye,pj_bool_t with_fb_nack,pj_bool_t with_fb_pli)568 static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
569 pj_bool_t with_sdes,
570 pj_bool_t with_bye,
571 pj_bool_t with_fb_nack,
572 pj_bool_t with_fb_pli)
573 {
574 void *sr_rr_pkt;
575 pj_uint8_t *pkt;
576 int len, max_len;
577 pj_status_t status;
578
579 /* Build RTCP RR/SR packet */
580 pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
581
582 if (with_sdes || with_bye || with_fb_nack || with_fb_pli) {
583 pkt = (pj_uint8_t*) stream->out_rtcp_pkt;
584 pj_memcpy(pkt, sr_rr_pkt, len);
585 max_len = stream->out_rtcp_pkt_size;
586 } else {
587 pkt = (pj_uint8_t*)sr_rr_pkt;
588 max_len = len;
589 }
590
591 /* Build RTCP SDES packet, forced if also send RTCP-FB */
592 with_sdes = with_sdes || with_fb_pli || with_fb_nack;
593 if (with_sdes) {
594 pjmedia_rtcp_sdes sdes;
595 pj_size_t sdes_len;
596
597 pj_bzero(&sdes, sizeof(sdes));
598 sdes.cname = stream->cname;
599 sdes_len = max_len - len;
600 status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len,
601 &sdes_len, &sdes);
602 if (status != PJ_SUCCESS) {
603 PJ_PERROR(4,(stream->name.ptr, status,
604 "Error generating RTCP SDES"));
605 } else {
606 len += (int)sdes_len;
607 }
608 }
609
610 /* Build RTCP BYE packet */
611 if (with_bye) {
612 pj_size_t bye_len = max_len - len;
613 status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len,
614 &bye_len, NULL);
615 if (status != PJ_SUCCESS) {
616 PJ_PERROR(4,(stream->name.ptr, status,
617 "Error generating RTCP BYE"));
618 } else {
619 len += (int)bye_len;
620 }
621 }
622
623 /* Build RTCP-FB generic NACK packet */
624 if (with_fb_nack && stream->rtcp_fb_nack.pid >= 0) {
625 pj_size_t fb_len = max_len - len;
626 status = pjmedia_rtcp_fb_build_nack(&stream->rtcp, pkt+len, &fb_len,
627 1, &stream->rtcp_fb_nack);
628 if (status != PJ_SUCCESS) {
629 PJ_PERROR(4,(stream->name.ptr, status,
630 "Error generating RTCP-FB NACK"));
631 } else {
632 len += (int)fb_len;
633 }
634 }
635
636 /* Build RTCP-FB PLI packet */
637 if (with_fb_pli) {
638 pj_size_t fb_len = max_len - len;
639 status = pjmedia_rtcp_fb_build_pli(&stream->rtcp, pkt+len, &fb_len);
640 if (status != PJ_SUCCESS) {
641 PJ_PERROR(4,(stream->name.ptr, status,
642 "Error generating RTCP-FB PLI"));
643 } else {
644 len += (int)fb_len;
645 PJ_LOG(5,(stream->name.ptr, "Sending RTCP-FB PLI packet"));
646 }
647 }
648
649 /* Send! */
650 status = pjmedia_transport_send_rtcp(stream->transport, pkt, len);
651 if (status != PJ_SUCCESS) {
652 if (stream->rtcp_tx_err_cnt++ == 0) {
653 LOGERR_((stream->name.ptr, status, "Error sending RTCP"));
654 }
655 if (stream->rtcp_tx_err_cnt > SEND_ERR_COUNT_TO_REPORT) {
656 stream->rtcp_tx_err_cnt = 0;
657 }
658 }
659 return status;
660 }
661
662
663 /**
664 * check_tx_rtcp()
665 *
666 * This function is can be called by either put_frame() or get_frame(),
667 * to transmit periodic RTCP SR/RR report.
668 * If 'fb_pli' is set to PJ_TRUE, this will send immediate RTCP-FB PLI.
669 */
check_tx_rtcp(pjmedia_vid_stream * stream)670 static void check_tx_rtcp(pjmedia_vid_stream *stream)
671 {
672 pj_timestamp now;
673 pj_bool_t early;
674
675 /* Check if early RTCP mode is required (i.e: RTCP-FB) and allowed (i.e:
676 * elapsed timestamp from previous RTCP-FB >= PJMEDIA_RTCP_FB_INTERVAL).
677 */
678 pj_get_timestamp(&now);
679 early = ((stream->pending_rtcp_fb_pli || stream->pending_rtcp_fb_nack)
680 &&
681 (stream->rtcp_fb_last_tx.u64 == 0 ||
682 pj_elapsed_msec(&stream->rtcp_fb_last_tx, &now) >=
683 PJMEDIA_RTCP_FB_INTERVAL));
684
685 /* First check, unless RTCP is 'urgent', just init rtcp_last_tx. */
686 if (stream->rtcp_last_tx.u64 == 0 && !early) {
687 pj_get_timestamp(&stream->rtcp_last_tx);
688 return;
689 }
690
691 /* Build & send RTCP */
692 if (early ||
693 pj_elapsed_msec(&stream->rtcp_last_tx, &now) >= stream->rtcp_interval)
694 {
695 pj_status_t status;
696
697 status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE,
698 stream->pending_rtcp_fb_nack,
699 stream->pending_rtcp_fb_pli);
700 if (status != PJ_SUCCESS) {
701 PJ_PERROR(4,(stream->name.ptr, status,
702 "Error sending RTCP"));
703 }
704
705 stream->rtcp_last_tx = now;
706
707 if (early)
708 stream->rtcp_fb_last_tx = now;
709
710 if (stream->pending_rtcp_fb_pli)
711 stream->pending_rtcp_fb_pli--;
712
713 if (stream->pending_rtcp_fb_nack)
714 stream->pending_rtcp_fb_nack--;
715 }
716 }
717
718
719 #if 0
720 static void dump_bin(const char *buf, unsigned len)
721 {
722 unsigned i;
723
724 PJ_LOG(3,(THIS_FILE, "begin dump"));
725 for (i=0; i<len; ++i) {
726 int j;
727 char bits[9];
728 unsigned val = buf[i] & 0xFF;
729
730 bits[8] = '\0';
731 for (j=0; j<8; ++j) {
732 if (val & (1 << (7-j)))
733 bits[j] = '1';
734 else
735 bits[j] = '0';
736 }
737
738 PJ_LOG(3,(THIS_FILE, "%2d %s [%d]", i, bits, val));
739 }
740 PJ_LOG(3,(THIS_FILE, "end dump"));
741 }
742 #endif
743
744
745 /*
746 * This callback is called by stream transport on receipt of packets
747 * in the RTP socket.
748 */
on_rx_rtp(pjmedia_tp_cb_param * param)749 static void on_rx_rtp( pjmedia_tp_cb_param *param)
750 {
751 pjmedia_vid_stream *stream = (pjmedia_vid_stream*) param->user_data;
752 void *pkt = param->pkt;
753 pj_ssize_t bytes_read = param->size;
754 pjmedia_vid_channel *channel = stream->dec;
755 const pjmedia_rtp_hdr *hdr;
756 const void *payload;
757 unsigned payloadlen;
758 pjmedia_rtp_status seq_st;
759 pj_status_t status;
760 pj_bool_t pkt_discarded = PJ_FALSE;
761
762 /* Check for errors */
763 if (bytes_read < 0) {
764 status = (pj_status_t)-bytes_read;
765 if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
766 return;
767 }
768
769 LOGERR_((channel->port.info.name.ptr, status,
770 "Unable to receive RTP packet"));
771
772 if (status == PJ_ESOCKETSTOP) {
773 /* Publish receive error event. */
774 publish_tp_event(PJMEDIA_EVENT_MEDIA_TP_ERR, status, PJ_TRUE,
775 PJMEDIA_DIR_DECODING, stream);
776 }
777 return;
778 }
779
780 /* Ignore keep-alive packets */
781 if (bytes_read < (pj_ssize_t) sizeof(pjmedia_rtp_hdr))
782 return;
783
784 /* Update RTP and RTCP session. */
785 status = pjmedia_rtp_decode_rtp(&channel->rtp, pkt, (int)bytes_read,
786 &hdr, &payload, &payloadlen);
787 if (status != PJ_SUCCESS) {
788 LOGERR_((channel->port.info.name.ptr, status, "RTP decode error"));
789 stream->rtcp.stat.rx.discard++;
790 return;
791 }
792
793 /* Check if multiplexing is allowed and the payload indicates RTCP. */
794 if (stream->info.rtcp_mux && hdr->pt >= 64 && hdr->pt <= 95) {
795 on_rx_rtcp(stream, pkt, bytes_read);
796 return;
797 }
798
799 /* Ignore the packet if decoder is paused */
800 if (channel->paused)
801 goto on_return;
802
803 /* Update RTP session (also checks if RTP session can accept
804 * the incoming packet.
805 */
806 pjmedia_rtp_session_update2(&channel->rtp, hdr, &seq_st, PJ_TRUE);
807 if (seq_st.status.value) {
808 TRC_ ((channel->port.info.name.ptr,
809 "RTP status: badpt=%d, badssrc=%d, dup=%d, "
810 "outorder=%d, probation=%d, restart=%d",
811 seq_st.status.flag.badpt,
812 seq_st.status.flag.badssrc,
813 seq_st.status.flag.dup,
814 seq_st.status.flag.outorder,
815 seq_st.status.flag.probation,
816 seq_st.status.flag.restart));
817
818 if (seq_st.status.flag.badpt) {
819 PJ_LOG(4,(channel->port.info.name.ptr,
820 "Bad RTP pt %d (expecting %d)",
821 hdr->pt, channel->rtp.out_pt));
822 }
823
824 if (!stream->info.has_rem_ssrc && seq_st.status.flag.badssrc) {
825 PJ_LOG(4,(channel->port.info.name.ptr,
826 "Changed RTP peer SSRC %d (previously %d)",
827 channel->rtp.peer_ssrc, stream->rtcp.peer_ssrc));
828 stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc;
829 }
830
831
832 }
833
834 /* Skip bad RTP packet */
835 if (seq_st.status.flag.bad) {
836 pkt_discarded = PJ_TRUE;
837 goto on_return;
838 }
839
840 /* Ignore if payloadlen is zero */
841 if (payloadlen == 0) {
842 pkt_discarded = PJ_TRUE;
843 goto on_return;
844 }
845
846 /* See if source address of RTP packet is different than the
847 * configured address, and check if we need to tell the
848 * media transport to switch RTP remote address.
849 */
850 if (param->src_addr) {
851 pj_bool_t badssrc = (stream->info.has_rem_ssrc &&
852 seq_st.status.flag.badssrc);
853
854 if (pj_sockaddr_cmp(&stream->rem_rtp_addr, param->src_addr) == 0) {
855 /* We're still receiving from rem_rtp_addr. */
856 stream->rtp_src_cnt = 0;
857 stream->rem_rtp_flag = badssrc? 2: 1;
858 } else {
859 stream->rtp_src_cnt++;
860
861 if (stream->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
862 if (stream->rem_rtp_flag == 1 ||
863 (stream->rem_rtp_flag == 2 && badssrc))
864 {
865 /* Only discard if:
866 * - we have ever received packet with good ssrc from
867 * remote address (rem_rtp_addr), or
868 * - we have ever received packet with bad ssrc from
869 * remote address and this packet also has bad ssrc.
870 */
871 pkt_discarded = PJ_TRUE;
872 goto on_return;
873 }
874 if (stream->info.has_rem_ssrc && !seq_st.status.flag.badssrc
875 && stream->rem_rtp_flag != 1)
876 {
877 /* Immediately switch if we receive packet with the
878 * correct ssrc AND we never receive packets with
879 * good ssrc from rem_rtp_addr.
880 */
881 param->rem_switch = PJ_TRUE;
882 }
883 } else {
884 /* Switch. We no longer receive packets from rem_rtp_addr. */
885 param->rem_switch = PJ_TRUE;
886 }
887
888 if (param->rem_switch) {
889 /* Set remote RTP address to source address */
890 pj_sockaddr_cp(&stream->rem_rtp_addr, param->src_addr);
891
892 /* Reset counter and flag */
893 stream->rtp_src_cnt = 0;
894 stream->rem_rtp_flag = badssrc? 2: 1;
895
896 /* Update RTCP peer ssrc */
897 stream->rtcp.peer_ssrc = pj_ntohl(hdr->ssrc);
898 }
899 }
900 }
901
902 pj_mutex_lock( stream->jb_mutex );
903
904 /* Quickly see if there may be a full picture in the jitter buffer, and
905 * decode them if so. More thorough check will be done in decode_frame().
906 */
907 if ((pj_ntohl(hdr->ts) != stream->dec_frame.timestamp.u32.lo) || hdr->m) {
908 if (PJMEDIA_VID_STREAM_SKIP_PACKETS_TO_REDUCE_LATENCY) {
909 /* Always decode whenever we have picture in jb and
910 * overwrite already decoded picture if necessary
911 */
912 pj_size_t old_size = stream->dec_frame.size;
913
914 stream->dec_frame.size = stream->dec_max_size;
915 if (decode_frame(stream, &stream->dec_frame) != PJ_SUCCESS) {
916 stream->dec_frame.size = old_size;
917 }
918 } else {
919 /* Only decode if we don't already have decoded one,
920 * unless the jb is full.
921 */
922 pj_bool_t can_decode = PJ_FALSE;
923
924 if (pjmedia_jbuf_is_full(stream->jb)) {
925 can_decode = PJ_TRUE;
926 }
927 else if (stream->dec_frame.size == 0) {
928 can_decode = PJ_TRUE;
929 }
930
931 if (can_decode) {
932 stream->dec_frame.size = stream->dec_max_size;
933 if (decode_frame(stream, &stream->dec_frame) != PJ_SUCCESS) {
934 stream->dec_frame.size = 0;
935 }
936 }
937 }
938 }
939
940 /* Put "good" packet to jitter buffer, or reset the jitter buffer
941 * when RTP session is restarted.
942 */
943 if (seq_st.status.flag.restart) {
944 status = pjmedia_jbuf_reset(stream->jb);
945 PJ_LOG(4,(channel->port.info.name.ptr, "Jitter buffer reset"));
946 } else {
947 /* Just put the payload into jitter buffer */
948 pjmedia_jbuf_put_frame3(stream->jb, payload, payloadlen, 0,
949 pj_ntohs(hdr->seq), pj_ntohl(hdr->ts), NULL);
950
951 #if TRACE_JB
952 trace_jb_put(stream, hdr, payloadlen, count);
953 #endif
954
955 }
956 pj_mutex_unlock( stream->jb_mutex );
957
958 /* Check if we need to send RTCP-FB generic NACK */
959 if (stream->send_rtcp_fb_nack && seq_st.diff > 1 &&
960 pj_ntohs(hdr->seq) >= seq_st.diff)
961 {
962 int i;
963 pj_bzero(&stream->rtcp_fb_nack, sizeof(stream->rtcp_fb_nack));
964 stream->rtcp_fb_nack.pid = pj_ntohs(hdr->seq) - seq_st.diff + 1;
965 for (i = 0; i < (seq_st.diff - 1); ++i) {
966 stream->rtcp_fb_nack.blp <<= 1;
967 stream->rtcp_fb_nack.blp |= 1;
968 }
969 stream->pending_rtcp_fb_nack = 1;
970 }
971
972 /* Check if now is the time to transmit RTCP SR/RR report.
973 * We only do this when stream direction is "decoding only" or
974 * if the encoder is paused,
975 * because otherwise check_tx_rtcp() will be handled by put_frame()
976 */
977 if (stream->dir == PJMEDIA_DIR_DECODING || stream->enc->paused) {
978 check_tx_rtcp(stream);
979 }
980
981 if (status != 0) {
982 LOGERR_((channel->port.info.name.ptr, status,
983 "Jitter buffer put() error"));
984 pkt_discarded = PJ_TRUE;
985 goto on_return;
986 }
987
988 on_return:
989 /* Update RTCP session */
990 if (stream->rtcp.peer_ssrc == 0)
991 stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc;
992
993 pjmedia_rtcp_rx_rtp2(&stream->rtcp, pj_ntohs(hdr->seq),
994 pj_ntohl(hdr->ts), payloadlen, pkt_discarded);
995
996 /* Send RTCP RR and SDES after we receive some RTP packets */
997 if (stream->rtcp.received >= 10 && !stream->initial_rr) {
998 status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled,
999 PJ_FALSE, PJ_FALSE, PJ_FALSE);
1000 if (status != PJ_SUCCESS) {
1001 PJ_PERROR(4,(stream->name.ptr, status,
1002 "Error sending initial RTCP RR"));
1003 } else {
1004 stream->initial_rr = PJ_TRUE;
1005 }
1006 }
1007 }
1008
1009
1010 /*
1011 * This callback is called by stream transport on receipt of packets
1012 * in the RTCP socket.
1013 */
on_rx_rtcp(void * data,void * pkt,pj_ssize_t bytes_read)1014 static void on_rx_rtcp( void *data,
1015 void *pkt,
1016 pj_ssize_t bytes_read)
1017 {
1018 pjmedia_vid_stream *stream = (pjmedia_vid_stream*) data;
1019 pj_status_t status;
1020
1021 /* Check for errors */
1022 if (bytes_read < 0) {
1023 status = (pj_status_t)-bytes_read;
1024 if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
1025 return;
1026 }
1027 LOGERR_((stream->cname.ptr, status, "Unable to receive RTCP packet"));
1028 if (status == PJ_ESOCKETSTOP) {
1029 /* Publish receive error event. */
1030 publish_tp_event(PJMEDIA_EVENT_MEDIA_TP_ERR, status, PJ_FALSE,
1031 PJMEDIA_DIR_DECODING, stream);
1032 }
1033 return;
1034 }
1035
1036 pjmedia_rtcp_rx_rtcp(&stream->rtcp, pkt, bytes_read);
1037 }
1038
put_frame(pjmedia_port * port,pjmedia_frame * frame)1039 static pj_status_t put_frame(pjmedia_port *port,
1040 pjmedia_frame *frame)
1041 {
1042 pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata;
1043 pjmedia_vid_channel *channel = stream->enc;
1044 pj_status_t status = 0;
1045 pjmedia_frame frame_out;
1046 unsigned rtp_ts_len;
1047 void *rtphdr;
1048 int rtphdrlen;
1049 pj_bool_t has_more_data = PJ_FALSE;
1050 pj_size_t total_sent = 0;
1051 pjmedia_vid_encode_opt enc_opt;
1052 unsigned pkt_cnt = 0;
1053 pj_timestamp initial_time;
1054 pj_timestamp now;
1055 pj_timestamp null_ts ={{0}};
1056
1057 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
1058 /* If the interval since last sending packet is greater than
1059 * PJMEDIA_STREAM_KA_INTERVAL, send keep-alive packet.
1060 */
1061 if (stream->use_ka)
1062 {
1063 pj_uint32_t dtx_duration, ka_interval;
1064
1065 dtx_duration = pj_timestamp_diff32(&stream->last_frm_ts_sent,
1066 &frame->timestamp);
1067 if (stream->start_ka_count) {
1068 ka_interval = stream->start_ka_interval *
1069 stream->info.codec_info.clock_rate / 1000;
1070 } else {
1071 ka_interval = PJMEDIA_STREAM_KA_INTERVAL *
1072 stream->info.codec_info.clock_rate;
1073 }
1074 if (dtx_duration > ka_interval) {
1075 send_keep_alive_packet(stream);
1076 stream->last_frm_ts_sent = frame->timestamp;
1077
1078 if (stream->start_ka_count)
1079 stream->start_ka_count--;
1080 }
1081 }
1082 #endif
1083 /* Get frame length in timestamp unit */
1084 rtp_ts_len = stream->frame_ts_len;
1085
1086 /* Don't do anything if stream is paused, except updating RTP timestamp */
1087 if (channel->paused) {
1088 /* Update RTP session's timestamp. */
1089 status = pjmedia_rtp_encode_rtp( &channel->rtp, 0, 0, 0, rtp_ts_len,
1090 NULL, NULL);
1091
1092 /* Update RTCP stats with last RTP timestamp. */
1093 stream->rtcp.stat.rtp_tx_last_ts =
1094 pj_ntohl(channel->rtp.out_hdr.ts);
1095 return PJ_SUCCESS;
1096 }
1097
1098 /* Empty video frame? Just update RTP timestamp for now */
1099 if (frame->type==PJMEDIA_FRAME_TYPE_VIDEO && frame->size==0) {
1100 pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0,
1101 rtp_ts_len, (const void**)&rtphdr,
1102 &rtphdrlen);
1103 return PJ_SUCCESS;
1104 }
1105
1106 /* Init frame_out buffer. */
1107 pj_bzero(&frame_out, sizeof(frame_out));
1108 frame_out.buf = ((char*)channel->buf) + sizeof(pjmedia_rtp_hdr);
1109
1110 /* Check if need to send keyframe. */
1111 pj_get_timestamp(&now);
1112 if (stream->num_keyframe &&
1113 (pj_cmp_timestamp(&null_ts, &stream->last_keyframe_tx) != 0))
1114 {
1115 unsigned elapse_time;
1116
1117 elapse_time = pj_elapsed_msec(&stream->last_keyframe_tx, &now);
1118 if (elapse_time > stream->info.sk_cfg.interval)
1119 {
1120 stream->force_keyframe = PJ_TRUE;
1121 --stream->num_keyframe;
1122 }
1123 }
1124
1125 /* Init encoding option */
1126 pj_bzero(&enc_opt, sizeof(enc_opt));
1127 if (stream->force_keyframe &&
1128 pj_elapsed_msec(&stream->last_keyframe_tx, &now) >=
1129 PJMEDIA_VID_STREAM_MIN_KEYFRAME_INTERVAL_MSEC)
1130 {
1131 /* Force encoder to generate keyframe */
1132 enc_opt.force_keyframe = PJ_TRUE;
1133 stream->force_keyframe = PJ_FALSE;
1134 TRC_((channel->port.info.name.ptr,
1135 "Forcing encoder to generate keyframe"));
1136 }
1137
1138 /* Encode! */
1139 status = pjmedia_vid_codec_encode_begin(stream->codec, &enc_opt, frame,
1140 channel->buf_size -
1141 sizeof(pjmedia_rtp_hdr),
1142 &frame_out,
1143 &has_more_data);
1144 if (status != PJ_SUCCESS) {
1145 LOGERR_((channel->port.info.name.ptr, status,
1146 "Codec encode_begin() error"));
1147
1148 /* Update RTP timestamp */
1149 pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0,
1150 rtp_ts_len, (const void**)&rtphdr,
1151 &rtphdrlen);
1152 return status;
1153 }
1154
1155 pj_get_timestamp(&initial_time);
1156
1157 if ((frame_out.bit_info & PJMEDIA_VID_FRM_KEYFRAME)
1158 == PJMEDIA_VID_FRM_KEYFRAME)
1159 {
1160 stream->last_keyframe_tx = initial_time;
1161 TRC_((channel->port.info.name.ptr, "Keyframe generated"));
1162 }
1163
1164 /* Loop while we have frame to send */
1165 for (;;) {
1166 status = pjmedia_rtp_encode_rtp(&channel->rtp,
1167 channel->pt,
1168 (has_more_data == PJ_FALSE ? 1 : 0),
1169 (int)frame_out.size,
1170 rtp_ts_len,
1171 (const void**)&rtphdr,
1172 &rtphdrlen);
1173 if (status != PJ_SUCCESS) {
1174 LOGERR_((channel->port.info.name.ptr, status,
1175 "RTP encode_rtp() error"));
1176 return status;
1177 }
1178
1179 /* When the payload length is zero, we should not send anything,
1180 * but proceed the rest normally.
1181 */
1182 if (frame_out.size != 0) {
1183 /* Copy RTP header to the beginning of packet */
1184 pj_memcpy(channel->buf, rtphdr, sizeof(pjmedia_rtp_hdr));
1185
1186 /* Send the RTP packet to the transport. */
1187 status = pjmedia_transport_send_rtp(stream->transport,
1188 (char*)channel->buf,
1189 frame_out.size +
1190 sizeof(pjmedia_rtp_hdr));
1191 if (status != PJ_SUCCESS) {
1192 if (stream->rtp_tx_err_cnt++ == 0) {
1193 LOGERR_((channel->port.info.name.ptr, status,
1194 "Error sending RTP"));
1195 }
1196 if (stream->rtp_tx_err_cnt > SEND_ERR_COUNT_TO_REPORT) {
1197 stream->rtp_tx_err_cnt = 0;
1198 }
1199 }
1200 pjmedia_rtcp_tx_rtp(&stream->rtcp, (unsigned)frame_out.size);
1201 total_sent += frame_out.size;
1202 pkt_cnt++;
1203 }
1204
1205 if (!has_more_data)
1206 break;
1207
1208 /* Next packets use same timestamp */
1209 rtp_ts_len = 0;
1210
1211 frame_out.size = 0;
1212
1213 /* Encode more! */
1214 status = pjmedia_vid_codec_encode_more(stream->codec,
1215 channel->buf_size -
1216 sizeof(pjmedia_rtp_hdr),
1217 &frame_out,
1218 &has_more_data);
1219 if (status != PJ_SUCCESS) {
1220 LOGERR_((channel->port.info.name.ptr, status,
1221 "Codec encode_more() error"));
1222 /* Ignore this error (?) */
1223 break;
1224 }
1225
1226 /* Send rate control */
1227 if (stream->info.rc_cfg.method==PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING)
1228 {
1229 pj_timestamp next_send_ts, total_send_ts;
1230
1231 total_send_ts.u64 = total_sent * stream->ts_freq.u64 * 8 /
1232 stream->info.rc_cfg.bandwidth;
1233 next_send_ts = initial_time;
1234 pj_add_timestamp(&next_send_ts, &total_send_ts);
1235
1236 pj_get_timestamp(&now);
1237 if (pj_cmp_timestamp(&now, &next_send_ts) < 0) {
1238 unsigned ms_sleep;
1239 ms_sleep = pj_elapsed_msec(&now, &next_send_ts);
1240
1241 if (ms_sleep > 10)
1242 ms_sleep = 10;
1243
1244 pj_thread_sleep(ms_sleep);
1245 }
1246 }
1247 }
1248
1249 #if TRACE_RC
1250 /* Trace log for rate control */
1251 {
1252 pj_timestamp end_time;
1253 unsigned total_sleep;
1254
1255 pj_get_timestamp(&end_time);
1256 total_sleep = pj_elapsed_msec(&initial_time, &end_time);
1257 PJ_LOG(5, (stream->name.ptr, "total pkt=%d size=%d sleep=%d",
1258 pkt_cnt, total_sent, total_sleep));
1259
1260 if (stream->tx_start.u64 == 0)
1261 stream->tx_start = initial_time;
1262 stream->tx_end = end_time;
1263 stream->rc_total_pkt += pkt_cnt;
1264 stream->rc_total_sleep += total_sleep;
1265 stream->rc_total_img++;
1266 }
1267 #endif
1268
1269 /* Check if now is the time to transmit RTCP SR/RR report.
1270 * We only do this when stream direction is not "decoding only", because
1271 * when it is, check_tx_rtcp() will be handled by get_frame().
1272 */
1273 if (stream->dir != PJMEDIA_DIR_DECODING) {
1274 check_tx_rtcp(stream);
1275 }
1276
1277 /* Do nothing if we have nothing to transmit */
1278 if (total_sent == 0) {
1279 return PJ_SUCCESS;
1280 }
1281
1282 /* Update stat */
1283 if (pkt_cnt) {
1284 stream->rtcp.stat.rtp_tx_last_ts =
1285 pj_ntohl(stream->enc->rtp.out_hdr.ts);
1286 stream->rtcp.stat.rtp_tx_last_seq =
1287 pj_ntohs(stream->enc->rtp.out_hdr.seq);
1288 }
1289
1290 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
1291 /* Update timestamp of last sending packet. */
1292 stream->last_frm_ts_sent = frame->timestamp;
1293 #endif
1294
1295 return PJ_SUCCESS;
1296 }
1297
1298 /* Decode one image from jitter buffer */
decode_frame(pjmedia_vid_stream * stream,pjmedia_frame * frame)1299 static pj_status_t decode_frame(pjmedia_vid_stream *stream,
1300 pjmedia_frame *frame)
1301 {
1302 pjmedia_vid_channel *channel = stream->dec;
1303 pj_uint32_t last_ts = 0, frm_ts = 0;
1304 pj_bool_t last_ts_inited = PJ_FALSE;
1305 int frm_first_seq = 0, frm_last_seq = 0;
1306 pj_bool_t got_frame = PJ_FALSE;
1307 unsigned cnt, frm_pkt_cnt = 0, frm_cnt = 0;
1308 pj_status_t status;
1309
1310 /* Repeat get payload from the jitter buffer until all payloads with same
1311 * timestamp are collected.
1312 */
1313
1314 /* Check if we got a decodable frame */
1315 for (cnt=0; ; ) {
1316 char ptype;
1317 pj_uint32_t ts;
1318 int seq;
1319
1320 /* Peek frame from jitter buffer. */
1321 pjmedia_jbuf_peek_frame(stream->jb, cnt, NULL, NULL,
1322 &ptype, NULL, &ts, &seq);
1323 if (ptype == PJMEDIA_JB_NORMAL_FRAME) {
1324 if (stream->last_dec_ts == ts) {
1325 /* Remove any late packet (the frame has been decoded) */
1326 pjmedia_jbuf_remove_frame(stream->jb, 1);
1327 continue;
1328 }
1329
1330 if (!last_ts_inited) {
1331 last_ts = ts;
1332
1333 /* Init timestamp and first seq of the first frame */
1334 frm_ts = ts;
1335 frm_first_seq = seq;
1336 last_ts_inited = PJ_TRUE;
1337 }
1338 if (ts != last_ts) {
1339 last_ts = ts;
1340 if (frm_pkt_cnt == 0)
1341 frm_pkt_cnt = cnt;
1342
1343 /* Is it time to decode? Check with minimum delay setting */
1344 if (++frm_cnt == stream->dec_delay_cnt) {
1345 got_frame = PJ_TRUE;
1346 break;
1347 }
1348 }
1349 } else if (ptype == PJMEDIA_JB_ZERO_EMPTY_FRAME) {
1350 /* No more packet in the jitter buffer */
1351 break;
1352 }
1353
1354 ++cnt;
1355 }
1356
1357 if (got_frame) {
1358 unsigned i;
1359
1360 /* Exclude any MISSING frames in the end of the packets array, as
1361 * it may be part of the next video frame (late packets).
1362 */
1363 for (; frm_pkt_cnt > 1; --frm_pkt_cnt) {
1364 char ptype;
1365 pjmedia_jbuf_peek_frame(stream->jb, frm_pkt_cnt, NULL, NULL, &ptype,
1366 NULL, NULL, NULL);
1367 if (ptype == PJMEDIA_JB_NORMAL_FRAME)
1368 break;
1369 }
1370
1371 /* Check if the packet count for this frame exceeds the limit */
1372 if (frm_pkt_cnt > stream->rx_frame_cnt) {
1373 PJ_LOG(1,(channel->port.info.name.ptr,
1374 "Discarding %u frames because array is full!",
1375 frm_pkt_cnt - stream->rx_frame_cnt));
1376 pjmedia_jbuf_remove_frame(stream->jb,
1377 frm_pkt_cnt - stream->rx_frame_cnt);
1378 frm_pkt_cnt = stream->rx_frame_cnt;
1379 }
1380
1381 /* Generate frame bitstream from the payload */
1382 for (i = 0; i < frm_pkt_cnt; ++i) {
1383 char ptype;
1384
1385 stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_VIDEO;
1386 stream->rx_frames[i].timestamp.u64 = frm_ts;
1387 stream->rx_frames[i].bit_info = 0;
1388
1389 /* We use jbuf_peek_frame() as it will returns the pointer of
1390 * the payload (no buffer and memcpy needed), just as we need.
1391 */
1392 pjmedia_jbuf_peek_frame(stream->jb, i,
1393 (const void**)&stream->rx_frames[i].buf,
1394 &stream->rx_frames[i].size, &ptype,
1395 NULL, NULL, &frm_last_seq);
1396
1397 if (ptype != PJMEDIA_JB_NORMAL_FRAME) {
1398 /* Packet lost, must set payload to NULL and keep going */
1399 stream->rx_frames[i].buf = NULL;
1400 stream->rx_frames[i].size = 0;
1401 stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_NONE;
1402 continue;
1403 }
1404 }
1405
1406 /* Decode */
1407 status = pjmedia_vid_codec_decode(stream->codec, frm_pkt_cnt,
1408 stream->rx_frames,
1409 (unsigned)frame->size, frame);
1410 if (status != PJ_SUCCESS) {
1411 LOGERR_((channel->port.info.name.ptr, status,
1412 "codec decode() error"));
1413 frame->type = PJMEDIA_FRAME_TYPE_NONE;
1414 frame->size = 0;
1415 }
1416
1417 pjmedia_jbuf_remove_frame(stream->jb, frm_pkt_cnt);
1418 }
1419
1420 /* Learn remote frame rate after successful decoding */
1421 if (got_frame && frame->type == PJMEDIA_FRAME_TYPE_VIDEO && frame->size)
1422 {
1423 /* Only check remote frame rate when timestamp is not wrapping and
1424 * sequence is increased by 1.
1425 */
1426 if (frm_ts > stream->last_dec_ts &&
1427 frm_first_seq - stream->last_dec_seq == 1)
1428 {
1429 pj_uint32_t ts_diff;
1430 pjmedia_ratio new_fps;
1431
1432 ts_diff = frm_ts - stream->last_dec_ts;
1433
1434 /* Calculate new FPS based on RTP timestamp diff */
1435 if (stream->info.codec_info.clock_rate % ts_diff == 0) {
1436 new_fps.num = stream->info.codec_info.clock_rate/ts_diff;
1437 new_fps.denum = 1;
1438 } else {
1439 new_fps.num = stream->info.codec_info.clock_rate;
1440 new_fps.denum = ts_diff;
1441 }
1442
1443 /* Only apply the new FPS when it is >0, <=100, and increasing */
1444 if (new_fps.num/new_fps.denum <= 100 &&
1445 new_fps.num/new_fps.denum > 0 &&
1446 new_fps.num*1.0/new_fps.denum >
1447 stream->dec_max_fps.num*1.0/stream->dec_max_fps.denum)
1448 {
1449 pjmedia_video_format_detail *vfd;
1450 vfd = pjmedia_format_get_video_format_detail(
1451 &channel->port.info.fmt, PJ_TRUE);
1452
1453 /* Update FPS in channel & stream info */
1454 vfd->fps = new_fps;
1455 stream->info.codec_param->dec_fmt.det.vid.fps = new_fps;
1456
1457 /* Update the decoding delay */
1458 {
1459 pjmedia_jb_state jb_state;
1460 pjmedia_jbuf_get_state(stream->jb, &jb_state);
1461
1462 stream->dec_delay_cnt =
1463 ((PJMEDIA_VID_STREAM_DECODE_MIN_DELAY_MSEC *
1464 vfd->fps.num) +
1465 (1000 * vfd->fps.denum) - 1) /
1466 (1000 * vfd->fps.denum);
1467 if (stream->dec_delay_cnt < 1)
1468 stream->dec_delay_cnt = 1;
1469 if (stream->dec_delay_cnt > jb_state.max_count * 4/5)
1470 stream->dec_delay_cnt = jb_state.max_count * 4/5;
1471 }
1472
1473 /* Publish PJMEDIA_EVENT_FMT_CHANGED event */
1474 {
1475 pjmedia_event *event = &stream->fmt_event;
1476
1477 /* Update max fps of decoding dir */
1478 stream->dec_max_fps = vfd->fps;
1479
1480 /* Use the buffered format changed event:
1481 * - just update the framerate if there is pending event,
1482 * - otherwise, init the whole event.
1483 */
1484 if (stream->fmt_event.type != PJMEDIA_EVENT_NONE) {
1485 event->data.fmt_changed.new_fmt.det.vid.fps = vfd->fps;
1486 } else {
1487 pjmedia_event_init(event, PJMEDIA_EVENT_FMT_CHANGED,
1488 &frame->timestamp, &channel->port);
1489 event->data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
1490 pj_memcpy(&event->data.fmt_changed.new_fmt,
1491 &stream->info.codec_param->dec_fmt,
1492 sizeof(pjmedia_format));
1493 }
1494 }
1495 }
1496 }
1497
1498 /* Update last frame seq and timestamp */
1499 stream->last_dec_seq = frm_last_seq;
1500 stream->last_dec_ts = frm_ts;
1501 }
1502
1503 return got_frame ? PJ_SUCCESS : PJ_ENOTFOUND;
1504 }
1505
1506
get_frame(pjmedia_port * port,pjmedia_frame * frame)1507 static pj_status_t get_frame(pjmedia_port *port,
1508 pjmedia_frame *frame)
1509 {
1510 pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata;
1511 pjmedia_vid_channel *channel = stream->dec;
1512
1513 /* Return no frame is channel is paused */
1514 if (channel->paused) {
1515 frame->type = PJMEDIA_FRAME_TYPE_NONE;
1516 frame->size = 0;
1517 return PJ_SUCCESS;
1518 }
1519
1520 /* Report pending events. Do not publish the event while holding the
1521 * jb_mutex as that would lead to deadlock. It should be safe to
1522 * operate on fmt_event without the mutex because format change normally
1523 * would only occur once during the start of the media.
1524 */
1525 if (stream->fmt_event.type != PJMEDIA_EVENT_NONE) {
1526 pjmedia_event_fmt_changed_data *fmt_chg_data;
1527
1528 fmt_chg_data = &stream->fmt_event.data.fmt_changed;
1529
1530 /* Update stream info and decoding channel port info */
1531 if (fmt_chg_data->dir == PJMEDIA_DIR_DECODING) {
1532 pjmedia_format_copy(&stream->info.codec_param->dec_fmt,
1533 &fmt_chg_data->new_fmt);
1534 pjmedia_format_copy(&stream->dec->port.info.fmt,
1535 &fmt_chg_data->new_fmt);
1536
1537 /* Override the framerate to be 1.5x higher in the event
1538 * for the renderer.
1539 */
1540 fmt_chg_data->new_fmt.det.vid.fps.num *= 3;
1541 fmt_chg_data->new_fmt.det.vid.fps.num /= 2;
1542 } else {
1543 pjmedia_format_copy(&stream->info.codec_param->enc_fmt,
1544 &fmt_chg_data->new_fmt);
1545 pjmedia_format_copy(&stream->enc->port.info.fmt,
1546 &fmt_chg_data->new_fmt);
1547 }
1548
1549 dump_port_info(fmt_chg_data->dir==PJMEDIA_DIR_DECODING ?
1550 stream->dec : stream->enc,
1551 "changed");
1552
1553 pjmedia_event_publish(NULL, port, &stream->fmt_event,
1554 PJMEDIA_EVENT_PUBLISH_POST_EVENT);
1555
1556 stream->fmt_event.type = PJMEDIA_EVENT_NONE;
1557 }
1558
1559 if (stream->miss_keyframe_event.type != PJMEDIA_EVENT_NONE) {
1560 pjmedia_event_publish(NULL, port, &stream->miss_keyframe_event,
1561 PJMEDIA_EVENT_PUBLISH_POST_EVENT);
1562 stream->miss_keyframe_event.type = PJMEDIA_EVENT_NONE;
1563 }
1564
1565 pj_mutex_lock( stream->jb_mutex );
1566
1567 if (stream->dec_frame.size == 0) {
1568 /* Don't have frame in buffer, try to decode one */
1569 if (decode_frame(stream, frame) != PJ_SUCCESS) {
1570 frame->type = PJMEDIA_FRAME_TYPE_NONE;
1571 frame->size = 0;
1572 }
1573 } else {
1574 if (frame->size < stream->dec_frame.size) {
1575 PJ_LOG(4,(stream->dec->port.info.name.ptr,
1576 "Error: not enough buffer for decoded frame "
1577 "(supplied=%d, required=%d)",
1578 (int)frame->size, (int)stream->dec_frame.size));
1579 frame->type = PJMEDIA_FRAME_TYPE_NONE;
1580 frame->size = 0;
1581 } else {
1582 frame->type = stream->dec_frame.type;
1583 frame->timestamp = stream->dec_frame.timestamp;
1584 frame->size = stream->dec_frame.size;
1585 pj_memcpy(frame->buf, stream->dec_frame.buf, frame->size);
1586 }
1587
1588 stream->dec_frame.size = 0;
1589 }
1590
1591 pj_mutex_unlock( stream->jb_mutex );
1592
1593 return PJ_SUCCESS;
1594 }
1595
1596 /*
1597 * Create media channel.
1598 */
create_channel(pj_pool_t * pool,pjmedia_vid_stream * stream,pjmedia_dir dir,unsigned pt,const pjmedia_vid_stream_info * info,pjmedia_vid_channel ** p_channel)1599 static pj_status_t create_channel( pj_pool_t *pool,
1600 pjmedia_vid_stream *stream,
1601 pjmedia_dir dir,
1602 unsigned pt,
1603 const pjmedia_vid_stream_info *info,
1604 pjmedia_vid_channel **p_channel)
1605 {
1606 enum { M = 32 };
1607 pjmedia_vid_channel *channel;
1608 pj_status_t status;
1609 unsigned min_out_pkt_size;
1610 pj_str_t name;
1611 const char *type_name;
1612 pjmedia_format *fmt;
1613 char fourcc_name[5];
1614 pjmedia_port_info *pi;
1615
1616 pj_assert(info->type == PJMEDIA_TYPE_VIDEO);
1617 pj_assert(dir == PJMEDIA_DIR_DECODING || dir == PJMEDIA_DIR_ENCODING);
1618
1619 /* Allocate memory for channel descriptor */
1620 channel = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_channel);
1621 PJ_ASSERT_RETURN(channel != NULL, PJ_ENOMEM);
1622
1623 /* Init vars */
1624 if (dir==PJMEDIA_DIR_DECODING) {
1625 type_name = "vstdec";
1626 fmt = &info->codec_param->dec_fmt;
1627 } else {
1628 type_name = "vstenc";
1629 fmt = &info->codec_param->enc_fmt;
1630 }
1631 name.ptr = (char*) pj_pool_alloc(pool, M);
1632 name.slen = pj_ansi_snprintf(name.ptr, M, "%s%p", type_name, stream);
1633 pi = &channel->port.info;
1634
1635 /* Init channel info. */
1636 channel->stream = stream;
1637 channel->dir = dir;
1638 channel->paused = 1;
1639 channel->pt = pt;
1640
1641 /* Allocate buffer for outgoing packet. */
1642 if (dir == PJMEDIA_DIR_ENCODING) {
1643 channel->buf_size = sizeof(pjmedia_rtp_hdr) + stream->frame_size;
1644
1645 /* It should big enough to hold (minimally) RTCP SR with an SDES. */
1646 min_out_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
1647 sizeof(pjmedia_rtcp_common) +
1648 (4 + (unsigned)stream->cname.slen) +
1649 32;
1650
1651 if (channel->buf_size < min_out_pkt_size)
1652 channel->buf_size = min_out_pkt_size;
1653
1654 channel->buf = pj_pool_alloc(pool, channel->buf_size);
1655 PJ_ASSERT_RETURN(channel->buf != NULL, PJ_ENOMEM);
1656 }
1657
1658 /* Create RTP and RTCP sessions: */
1659 {
1660 pjmedia_rtp_session_setting settings;
1661
1662 settings.flags = (pj_uint8_t)((info->rtp_seq_ts_set << 2) |
1663 (info->has_rem_ssrc << 4) | 3);
1664 settings.default_pt = pt;
1665 settings.sender_ssrc = info->ssrc;
1666 settings.peer_ssrc = info->rem_ssrc;
1667 settings.seq = info->rtp_seq;
1668 settings.ts = info->rtp_ts;
1669 status = pjmedia_rtp_session_init2(&channel->rtp, settings);
1670 }
1671 if (status != PJ_SUCCESS)
1672 return status;
1673
1674 /* Init port. */
1675 pjmedia_port_info_init2(pi, &name, SIGNATURE, dir, fmt);
1676 if (dir == PJMEDIA_DIR_DECODING) {
1677 channel->port.get_frame = &get_frame;
1678 } else {
1679 pi->fmt.id = info->codec_param->dec_fmt.id;
1680 channel->port.put_frame = &put_frame;
1681 }
1682
1683 /* Init port. */
1684 channel->port.port_data.pdata = stream;
1685
1686 PJ_LOG(5, (name.ptr,
1687 "%s channel created %dx%d %s%s%.*s %d/%d(~%d)fps",
1688 (dir==PJMEDIA_DIR_ENCODING?"Encoding":"Decoding"),
1689 pi->fmt.det.vid.size.w, pi->fmt.det.vid.size.h,
1690 pjmedia_fourcc_name(pi->fmt.id, fourcc_name),
1691 (dir==PJMEDIA_DIR_ENCODING?"->":"<-"),
1692 info->codec_info.encoding_name.slen,
1693 info->codec_info.encoding_name.ptr,
1694 pi->fmt.det.vid.fps.num, pi->fmt.det.vid.fps.denum,
1695 pi->fmt.det.vid.fps.num/pi->fmt.det.vid.fps.denum));
1696
1697 /* Done. */
1698 *p_channel = channel;
1699 return PJ_SUCCESS;
1700 }
1701
1702
1703 /*
1704 * Create stream.
1705 */
pjmedia_vid_stream_create(pjmedia_endpt * endpt,pj_pool_t * pool,pjmedia_vid_stream_info * info,pjmedia_transport * tp,void * user_data,pjmedia_vid_stream ** p_stream)1706 PJ_DEF(pj_status_t) pjmedia_vid_stream_create(
1707 pjmedia_endpt *endpt,
1708 pj_pool_t *pool,
1709 pjmedia_vid_stream_info *info,
1710 pjmedia_transport *tp,
1711 void *user_data,
1712 pjmedia_vid_stream **p_stream)
1713 {
1714 enum { M = 32 };
1715 pj_pool_t *own_pool = NULL;
1716 pjmedia_vid_stream *stream;
1717 unsigned jb_init, jb_max, jb_min_pre, jb_max_pre;
1718 int frm_ptime, chunks_per_frm;
1719 pjmedia_video_format_detail *vfd_enc, *vfd_dec;
1720 char *p;
1721 pj_status_t status;
1722 pjmedia_transport_attach_param att_param;
1723
1724 if (!pool) {
1725 own_pool = pjmedia_endpt_create_pool( endpt, "vstrm%p",
1726 PJMEDIA_VSTREAM_SIZE,
1727 PJMEDIA_VSTREAM_INC);
1728 PJ_ASSERT_RETURN(own_pool != NULL, PJ_ENOMEM);
1729 pool = own_pool;
1730 }
1731
1732 /* Allocate stream */
1733 stream = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_stream);
1734 PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
1735 stream->own_pool = own_pool;
1736
1737 /* Get codec manager */
1738 stream->codec_mgr = pjmedia_vid_codec_mgr_instance();
1739 PJ_ASSERT_RETURN(stream->codec_mgr, PJMEDIA_CODEC_EFAILED);
1740
1741 /* Init stream/port name */
1742 stream->name.ptr = (char*) pj_pool_alloc(pool, M);
1743 stream->name.slen = pj_ansi_snprintf(stream->name.ptr, M,
1744 "vstrm%p", stream);
1745
1746 /* Create and initialize codec: */
1747 status = pjmedia_vid_codec_mgr_alloc_codec(stream->codec_mgr,
1748 &info->codec_info,
1749 &stream->codec);
1750 if (status != PJ_SUCCESS)
1751 goto err_cleanup;
1752
1753 /* Get codec param: */
1754 if (!info->codec_param) {
1755 pjmedia_vid_codec_param def_param;
1756
1757 status = pjmedia_vid_codec_mgr_get_default_param(stream->codec_mgr,
1758 &info->codec_info,
1759 &def_param);
1760 if (status != PJ_SUCCESS)
1761 goto err_cleanup;
1762
1763 info->codec_param = pjmedia_vid_codec_param_clone(pool, &def_param);
1764 pj_assert(info->codec_param);
1765 }
1766
1767 /* Init codec param and adjust MTU */
1768 info->codec_param->dir = info->dir;
1769 info->codec_param->enc_mtu -= (sizeof(pjmedia_rtp_hdr) +
1770 PJMEDIA_STREAM_RESV_PAYLOAD_LEN);
1771 if (info->codec_param->enc_mtu > PJMEDIA_MAX_MTU)
1772 info->codec_param->enc_mtu = PJMEDIA_MAX_MTU;
1773
1774 /* Packet size estimation for decoding direction */
1775 vfd_enc = pjmedia_format_get_video_format_detail(
1776 &info->codec_param->enc_fmt, PJ_TRUE);
1777 vfd_dec = pjmedia_format_get_video_format_detail(
1778 &info->codec_param->dec_fmt, PJ_TRUE);
1779
1780 /* Init stream: */
1781 stream->endpt = endpt;
1782 stream->dir = info->dir;
1783 stream->user_data = user_data;
1784 stream->rtcp_interval = PJMEDIA_RTCP_INTERVAL + pj_rand()%1000 - 500;
1785 stream->rtcp_sdes_bye_disabled = info->rtcp_sdes_bye_disabled;
1786
1787 stream->jb_last_frm = PJMEDIA_JB_NORMAL_FRAME;
1788
1789 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
1790 stream->use_ka = info->use_ka;
1791 stream->start_ka_count = info->ka_cfg.start_count;
1792 stream->start_ka_interval = info->ka_cfg.start_interval;
1793 #endif
1794 stream->num_keyframe = info->sk_cfg.count;
1795
1796 stream->cname = info->cname;
1797 if (stream->cname.slen == 0) {
1798 /* Build random RTCP CNAME. CNAME has user@host format */
1799 stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
1800 pj_create_random_string(p, 5);
1801 p += 5;
1802 *p++ = '@'; *p++ = 'p'; *p++ = 'j';
1803 pj_create_random_string(p, 6);
1804 p += 6;
1805 *p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
1806 stream->cname.slen = p - stream->cname.ptr;
1807 }
1808
1809 /* Create mutex to protect jitter buffer: */
1810
1811 status = pj_mutex_create_simple(pool, NULL, &stream->jb_mutex);
1812 if (status != PJ_SUCCESS)
1813 goto err_cleanup;
1814
1815 /* Init and open the codec. */
1816 status = pjmedia_vid_codec_init(stream->codec, pool);
1817 if (status != PJ_SUCCESS)
1818 goto err_cleanup;
1819 status = pjmedia_vid_codec_open(stream->codec, info->codec_param);
1820 if (status != PJ_SUCCESS)
1821 goto err_cleanup;
1822
1823 /* Subscribe to codec events */
1824 pjmedia_event_subscribe(NULL, &stream_event_cb, stream,
1825 stream->codec);
1826
1827 /* Estimate the maximum frame size */
1828 stream->frame_size = vfd_enc->size.w * vfd_enc->size.h * 4;
1829
1830 #if 0
1831 stream->frame_size = vfd_enc->max_bps/8 * vfd_enc->fps.denum /
1832 vfd_enc->fps.num;
1833
1834 /* As the maximum frame_size is not represented directly by maximum bps
1835 * (which includes intra and predicted frames), let's increase the
1836 * frame size value for safety.
1837 */
1838 stream->frame_size <<= 4;
1839 #endif
1840
1841 /* Validate the frame size */
1842 if (stream->frame_size == 0 ||
1843 stream->frame_size > PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE)
1844 {
1845 stream->frame_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
1846 }
1847
1848 /* Get frame length in timestamp unit */
1849 stream->frame_ts_len = info->codec_info.clock_rate *
1850 vfd_enc->fps.denum / vfd_enc->fps.num;
1851
1852 /* Initialize send rate states */
1853 pj_get_timestamp_freq(&stream->ts_freq);
1854 if (info->rc_cfg.bandwidth == 0)
1855 info->rc_cfg.bandwidth = vfd_enc->max_bps;
1856
1857 /* For simple blocking, need to have bandwidth large enough, otherwise
1858 * we can slow down the transmission too much
1859 */
1860 if (info->rc_cfg.method==PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING &&
1861 info->rc_cfg.bandwidth < vfd_enc->avg_bps * 3)
1862 {
1863 info->rc_cfg.bandwidth = vfd_enc->avg_bps * 3;
1864 }
1865
1866 /* Override the initial framerate in the decoding direction. This initial
1867 * value will be used by the renderer to configure its clock, and setting
1868 * it to a bit higher value can avoid the possibility of high latency
1869 * caused by clock drift (remote encoder clock runs slightly faster than
1870 * local renderer clock) or video setup lag. Note that the actual framerate
1871 * will be continuously calculated based on the incoming RTP timestamps.
1872 */
1873 vfd_dec->fps.num = vfd_dec->fps.num * 3 / 2;
1874 stream->dec_max_fps = vfd_dec->fps;
1875
1876 /* Create decoder channel */
1877 status = create_channel( pool, stream, PJMEDIA_DIR_DECODING,
1878 info->rx_pt, info, &stream->dec);
1879 if (status != PJ_SUCCESS)
1880 goto err_cleanup;
1881
1882 /* Create encoder channel */
1883 status = create_channel( pool, stream, PJMEDIA_DIR_ENCODING,
1884 info->tx_pt, info, &stream->enc);
1885 if (status != PJ_SUCCESS)
1886 goto err_cleanup;
1887
1888 /* Create temporary buffer for immediate decoding */
1889 stream->dec_max_size = vfd_dec->size.w * vfd_dec->size.h * 4;
1890 stream->dec_frame.buf = pj_pool_alloc(pool, stream->dec_max_size);
1891
1892 /* Init jitter buffer parameters: */
1893 frm_ptime = 1000 * vfd_enc->fps.denum / vfd_enc->fps.num;
1894 chunks_per_frm = stream->frame_size / PJMEDIA_MAX_MRU;
1895 if (chunks_per_frm < MIN_CHUNKS_PER_FRM)
1896 chunks_per_frm = MIN_CHUNKS_PER_FRM;
1897
1898 /* JB max count, default 500ms */
1899 if (info->jb_max >= frm_ptime)
1900 jb_max = info->jb_max * chunks_per_frm / frm_ptime;
1901 else
1902 jb_max = 500 * chunks_per_frm / frm_ptime;
1903
1904 /* JB min prefetch, default 1 frame */
1905 if (info->jb_min_pre >= frm_ptime)
1906 jb_min_pre = info->jb_min_pre * chunks_per_frm / frm_ptime;
1907 else
1908 jb_min_pre = 1;
1909
1910 /* JB max prefetch, default 4/5 JB max count */
1911 if (info->jb_max_pre >= frm_ptime)
1912 jb_max_pre = info->jb_max_pre * chunks_per_frm / frm_ptime;
1913 else
1914 jb_max_pre = jb_max * 4 / 5;
1915
1916 /* JB init prefetch, default 0 */
1917 if (info->jb_init >= frm_ptime)
1918 jb_init = info->jb_init * chunks_per_frm / frm_ptime;
1919 else
1920 jb_init = 0;
1921
1922 /* Calculate the decoding delay (in number of frames) based on FPS */
1923 stream->dec_delay_cnt = ((PJMEDIA_VID_STREAM_DECODE_MIN_DELAY_MSEC *
1924 vfd_dec->fps.num) +
1925 (1000 * vfd_dec->fps.denum) - 1) /
1926 (1000 * vfd_dec->fps.denum);
1927 if (stream->dec_delay_cnt < 1)
1928 stream->dec_delay_cnt = 1;
1929 if (stream->dec_delay_cnt > jb_max * 4/5)
1930 stream->dec_delay_cnt = jb_max * 4/5;
1931
1932 /* Allocate array for temporary storage for assembly of incoming
1933 * frames. Add more just in case.
1934 */
1935 stream->rx_frame_cnt = chunks_per_frm * 2;
1936 stream->rx_frames = pj_pool_calloc(pool, stream->rx_frame_cnt,
1937 sizeof(stream->rx_frames[0]));
1938
1939 /* Create jitter buffer */
1940 status = pjmedia_jbuf_create(pool, &stream->dec->port.info.name,
1941 PJMEDIA_MAX_MRU,
1942 1000 * vfd_enc->fps.denum / vfd_enc->fps.num,
1943 jb_max, &stream->jb);
1944 if (status != PJ_SUCCESS)
1945 goto err_cleanup;
1946
1947
1948 /* Set up jitter buffer */
1949 pjmedia_jbuf_set_adaptive(stream->jb, jb_init, jb_min_pre, jb_max_pre);
1950 pjmedia_jbuf_set_discard(stream->jb, PJMEDIA_JB_DISCARD_NONE);
1951
1952 /* Init RTCP session: */
1953 {
1954 pjmedia_rtcp_session_setting rtcp_setting;
1955
1956 pjmedia_rtcp_session_setting_default(&rtcp_setting);
1957 rtcp_setting.name = stream->name.ptr;
1958 rtcp_setting.ssrc = info->ssrc;
1959 rtcp_setting.rtp_ts_base = pj_ntohl(stream->enc->rtp.out_hdr.ts);
1960 rtcp_setting.clock_rate = info->codec_info.clock_rate;
1961 rtcp_setting.samples_per_frame = 1;
1962
1963 pjmedia_rtcp_init2(&stream->rtcp, &rtcp_setting);
1964
1965 /* Subscribe to RTCP events */
1966 pjmedia_event_subscribe(NULL, &stream_event_cb, stream,
1967 &stream->rtcp);
1968 }
1969
1970 /* Allocate outgoing RTCP buffer, should be enough to hold SR/RR, SDES,
1971 * BYE, Feedback, and XR.
1972 */
1973 stream->out_rtcp_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
1974 sizeof(pjmedia_rtcp_common) +
1975 (4 + (unsigned)stream->cname.slen) +
1976 32 + 32;
1977 if (stream->out_rtcp_pkt_size > PJMEDIA_MAX_MTU)
1978 stream->out_rtcp_pkt_size = PJMEDIA_MAX_MTU;
1979
1980 stream->out_rtcp_pkt = pj_pool_alloc(pool, stream->out_rtcp_pkt_size);
1981 pj_bzero(&att_param, sizeof(att_param));
1982 att_param.stream = stream;
1983 att_param.media_type = PJMEDIA_TYPE_VIDEO;
1984 att_param.user_data = stream;
1985 pj_sockaddr_cp(&att_param.rem_addr, &info->rem_addr);
1986 pj_sockaddr_cp(&stream->rem_rtp_addr, &info->rem_addr);
1987 if (info->rtcp_mux) {
1988 pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_addr);
1989 } else if (pj_sockaddr_has_addr(&info->rem_rtcp.addr)) {
1990 pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);
1991 }
1992 att_param.addr_len = pj_sockaddr_get_len(&info->rem_addr);
1993 att_param.rtp_cb2 = &on_rx_rtp;
1994 att_param.rtcp_cb = &on_rx_rtcp;
1995
1996 /* Only attach transport when stream is ready. */
1997 status = pjmedia_transport_attach2(tp, &att_param);
1998 if (status != PJ_SUCCESS)
1999 goto err_cleanup;
2000
2001 stream->transport = tp;
2002
2003 /* Send RTCP SDES */
2004 if (!stream->rtcp_sdes_bye_disabled) {
2005 pjmedia_vid_stream_send_rtcp_sdes(stream);
2006 }
2007
2008 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
2009 /* NAT hole punching by sending KA packet via RTP transport. */
2010 if (stream->use_ka)
2011 send_keep_alive_packet(stream);
2012 #endif
2013
2014 #if TRACE_JB
2015 {
2016 char trace_name[PJ_MAXPATH];
2017 pj_ssize_t len;
2018
2019 pj_ansi_snprintf(trace_name, sizeof(trace_name),
2020 TRACE_JB_PATH_PREFIX "%s.csv",
2021 channel->port.info.name.ptr);
2022 status = pj_file_open(pool, trace_name, PJ_O_RDWR,
2023 &stream->trace_jb_fd);
2024 if (status != PJ_SUCCESS) {
2025 stream->trace_jb_fd = TRACE_JB_INVALID_FD;
2026 PJ_PERROR(3,(THIS_FILE, status,
2027 "Failed creating RTP trace file '%s'",
2028 trace_name));
2029 } else {
2030 stream->trace_jb_buf = (char*)pj_pool_alloc(pool, PJ_LOG_MAX_SIZE);
2031
2032 /* Print column header */
2033 len = pj_ansi_snprintf(stream->trace_jb_buf, PJ_LOG_MAX_SIZE,
2034 "Time, Operation, Size, Frame Count, "
2035 "Frame type, RTP Seq, RTP TS, RTP M, "
2036 "JB size, JB burst level, JB prefetch\n");
2037 if (len < 1 || len >= PJ_LOG_MAX_SIZE)
2038 len = PJ_LOG_MAX_SIZE - 1;
2039 pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
2040 pj_file_flush(stream->trace_jb_fd);
2041 }
2042 }
2043 #endif
2044
2045 /* Save the stream info */
2046 pj_memcpy(&stream->info, info, sizeof(*info));
2047 stream->info.codec_param = pjmedia_vid_codec_param_clone(
2048 pool, info->codec_param);
2049 pjmedia_rtcp_fb_info_dup(pool, &stream->info.loc_rtcp_fb,
2050 &info->loc_rtcp_fb);
2051 pjmedia_rtcp_fb_info_dup(pool, &stream->info.rem_rtcp_fb,
2052 &info->rem_rtcp_fb);
2053
2054 /* Check if we should send RTCP-FB */
2055 if (stream->info.rem_rtcp_fb.cap_count) {
2056 pjmedia_rtcp_fb_info *rfi = &stream->info.rem_rtcp_fb;
2057 unsigned i;
2058
2059 for (i = 0; i < rfi->cap_count; ++i) {
2060 if (rfi->caps[i].type == PJMEDIA_RTCP_FB_NACK) {
2061 if (rfi->caps[i].param.slen == 0) {
2062 stream->send_rtcp_fb_nack = PJ_TRUE;
2063 PJ_LOG(5,(stream->name.ptr, "Send RTCP-FB generic NACK"));
2064 } else if (pj_stricmp2(&rfi->caps[i].param, "pli")==0) {
2065 stream->send_rtcp_fb_pli = PJ_TRUE;
2066 PJ_LOG(5,(stream->name.ptr, "Send RTCP-FB PLI"));
2067 }
2068 }
2069 }
2070 }
2071
2072 /* Check if we should process incoming RTCP-FB */
2073 stream->rtcp_fb_nack_cap_idx = -1;
2074 stream->rtcp_fb_pli_cap_idx = -1;
2075 if (stream->info.loc_rtcp_fb.cap_count) {
2076 pjmedia_rtcp_fb_info *lfi = &stream->info.loc_rtcp_fb;
2077 unsigned i;
2078
2079 for (i = 0; i < lfi->cap_count; ++i) {
2080 if (lfi->caps[i].type == PJMEDIA_RTCP_FB_NACK) {
2081 if (lfi->caps[i].param.slen == 0) {
2082 stream->rtcp_fb_nack_cap_idx = i;
2083 PJ_LOG(5,(stream->name.ptr,
2084 "Receive RTCP-FB generic NACK"));
2085 } else if (pj_stricmp2(&lfi->caps[i].param, "pli")==0) {
2086 stream->rtcp_fb_pli_cap_idx = i;
2087 PJ_LOG(5,(stream->name.ptr, "Receive RTCP-FB PLI"));
2088 }
2089 }
2090 }
2091 }
2092
2093 /* Success! */
2094 *p_stream = stream;
2095
2096 PJ_LOG(5,(THIS_FILE, "Video stream %s created", stream->name.ptr));
2097
2098 return PJ_SUCCESS;
2099
2100 err_cleanup:
2101 pjmedia_vid_stream_destroy(stream);
2102 return status;
2103 }
2104
2105
2106 /*
2107 * Destroy stream.
2108 */
pjmedia_vid_stream_destroy(pjmedia_vid_stream * stream)2109 PJ_DEF(pj_status_t) pjmedia_vid_stream_destroy( pjmedia_vid_stream *stream )
2110 {
2111 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
2112
2113 #if TRACE_RC
2114 {
2115 unsigned total_time;
2116
2117 total_time = pj_elapsed_msec(&stream->tx_start, &stream->tx_end);
2118 PJ_LOG(5, (stream->name.ptr,
2119 "RC stat: pkt_cnt=%.2f/image, sleep=%.2fms/s, fps=%.2f",
2120 stream->rc_total_pkt*1.0/stream->rc_total_img,
2121 stream->rc_total_sleep*1000.0/total_time,
2122 stream->rc_total_img*1000.0/total_time));
2123 }
2124 #endif
2125
2126 /* Unsubscribe events from RTCP */
2127 pjmedia_event_unsubscribe(NULL, &stream_event_cb, stream, &stream->rtcp);
2128
2129 /* Send RTCP BYE (also SDES) */
2130 if (stream->transport && !stream->rtcp_sdes_bye_disabled) {
2131 send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE, PJ_FALSE);
2132 }
2133
2134 /* Detach from transport
2135 * MUST NOT hold stream mutex while detaching from transport, as
2136 * it may cause deadlock. See ticket #460 for the details.
2137 */
2138 if (stream->transport) {
2139 pjmedia_transport_detach(stream->transport, stream);
2140 stream->transport = NULL;
2141 }
2142
2143 /* This function may be called when stream is partly initialized. */
2144 if (stream->jb_mutex)
2145 pj_mutex_lock(stream->jb_mutex);
2146
2147
2148 /* Free codec. */
2149 if (stream->codec) {
2150 pjmedia_event_unsubscribe(NULL, &stream_event_cb, stream,
2151 stream->codec);
2152 pjmedia_vid_codec_close(stream->codec);
2153 pjmedia_vid_codec_mgr_dealloc_codec(stream->codec_mgr, stream->codec);
2154 stream->codec = NULL;
2155 }
2156
2157 /* Free mutex */
2158
2159 if (stream->jb_mutex) {
2160 pj_mutex_destroy(stream->jb_mutex);
2161 stream->jb_mutex = NULL;
2162 }
2163
2164 /* Destroy jitter buffer */
2165 if (stream->jb) {
2166 pjmedia_jbuf_destroy(stream->jb);
2167 stream->jb = NULL;
2168 }
2169
2170 #if TRACE_JB
2171 if (TRACE_JB_OPENED(stream)) {
2172 pj_file_close(stream->trace_jb_fd);
2173 stream->trace_jb_fd = TRACE_JB_INVALID_FD;
2174 }
2175 #endif
2176
2177 pj_pool_safe_release(&stream->own_pool);
2178
2179 return PJ_SUCCESS;
2180 }
2181
2182
2183 /*
2184 * Get the port interface.
2185 */
pjmedia_vid_stream_get_port(pjmedia_vid_stream * stream,pjmedia_dir dir,pjmedia_port ** p_port)2186 PJ_DEF(pj_status_t) pjmedia_vid_stream_get_port(pjmedia_vid_stream *stream,
2187 pjmedia_dir dir,
2188 pjmedia_port **p_port )
2189 {
2190 PJ_ASSERT_RETURN(dir==PJMEDIA_DIR_ENCODING || dir==PJMEDIA_DIR_DECODING,
2191 PJ_EINVAL);
2192
2193 if (dir == PJMEDIA_DIR_ENCODING)
2194 *p_port = &stream->enc->port;
2195 else
2196 *p_port = &stream->dec->port;
2197
2198 return PJ_SUCCESS;
2199 }
2200
2201
2202 /*
2203 * Get the transport object
2204 */
pjmedia_vid_stream_get_transport(pjmedia_vid_stream * st)2205 PJ_DEF(pjmedia_transport*) pjmedia_vid_stream_get_transport(
2206 pjmedia_vid_stream *st)
2207 {
2208 return st->transport;
2209 }
2210
2211
2212 /*
2213 * Get stream statistics.
2214 */
pjmedia_vid_stream_get_stat(const pjmedia_vid_stream * stream,pjmedia_rtcp_stat * stat)2215 PJ_DEF(pj_status_t) pjmedia_vid_stream_get_stat(
2216 const pjmedia_vid_stream *stream,
2217 pjmedia_rtcp_stat *stat)
2218 {
2219 PJ_ASSERT_RETURN(stream && stat, PJ_EINVAL);
2220
2221 pj_memcpy(stat, &stream->rtcp.stat, sizeof(pjmedia_rtcp_stat));
2222 return PJ_SUCCESS;
2223 }
2224
2225
2226 /*
2227 * Reset the stream statistics in the middle of a stream session.
2228 */
pjmedia_vid_stream_reset_stat(pjmedia_vid_stream * stream)2229 PJ_DEF(pj_status_t) pjmedia_vid_stream_reset_stat(pjmedia_vid_stream *stream)
2230 {
2231 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2232
2233 pjmedia_rtcp_init_stat(&stream->rtcp.stat);
2234
2235 return PJ_SUCCESS;
2236 }
2237
2238
2239 /*
2240 * Get jitter buffer state.
2241 */
pjmedia_vid_stream_get_stat_jbuf(const pjmedia_vid_stream * stream,pjmedia_jb_state * state)2242 PJ_DEF(pj_status_t) pjmedia_vid_stream_get_stat_jbuf(
2243 const pjmedia_vid_stream *stream,
2244 pjmedia_jb_state *state)
2245 {
2246 PJ_ASSERT_RETURN(stream && state, PJ_EINVAL);
2247 return pjmedia_jbuf_get_state(stream->jb, state);
2248 }
2249
2250
2251 /*
2252 * Get the stream info.
2253 */
pjmedia_vid_stream_get_info(const pjmedia_vid_stream * stream,pjmedia_vid_stream_info * info)2254 PJ_DEF(pj_status_t) pjmedia_vid_stream_get_info(
2255 const pjmedia_vid_stream *stream,
2256 pjmedia_vid_stream_info *info)
2257 {
2258 PJ_ASSERT_RETURN(stream && info, PJ_EINVAL);
2259 pj_memcpy(info, &stream->info, sizeof(*info));
2260 return PJ_SUCCESS;
2261 }
2262
2263
2264 /*
2265 * Start stream.
2266 */
pjmedia_vid_stream_start(pjmedia_vid_stream * stream)2267 PJ_DEF(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
2268 {
2269
2270 PJ_ASSERT_RETURN(stream && stream->enc && stream->dec, PJ_EINVALIDOP);
2271
2272 if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) {
2273 stream->enc->paused = 0;
2274 //pjmedia_snd_stream_start(stream->enc->snd_stream);
2275 PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream started"));
2276 } else {
2277 PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
2278 }
2279
2280 if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) {
2281 stream->dec->paused = 0;
2282 //pjmedia_snd_stream_start(stream->dec->snd_stream);
2283 PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream started"));
2284 } else {
2285 PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
2286 }
2287
2288 return PJ_SUCCESS;
2289 }
2290
2291
2292 /*
2293 * Check status.
2294 */
pjmedia_vid_stream_is_running(pjmedia_vid_stream * stream,pjmedia_dir dir)2295 PJ_DEF(pj_bool_t) pjmedia_vid_stream_is_running(pjmedia_vid_stream *stream,
2296 pjmedia_dir dir)
2297 {
2298 pj_bool_t is_running = PJ_TRUE;
2299
2300 PJ_ASSERT_RETURN(stream, PJ_FALSE);
2301
2302 if (dir & PJMEDIA_DIR_ENCODING) {
2303 is_running &= (stream->enc && !stream->enc->paused);
2304 }
2305
2306 if (dir & PJMEDIA_DIR_DECODING) {
2307 is_running &= (stream->dec && !stream->dec->paused);
2308 }
2309
2310 return is_running;
2311 }
2312
2313 /*
2314 * Pause stream.
2315 */
pjmedia_vid_stream_pause(pjmedia_vid_stream * stream,pjmedia_dir dir)2316 PJ_DEF(pj_status_t) pjmedia_vid_stream_pause(pjmedia_vid_stream *stream,
2317 pjmedia_dir dir)
2318 {
2319 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2320
2321 if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
2322 stream->enc->paused = 1;
2323 PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
2324 }
2325
2326 if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
2327 stream->dec->paused = 1;
2328
2329 /* Also reset jitter buffer */
2330 pj_mutex_lock( stream->jb_mutex );
2331 pjmedia_jbuf_reset(stream->jb);
2332 pj_mutex_unlock( stream->jb_mutex );
2333
2334 PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
2335 }
2336
2337 return PJ_SUCCESS;
2338 }
2339
2340
2341 /*
2342 * Resume stream
2343 */
pjmedia_vid_stream_resume(pjmedia_vid_stream * stream,pjmedia_dir dir)2344 PJ_DEF(pj_status_t) pjmedia_vid_stream_resume(pjmedia_vid_stream *stream,
2345 pjmedia_dir dir)
2346 {
2347 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2348
2349 if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
2350 stream->enc->paused = 0;
2351 stream->force_keyframe = PJ_TRUE;
2352 PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream resumed"));
2353 }
2354
2355 if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
2356 stream->dec->paused = 0;
2357 stream->last_dec_seq = 0;
2358 PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream resumed"));
2359 }
2360
2361 return PJ_SUCCESS;
2362 }
2363
2364
2365 /*
2366 * Force stream to send video keyframe.
2367 */
pjmedia_vid_stream_send_keyframe(pjmedia_vid_stream * stream)2368 PJ_DEF(pj_status_t) pjmedia_vid_stream_send_keyframe(
2369 pjmedia_vid_stream *stream)
2370 {
2371 pj_timestamp now;
2372
2373 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2374
2375 if (!pjmedia_vid_stream_is_running(stream, PJMEDIA_DIR_ENCODING))
2376 return PJ_EINVALIDOP;
2377
2378 pj_get_timestamp(&now);
2379 if (pj_elapsed_msec(&stream->last_keyframe_tx, &now) <
2380 PJMEDIA_VID_STREAM_MIN_KEYFRAME_INTERVAL_MSEC)
2381 {
2382 return PJ_ETOOMANY;
2383 }
2384
2385 stream->force_keyframe = PJ_TRUE;
2386
2387 return PJ_SUCCESS;
2388 }
2389
2390
2391 /*
2392 * Send RTCP SDES.
2393 */
pjmedia_vid_stream_send_rtcp_sdes(pjmedia_vid_stream * stream)2394 PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_sdes(
2395 pjmedia_vid_stream *stream)
2396 {
2397 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2398
2399 return send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE, PJ_FALSE);
2400 }
2401
2402
2403 /*
2404 * Send RTCP BYE.
2405 */
pjmedia_vid_stream_send_rtcp_bye(pjmedia_vid_stream * stream)2406 PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_bye(
2407 pjmedia_vid_stream *stream)
2408 {
2409 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2410
2411 if (stream->enc && stream->transport) {
2412 return send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE, PJ_FALSE);
2413 }
2414
2415 return PJ_SUCCESS;
2416 }
2417
2418
2419 /*
2420 * Send RTCP PLI.
2421 */
pjmedia_vid_stream_send_rtcp_pli(pjmedia_vid_stream * stream)2422 PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_pli(
2423 pjmedia_vid_stream *stream)
2424 {
2425 PJ_ASSERT_RETURN(stream, PJ_EINVAL);
2426
2427 if (stream->transport) {
2428 return send_rtcp(stream, PJ_FALSE, PJ_FALSE, PJ_FALSE, PJ_TRUE);
2429 }
2430
2431 return PJ_SUCCESS;
2432 }
2433
2434
2435 /*
2436 * Initialize the video stream rate control with default settings.
2437 */
2438 PJ_DEF(void)
pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config * cfg)2439 pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config *cfg)
2440 {
2441 pj_bzero(cfg, sizeof(*cfg));
2442 cfg->method = PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING;
2443 }
2444
2445
2446 /*
2447 * Initialize the video stream send keyframe with default settings.
2448 */
2449 PJ_DEF(void)
pjmedia_vid_stream_sk_config_default(pjmedia_vid_stream_sk_config * cfg)2450 pjmedia_vid_stream_sk_config_default(pjmedia_vid_stream_sk_config *cfg)
2451 {
2452 pj_bzero(cfg, sizeof(*cfg));
2453 cfg->count = PJMEDIA_VID_STREAM_START_KEYFRAME_CNT;
2454 cfg->interval = PJMEDIA_VID_STREAM_START_KEYFRAME_INTERVAL_MSEC;
2455 }
2456
2457
2458 /**
2459 * Get RTP session information from video stream.
2460 */
2461 PJ_DEF(pj_status_t)
pjmedia_vid_stream_get_rtp_session_info(pjmedia_vid_stream * stream,pjmedia_stream_rtp_sess_info * session_info)2462 pjmedia_vid_stream_get_rtp_session_info(pjmedia_vid_stream *stream,
2463 pjmedia_stream_rtp_sess_info *session_info)
2464 {
2465 session_info->rx_rtp = &stream->dec->rtp;
2466 session_info->tx_rtp = &stream->enc->rtp;
2467 session_info->rtcp = &stream->rtcp;
2468 return PJ_SUCCESS;
2469 }
2470
2471
2472 #endif /* PJMEDIA_HAS_VIDEO */
2473