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