1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Component */
17 /** */
18 /** Real Time Transport Protocol (RTP) */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_RTP_SENDER_SOURCE_CODE
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #include "nx_api.h"
29 #include "nx_ip.h"
30 #ifdef FEATURE_NX_IPV6
31 #include "nx_ipv6.h"
32 #endif /* FEATURE_NX_IPV6 */
33 #include "nx_udp.h"
34 #include "nx_rtp_sender.h"
35
36
37 /* Define JPEG quantization table parameters. */
38 #define NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_MAX_NUM (4)
39 #define NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH (64)
40
41 /* Define H264 parameters. */
42 #define NX_RTP_SENDER_H264_NRI_MASK_BITS (0x60) /* The mask bits of relative transport priority. */
43 #define NX_RTP_SENDER_H264_TYPE_MASK_BITS (0x1F) /* The mask bits of NAL unit type.*/
44 #define NX_RTP_SENDER_H264_TYPE_SEI (6)
45 #define NX_RTP_SENDER_H264_TYPE_SPS (7)
46 #define NX_RTP_SENDER_H264_TYPE_PPS (8)
47 #define NX_RTP_SENDER_H264_TYPE_FU_A (28)
48 #define NX_RTP_SENDER_H264_FU_A_S_MASK_BIT (0x80)
49 #define NX_RTP_SENDER_H264_FU_A_E_MASK_BIT (0x40)
50
51 /* Define AAC parameters. */
52 #define NX_RTP_SENDER_AAC_HBR_MODE_MAX_DATA_SIZE (8191) /* RFC 3640, p25, section 3.3.6. */
53 #define NX_RTP_SENDER_AAC_FRAME_DATA_LENGTH_HIGH_BITS_MASK (0x1FE0)
54 #define NX_RTP_SENDER_AAC_FRAME_DATA_LENGTH_LOW_BITS_MASK (0x1F)
55
56 /* Declare rtp sender internal functions */
57 static UINT _nx_rtp_sender_cleanup(NX_RTP_SENDER *rtp_sender);
58 static UINT _nx_rtp_sender_session_find(NX_RTP_SENDER *rtp_sender, UINT ssrc, NX_RTP_SESSION **session);
59 static VOID _nx_rtp_sender_session_link(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session);
60 static UINT _nx_rtp_sender_session_unlink(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session);
61
62 static UINT _nx_rtcp_packet_process(NX_RTP_SENDER *rtp_sender, NX_PACKET *packet_ptr);
63 static UINT _nx_rtcp_packet_rr_process(NX_RTP_SENDER *rtp_sender, NX_RTCP_HEADER *header);
64 static UINT _nx_rtcp_packet_sdes_process(NX_RTP_SENDER *rtp_sender, NX_RTCP_HEADER *header);
65 static UINT _nx_rtcp_sr_data_append(NX_RTP_SESSION *session, NX_PACKET *packet_ptr);
66 static UINT _nx_rtcp_sdes_data_append(NX_RTP_SESSION *session, NX_PACKET *packet_ptr);
67 static UINT _nx_rtcp_packet_send(NX_RTP_SESSION *session);
68 static VOID _nx_rtcp_packet_receive_notify(NX_UDP_SOCKET *socket_ptr);
69
70
71 /**************************************************************************/
72 /* */
73 /* FUNCTION RELEASE */
74 /* */
75 /* _nxe_rtp_sender_create PORTABLE C */
76 /* 6.3.0 */
77 /* AUTHOR */
78 /* */
79 /* Haiqing Zhao, Microsoft Corporation */
80 /* */
81 /* DESCRIPTION */
82 /* */
83 /* This function checks errors in the RTP sender create function call. */
84 /* */
85 /* INPUT */
86 /* */
87 /* rtp_sender Pointer to RTP Sender instance */
88 /* ip_ptr Pointer to IP instance */
89 /* pool_ptr Pointer to the packet pool */
90 /* cname Pointer to the name string */
91 /* shown in rtcp SDES report */
92 /* cname_length The length of the name string */
93 /* */
94 /* OUTPUT */
95 /* */
96 /* status Completion status */
97 /* NX_PTR_ERROR Invalid pointer input */
98 /* */
99 /* CALLS */
100 /* */
101 /* _nx_rtp_sender_create Create rtp sender */
102 /* */
103 /* CALLED BY */
104 /* */
105 /* Application Code */
106 /* */
107 /* RELEASE HISTORY */
108 /* */
109 /* DATE NAME DESCRIPTION */
110 /* */
111 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
112 /* */
113 /**************************************************************************/
_nxe_rtp_sender_create(NX_RTP_SENDER * rtp_sender,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,CHAR * cname,UCHAR cname_length)114 UINT _nxe_rtp_sender_create(NX_RTP_SENDER *rtp_sender, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, CHAR *cname, UCHAR cname_length)
115 {
116
117 UINT status;
118
119
120 /* Check for invalid input pointers. */
121 if ((rtp_sender == NX_NULL) || (ip_ptr == NX_NULL) || (pool_ptr == NX_NULL) || (rtp_sender -> nx_rtp_sender_id == NX_RTP_SENDER_ID))
122 {
123 return(NX_PTR_ERROR);
124 }
125
126 /* Call actual RTP sender create service. */
127 status = _nx_rtp_sender_create(rtp_sender, ip_ptr, pool_ptr, cname, cname_length);
128
129 /* Return status. */
130 return(status);
131 }
132
133 /**************************************************************************/
134 /* */
135 /* FUNCTION RELEASE */
136 /* */
137 /* _nx_rtp_sender_create PORTABLE C */
138 /* 6.3.0 */
139 /* AUTHOR */
140 /* */
141 /* Haiqing Zhao, Microsoft Corporation */
142 /* */
143 /* DESCRIPTION */
144 /* */
145 /* This function creates a RTP sender on the specified IP. */
146 /* */
147 /* INPUT */
148 /* */
149 /* rtp_sender Pointer to RTP Sender instance */
150 /* ip_ptr Pointer to IP instance */
151 /* pool_ptr Pointer to the packet pool */
152 /* cname Pointer to the name string */
153 /* shown in rtcp SDES report */
154 /* cname_length The length of the name string */
155 /* */
156 /* OUTPUT */
157 /* */
158 /* status Completion status */
159 /* */
160 /* CALLS */
161 /* */
162 /* memset Reset memory */
163 /* tx_mutex_create Create RTP sender mutex */
164 /* tx_mutex_delete Delete RTP sender mutex */
165 /* nx_udp_socket_create Create RTP sender UDP socket */
166 /* nx_udp_socket_delete Delete RTP sender UDP socket */
167 /* nx_udp_free_port_find Find a free UDP port for RTP */
168 /* or RTCP socket */
169 /* nx_udp_socket_bind Bind a UDP port for RTP */
170 /* or RTCP socket */
171 /* nx_udp_socket_unbind Unbind UDP port for RTP socket */
172 /* _nx_rtp_sender_cleanup Clean-up resources */
173 /* nx_udp_socket_receive_notify Set callback function for UDP */
174 /* data receive notify */
175 /* */
176 /* CALLED BY */
177 /* */
178 /* Application Code */
179 /* */
180 /* RELEASE HISTORY */
181 /* */
182 /* DATE NAME DESCRIPTION */
183 /* */
184 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
185 /* */
186 /**************************************************************************/
_nx_rtp_sender_create(NX_RTP_SENDER * rtp_sender,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,CHAR * cname,UCHAR cname_length)187 UINT _nx_rtp_sender_create(NX_RTP_SENDER *rtp_sender, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, CHAR *cname, UCHAR cname_length)
188 {
189
190 UINT status;
191 UINT free_port;
192
193
194 /* Reset the rtp_sender data structure. */
195 memset(rtp_sender, 0, sizeof(NX_RTP_SENDER));
196
197 /* Create mutex protection. */
198 status = tx_mutex_create(&(rtp_sender -> nx_rtp_sender_protection), "RTP sender protection", TX_INHERIT);
199 if (status)
200 {
201 return(status);
202 }
203
204 /* Create RTP UDP socket. */
205 status = nx_udp_socket_create(ip_ptr, &(rtp_sender -> nx_rtp_sender_rtp_socket), "RTP Socket",
206 NX_RTP_SENDER_TYPE_OF_SERVICE, NX_RTP_SENDER_FRAGMENT_OPTION,
207 NX_RTP_SENDER_TIME_TO_LIVE, NX_RTP_SENDER_QUEUE_DEPTH);
208 if (status)
209 {
210
211 /* Delete already created resources and return error status. */
212 tx_mutex_delete(&(rtp_sender -> nx_rtp_sender_protection));
213 return(status);
214 }
215
216 /* Create RTCP UDP socket. */
217 status = nx_udp_socket_create(ip_ptr, &(rtp_sender -> nx_rtp_sender_rtcp_socket), "RTCP Socket",
218 NX_RTP_SENDER_TYPE_OF_SERVICE, NX_RTP_SENDER_FRAGMENT_OPTION,
219 NX_RTP_SENDER_TIME_TO_LIVE, NX_RTP_SENDER_QUEUE_DEPTH);
220 if (status)
221 {
222
223 /* Delete already created resources and return error status. */
224 tx_mutex_delete(&(rtp_sender -> nx_rtp_sender_protection));
225 nx_udp_socket_delete(&(rtp_sender -> nx_rtp_sender_rtp_socket));
226 return(status);
227 }
228
229 /* Start from the suggested default port number. */
230 rtp_sender -> nx_rtp_sender_rtp_port = NX_RTP_SENDER_INITIAL_RTP_PORT;
231
232 while (1)
233 {
234
235 /* Try to find an available port for RTP. */
236 status = nx_udp_free_port_find(ip_ptr, rtp_sender -> nx_rtp_sender_rtp_port, &free_port);
237 if (status)
238 {
239 break;
240 }
241 else if (rtp_sender -> nx_rtp_sender_rtp_port > free_port)
242 {
243
244 /* Return since there will be no even number port obtained. */
245 status = NX_NO_FREE_PORTS;
246 break;
247 }
248
249 /* Check if free_port is an odd number. */
250 if ((free_port & 1) != 0)
251 {
252
253 /* Check if the found free port reaches maximum. */
254 if (free_port == NX_MAX_PORT)
255 {
256
257 /* Return since there will be no even number port obtained. */
258 status = NX_NO_FREE_PORTS;
259 break;
260 }
261
262 /* Free UDP port is not the one we expected for RTP. Move to the next port number and try again. */
263 rtp_sender -> nx_rtp_sender_rtp_port = (USHORT)(free_port + 1);
264 }
265 else
266 {
267
268 /* Set RTP port. */
269 rtp_sender -> nx_rtp_sender_rtp_port = (USHORT)free_port;
270 }
271
272 /* Both RTP and RTCP ports are available. Now do a real RTP bind. */
273 status = nx_udp_socket_bind(&(rtp_sender -> nx_rtp_sender_rtp_socket), rtp_sender -> nx_rtp_sender_rtp_port, NX_NO_WAIT);
274 if (status == NX_SUCCESS)
275 {
276
277 /* RTP socket was bound successfully. Now try RTCP socket. */
278
279 /* Set RTCP port to be the next odd port of RTP port and bind. */
280 rtp_sender -> nx_rtp_sender_rtcp_port = (USHORT)(rtp_sender -> nx_rtp_sender_rtp_port + 1);
281 status = nx_udp_socket_bind(&(rtp_sender -> nx_rtp_sender_rtcp_socket), rtp_sender -> nx_rtp_sender_rtcp_port, NX_NO_WAIT);
282 if (status == NX_SUCCESS)
283 {
284
285 /* Jump out since both ports are found. */
286 break;
287 }
288
289 /* RTCP port is unavailable. Unbind the RTP port and try again. */
290 nx_udp_socket_unbind(&(rtp_sender -> nx_rtp_sender_rtp_socket));
291 }
292
293 /* Move and check next possible even port. */
294 rtp_sender -> nx_rtp_sender_rtp_port = (USHORT)(rtp_sender -> nx_rtp_sender_rtp_port + 2);
295 if (rtp_sender -> nx_rtp_sender_rtp_port == 0)
296 {
297 status = NX_NO_FREE_PORTS;
298 break;
299 }
300 }
301
302 /* Clean-up generated resources if fails to find a rtp/rtcp port pair. */
303 if (status)
304 {
305 _nx_rtp_sender_cleanup(rtp_sender);
306 return(status);
307 }
308
309 /* Store pool pointer. */
310 rtp_sender -> nx_rtp_sender_packet_pool_ptr = pool_ptr;
311
312 /* Set application-specific filed indicating the socket is associated with this RTP sender instance. */
313 rtp_sender -> nx_rtp_sender_rtcp_socket.nx_udp_socket_reserved_ptr = (void *)rtp_sender;
314
315 /* Install RTCP callback. */
316 nx_udp_socket_receive_notify(&(rtp_sender -> nx_rtp_sender_rtcp_socket), _nx_rtcp_packet_receive_notify);
317
318 /* Update rtp variables. */
319 rtp_sender -> nx_rtp_sender_id = NX_RTP_SENDER_ID;
320 rtp_sender -> nx_rtp_sender_ip_ptr = ip_ptr;
321 rtp_sender -> nx_rtp_sender_cname = cname;
322 rtp_sender -> nx_rtp_sender_cname_length = cname_length;
323
324 return(NX_SUCCESS);
325 }
326
327 /**************************************************************************/
328 /* */
329 /* FUNCTION RELEASE */
330 /* */
331 /* _nxe_rtp_sender_delete PORTABLE C */
332 /* 6.3.0 */
333 /* AUTHOR */
334 /* */
335 /* Haiqing Zhao, Microsoft Corporation */
336 /* */
337 /* DESCRIPTION */
338 /* */
339 /* This function checks errors in the RTP sender delete function call. */
340 /* */
341 /* INPUT */
342 /* */
343 /* rtp_sender Pointer to RTP Sender instance */
344 /* */
345 /* OUTPUT */
346 /* */
347 /* status Completion status */
348 /* NX_PTR_ERROR Invalid pointer input */
349 /* */
350 /* CALLS */
351 /* */
352 /* _nx_rtp_sender_delete Delete RTP sender */
353 /* */
354 /* CALLED BY */
355 /* */
356 /* Application Code */
357 /* */
358 /* RELEASE HISTORY */
359 /* */
360 /* DATE NAME DESCRIPTION */
361 /* */
362 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
363 /* */
364 /**************************************************************************/
_nxe_rtp_sender_delete(NX_RTP_SENDER * rtp_sender)365 UINT _nxe_rtp_sender_delete(NX_RTP_SENDER *rtp_sender)
366 {
367
368 UINT status;
369
370
371 /* Check for invalid input pointers. */
372 if ((rtp_sender == NX_NULL) || (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID))
373 {
374 return(NX_PTR_ERROR);
375 }
376
377 /* Call actual RTP sender delete service. */
378 status = _nx_rtp_sender_delete(rtp_sender);
379
380 /* Return status. */
381 return(status);
382 }
383
384 /**************************************************************************/
385 /* */
386 /* FUNCTION RELEASE */
387 /* */
388 /* _nx_rtp_sender_delete PORTABLE C */
389 /* 6.3.0 */
390 /* AUTHOR */
391 /* */
392 /* Haiqing Zhao, Microsoft Corporation */
393 /* */
394 /* DESCRIPTION */
395 /* */
396 /* This function deletes a previous created RTP sender */
397 /* */
398 /* INPUT */
399 /* */
400 /* rtp_sender Pointer to RTP Sender instance */
401 /* */
402 /* OUTPUT */
403 /* */
404 /* status Completion status */
405 /* NX_DELETE_ERROR Fail to delete RTP sender */
406 /* */
407 /* CALLS */
408 /* */
409 /* tx_mutex_get Obtain protection mutex */
410 /* tx_mutex_put Release protection mutex */
411 /* _nx_rtp_sender_cleanup Clean-up resources */
412 /* */
413 /* CALLED BY */
414 /* */
415 /* Application Code */
416 /* */
417 /* RELEASE HISTORY */
418 /* */
419 /* DATE NAME DESCRIPTION */
420 /* */
421 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
422 /* */
423 /**************************************************************************/
_nx_rtp_sender_delete(NX_RTP_SENDER * rtp_sender)424 UINT _nx_rtp_sender_delete(NX_RTP_SENDER *rtp_sender)
425 {
426
427 /* Obtain the mutex. */
428 tx_mutex_get(&(rtp_sender -> nx_rtp_sender_protection), TX_WAIT_FOREVER);
429
430 /* rtp sender can only be deleted when all sessions have been deleted. */
431 if (rtp_sender -> nx_rtp_sender_session_created_ptr)
432 {
433
434 /* Release the mutex and return error status. */
435 tx_mutex_put(&(rtp_sender -> nx_rtp_sender_protection));
436 return(NX_DELETE_ERROR);
437 }
438
439 /* Set the id to be 0 to make sure other api functions (except create) cannot execute after deleting. */
440 rtp_sender -> nx_rtp_sender_id = 0;
441
442 /* Release the mutex */
443 tx_mutex_put(&(rtp_sender -> nx_rtp_sender_protection));
444
445 /* Clean-up all generated resources. */
446 _nx_rtp_sender_cleanup(rtp_sender);
447
448 return(NX_SUCCESS);
449 }
450
451 /**************************************************************************/
452 /* */
453 /* FUNCTION RELEASE */
454 /* */
455 /* _nxe_rtp_sender_port_get PORTABLE C */
456 /* 6.3.0 */
457 /* AUTHOR */
458 /* */
459 /* Haiqing Zhao, Microsoft Corporation */
460 /* */
461 /* DESCRIPTION */
462 /* */
463 /* This function checks errors in the RTP sender port get function */
464 /* call. */
465 /* */
466 /* INPUT */
467 /* */
468 /* rtp_sender Pointer to RTP Sender instance */
469 /* rtp_port Pointer to returned RTP port */
470 /* rtcp_port Pointer to returned RTCP port */
471 /* */
472 /* OUTPUT */
473 /* */
474 /* status Completion status */
475 /* NX_PTR_ERROR Invalid pointer input */
476 /* */
477 /* CALLS */
478 /* */
479 /* _nx_rtp_sender_port_get Get the bound RTP port and */
480 /* RTCP port in RTP sender */
481 /* */
482 /* CALLED BY */
483 /* */
484 /* Application Code */
485 /* */
486 /* RELEASE HISTORY */
487 /* */
488 /* DATE NAME DESCRIPTION */
489 /* */
490 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
491 /* */
492 /**************************************************************************/
_nxe_rtp_sender_port_get(NX_RTP_SENDER * rtp_sender,UINT * rtp_port,UINT * rtcp_port)493 UINT _nxe_rtp_sender_port_get(NX_RTP_SENDER *rtp_sender, UINT *rtp_port, UINT *rtcp_port)
494 {
495
496 UINT status;
497
498
499 /* Check for invalid input pointers. */
500 if ((rtp_sender == NX_NULL) || (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID) ||
501 (rtp_port == NX_NULL) || (rtcp_port == NX_NULL))
502 {
503 return(NX_PTR_ERROR);
504 }
505
506 /* Call actual RTP sender port get service. */
507 status = _nx_rtp_sender_port_get(rtp_sender, rtp_port, rtcp_port);
508
509 /* Return status. */
510 return(status);
511 }
512
513 /**************************************************************************/
514 /* */
515 /* FUNCTION RELEASE */
516 /* */
517 /* _nx_rtp_sender_port_get PORTABLE C */
518 /* 6.3.0 */
519 /* AUTHOR */
520 /* */
521 /* Haiqing Zhao, Microsoft Corporation */
522 /* */
523 /* DESCRIPTION */
524 /* */
525 /* This function returns bound RTP and RTCP port pair in RTP sender. */
526 /* */
527 /* INPUT */
528 /* */
529 /* rtp_sender Pointer to RTP Sender instance */
530 /* rtp_port Pointer to returned RTP port */
531 /* rtcp_port Pointer to returned RTCP port */
532 /* */
533 /* OUTPUT */
534 /* */
535 /* NX_SUCCESS Completion status */
536 /* */
537 /* CALLS */
538 /* */
539 /* _nx_rtp_sender_port_get Get the bound RTP port and */
540 /* RTCP port in RTP sender */
541 /* */
542 /* CALLED BY */
543 /* */
544 /* Application Code */
545 /* */
546 /* RELEASE HISTORY */
547 /* */
548 /* DATE NAME DESCRIPTION */
549 /* */
550 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
551 /* */
552 /**************************************************************************/
_nx_rtp_sender_port_get(NX_RTP_SENDER * rtp_sender,UINT * rtp_port,UINT * rtcp_port)553 UINT _nx_rtp_sender_port_get(NX_RTP_SENDER *rtp_sender, UINT *rtp_port, UINT *rtcp_port)
554 {
555
556 /* Set RTP port and RTCP port. */
557 *rtp_port = rtp_sender -> nx_rtp_sender_rtp_port;
558 *rtcp_port = rtp_sender -> nx_rtp_sender_rtcp_port;
559
560 /* All done. Return success code. */
561 return(NX_SUCCESS);
562 }
563
564 /**************************************************************************/
565 /* */
566 /* FUNCTION RELEASE */
567 /* */
568 /* _nxe_rtp_sender_session_create PORTABLE C */
569 /* 6.3.0 */
570 /* AUTHOR */
571 /* */
572 /* Haiqing Zhao, Microsoft Corporation */
573 /* */
574 /* DESCRIPTION */
575 /* */
576 /* This function checks errors in the RTP sender session create */
577 /* function call. */
578 /* */
579 /* INPUT */
580 /* */
581 /* rtp_sender Pointer to RTP Sender instance */
582 /* session Pointer to RTP session */
583 /* payload_type Payload type number */
584 /* interface_index IP interface index */
585 /* receiver_ip_address The receiver's IP address */
586 /* receiver_rtp_port_number The receiver's RTP port */
587 /* receiver_rtcp_port_number The receiver's RTCP port */
588 /* */
589 /* OUTPUT */
590 /* */
591 /* status Completion status */
592 /* NX_PTR_ERROR Invalid pointer input */
593 /* */
594 /* CALLS */
595 /* */
596 /* _nx_rtp_sender_session_create Create RTP session with */
597 /* specific arguments */
598 /* */
599 /* CALLED BY */
600 /* */
601 /* Application Code */
602 /* */
603 /* RELEASE HISTORY */
604 /* */
605 /* DATE NAME DESCRIPTION */
606 /* */
607 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
608 /* */
609 /**************************************************************************/
_nxe_rtp_sender_session_create(NX_RTP_SENDER * rtp_sender,NX_RTP_SESSION * session,ULONG payload_type,UINT interface_index,NXD_ADDRESS * receiver_ip_address,UINT receiver_rtp_port_number,UINT receiver_rtcp_port_number)610 UINT _nxe_rtp_sender_session_create(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session, ULONG payload_type,
611 UINT interface_index, NXD_ADDRESS *receiver_ip_address,
612 UINT receiver_rtp_port_number, UINT receiver_rtcp_port_number)
613 {
614
615 UINT status;
616
617
618 /* Check for invalid input pointers. */
619 if ((rtp_sender == NX_NULL) || (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID) ||
620 (session == NX_NULL) || (session -> nx_rtp_session_id == NX_RTP_SESSION_ID) ||
621 (receiver_ip_address == NX_NULL))
622 {
623 return(NX_PTR_ERROR);
624 }
625
626 if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
627 {
628 return(NX_INVALID_INTERFACE);
629 }
630
631 /* Call actual RTP sender session create service. */
632 status = _nx_rtp_sender_session_create(rtp_sender, session, payload_type,
633 interface_index, receiver_ip_address,
634 receiver_rtp_port_number, receiver_rtcp_port_number);
635
636 /* Return status. */
637 return(status);
638 }
639
640 /**************************************************************************/
641 /* */
642 /* FUNCTION RELEASE */
643 /* */
644 /* _nx_rtp_sender_session_create PORTABLE C */
645 /* 6.3.0 */
646 /* AUTHOR */
647 /* */
648 /* Haiqing Zhao, Microsoft Corporation */
649 /* */
650 /* DESCRIPTION */
651 /* */
652 /* This function creates a RTP session with specific arguments. */
653 /* */
654 /* INPUT */
655 /* */
656 /* rtp_sender Pointer to RTP Sender instance */
657 /* session Pointer to RTP session */
658 /* payload_type Payload type number */
659 /* interface_index IP interface index */
660 /* receiver_ip_address The receiver's IP address */
661 /* receiver_rtp_port_number The receiver's RTP port */
662 /* receiver_rtcp_port_number The receiver's RTCP port */
663 /* */
664 /* OUTPUT */
665 /* */
666 /* NX_SUCCESS Completion status */
667 /* NX_INVALID_PARAMETERS Payload type out of range */
668 /* NX_IP_ADDRESS_ERROR Unsupported IP version */
669 /* */
670 /* CALLS */
671 /* */
672 /* memset Reset memory */
673 /* COPY_IPV6_ADDRESS Make a copy of an IPv6 address */
674 /* NX_RAND Generate a random number */
675 /* tx_mutex_get Obtain protection mutex */
676 /* tx_mutex_put Release protection mutex */
677 /* _nx_rtp_sender_session_link Link the created session into */
678 /* RTP sender control block */
679 /* */
680 /* CALLED BY */
681 /* */
682 /* Application Code */
683 /* */
684 /* RELEASE HISTORY */
685 /* */
686 /* DATE NAME DESCRIPTION */
687 /* */
688 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
689 /* */
690 /**************************************************************************/
_nx_rtp_sender_session_create(NX_RTP_SENDER * rtp_sender,NX_RTP_SESSION * session,ULONG payload_type,UINT interface_index,NXD_ADDRESS * receiver_ip_address,UINT receiver_rtp_port_number,UINT receiver_rtcp_port_number)691 UINT _nx_rtp_sender_session_create(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session, ULONG payload_type,
692 UINT interface_index, NXD_ADDRESS *receiver_ip_address,
693 UINT receiver_rtp_port_number, UINT receiver_rtcp_port_number)
694 {
695
696 /* Check and validate rtp payload type with valid range from 0 to 127 (7 bits). */
697 if (payload_type > 127)
698 {
699 return(NX_INVALID_PARAMETERS);
700 }
701
702 /* Reset rtp session members. */
703 memset(session, 0, sizeof(NX_RTP_SESSION));
704
705 /* Record peer's ip address and rtp/rtcp port pair. */
706 session -> nx_rtp_session_peer_ip_address.nxd_ip_version = receiver_ip_address -> nxd_ip_version;
707
708 /* Store the receiver's ip interface index into the session. */
709 session -> nx_rtp_session_interface_index = interface_index;
710
711 if (receiver_ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
712 {
713 #ifndef NX_DISABLE_IPV4
714 session -> nx_rtp_session_peer_ip_address.nxd_ip_address.v4 = receiver_ip_address -> nxd_ip_address.v4;
715
716 /* Compute the maximum frame packet length based on mtu size. */
717 session -> nx_rtp_session_max_packet_size = rtp_sender -> nx_rtp_sender_ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_mtu_size
718 - sizeof(NX_UDP_HEADER) - NX_RTP_HEADER_LENGTH - sizeof(NX_IPV4_HEADER);
719 #else
720 return(NX_IP_ADDRESS_ERROR);
721 #endif /* NX_DISABLE_IPV4 */
722 }
723 else if (receiver_ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
724 {
725 #ifdef FEATURE_NX_IPV6
726 COPY_IPV6_ADDRESS(receiver_ip_address -> nxd_ip_address.v6, session -> nx_rtp_session_peer_ip_address.nxd_ip_address.v6);
727
728 /* Compute the maximum frame packet length based on mtu size. */
729 session -> nx_rtp_session_max_packet_size = rtp_sender -> nx_rtp_sender_ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_mtu_size
730 - sizeof(NX_UDP_HEADER) - NX_RTP_HEADER_LENGTH - sizeof(NX_IPV6_HEADER);
731 #else
732 return(NX_IP_ADDRESS_ERROR);
733 #endif /* #ifdef FEATURE_NX_IPV6 */
734 }
735 else
736 {
737 return(NX_IP_ADDRESS_ERROR);
738 }
739
740 /* Store the receiver's rtp/rtcp ports number. */
741 session -> nx_rtp_session_peer_rtp_port = (USHORT)receiver_rtp_port_number;
742 session -> nx_rtp_session_peer_rtcp_port = (USHORT)receiver_rtcp_port_number;
743
744 /* Record session payload type. */
745 session -> nx_rtp_session_payload_type = (UCHAR)(payload_type);
746
747 /* Generate random values for the ssrc and sequence number. */
748 session -> nx_rtp_session_ssrc = (ULONG)NX_RAND();
749 session -> nx_rtp_session_sequence_number = (USHORT)NX_RAND();
750
751 /* Record the rtp sender pointer in the session. */
752 session -> nx_rtp_sender = rtp_sender;
753
754 /* Obtain the mutex */
755 tx_mutex_get(&(rtp_sender -> nx_rtp_sender_protection), TX_WAIT_FOREVER);
756
757 _nx_rtp_sender_session_link(rtp_sender, session);
758
759 /* Release the mutex and return success status. */
760 tx_mutex_put(&(rtp_sender -> nx_rtp_sender_protection));
761
762 /* Set session magic number to indicate the session is created successfully. */
763 session -> nx_rtp_session_id = NX_RTP_SESSION_ID;
764
765 return(NX_SUCCESS);
766 }
767
768 /**************************************************************************/
769 /* */
770 /* FUNCTION RELEASE */
771 /* */
772 /* _nxe_rtp_sender_session_delete PORTABLE C */
773 /* 6.3.0 */
774 /* AUTHOR */
775 /* */
776 /* Haiqing Zhao, Microsoft Corporation */
777 /* */
778 /* DESCRIPTION */
779 /* */
780 /* This function checks errors in the rtp sender session delete */
781 /* function call. */
782 /* */
783 /* INPUT */
784 /* */
785 /* session Pointer to RTP session */
786 /* */
787 /* OUTPUT */
788 /* */
789 /* status Completion status */
790 /* NX_PTR_ERROR Invalid pointer input */
791 /* */
792 /* CALLS */
793 /* */
794 /* _nx_rtp_sender_session_delete Delete RTP session */
795 /* */
796 /* CALLED BY */
797 /* */
798 /* Application Code */
799 /* */
800 /* RELEASE HISTORY */
801 /* */
802 /* DATE NAME DESCRIPTION */
803 /* */
804 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
805 /* */
806 /**************************************************************************/
_nxe_rtp_sender_session_delete(NX_RTP_SESSION * session)807 UINT _nxe_rtp_sender_session_delete(NX_RTP_SESSION *session)
808 {
809
810 UINT status;
811
812
813 /* Check for invalid input pointers. */
814 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID))
815 {
816 return(NX_PTR_ERROR);
817 }
818
819 /* Call actual RTP sender session delete service. */
820 status = _nx_rtp_sender_session_delete(session);
821
822 /* Return status. */
823 return(status);
824 }
825
826 /**************************************************************************/
827 /* */
828 /* FUNCTION RELEASE */
829 /* */
830 /* _nx_rtp_sender_session_delete PORTABLE C */
831 /* 6.3.0 */
832 /* AUTHOR */
833 /* */
834 /* Haiqing Zhao, Microsoft Corporation */
835 /* */
836 /* DESCRIPTION */
837 /* */
838 /* This function deletes a RTP session. */
839 /* */
840 /* INPUT */
841 /* */
842 /* session Pointer to RTP session */
843 /* */
844 /* OUTPUT */
845 /* */
846 /* NX_SUCCESS Completion status */
847 /* */
848 /* CALLS */
849 /* */
850 /* tx_mutex_get Obtain protection mutex */
851 /* tx_mutex_put Release protection mutex */
852 /* _nx_rtp_sender_session_unlink Unlink the session from */
853 /* RTP sender control block */
854 /* */
855 /* CALLED BY */
856 /* */
857 /* Application Code */
858 /* */
859 /* RELEASE HISTORY */
860 /* */
861 /* DATE NAME DESCRIPTION */
862 /* */
863 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
864 /* */
865 /**************************************************************************/
_nx_rtp_sender_session_delete(NX_RTP_SESSION * session)866 UINT _nx_rtp_sender_session_delete(NX_RTP_SESSION *session)
867 {
868
869 /* Reset the rtp session id. */
870 session -> nx_rtp_session_id = 0;
871
872 /* Obtain the mutex. */
873 tx_mutex_get(&(session -> nx_rtp_sender -> nx_rtp_sender_protection), TX_WAIT_FOREVER);
874
875 _nx_rtp_sender_session_unlink(session -> nx_rtp_sender, session);
876
877 /* Release the mutex and return success status. */
878 tx_mutex_put(&(session -> nx_rtp_sender -> nx_rtp_sender_protection));
879 return(NX_SUCCESS);
880 }
881
882 /**************************************************************************/
883 /* */
884 /* FUNCTION RELEASE */
885 /* */
886 /* _nxe_rtp_sender_rtcp_receiver_report_callback_set PORTABLE C */
887 /* 6.3.0 */
888 /* AUTHOR */
889 /* */
890 /* Ting Zhu, Microsoft Corporation */
891 /* */
892 /* DESCRIPTION */
893 /* */
894 /* This function checks errors in rtcp receiver report callback set */
895 /* function call. */
896 /* */
897 /* INPUT */
898 /* */
899 /* rtp_sender Pointer to RTP sender */
900 /* rtcp_rr_cb Application specified */
901 /* callback function */
902 /* */
903 /* OUTPUT */
904 /* */
905 /* status Completion status */
906 /* */
907 /* CALLS */
908 /* */
909 /* _nx_rtp_sender_rtcp_receiver_report_callback_set */
910 /* Set RTCP RR packet receive */
911 /* notify function */
912 /* */
913 /* CALLED BY */
914 /* */
915 /* Application Code */
916 /* */
917 /* RELEASE HISTORY */
918 /* */
919 /* DATE NAME DESCRIPTION */
920 /* */
921 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
922 /* */
923 /**************************************************************************/
_nxe_rtp_sender_rtcp_receiver_report_callback_set(NX_RTP_SENDER * rtp_sender,UINT (* rtcp_rr_cb)(NX_RTP_SESSION *,NX_RTCP_RECEIVER_REPORT *))924 UINT _nxe_rtp_sender_rtcp_receiver_report_callback_set(NX_RTP_SENDER *rtp_sender, UINT (*rtcp_rr_cb)(NX_RTP_SESSION *, NX_RTCP_RECEIVER_REPORT *))
925 {
926
927 UINT status;
928
929
930 /* Validate user input parameter. */
931 if ((rtp_sender == NX_NULL) || (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID))
932 {
933 return(NX_PTR_ERROR);
934 }
935
936 /* Call actual RTP sender rtcp receiver report callback service. */
937 status = _nx_rtp_sender_rtcp_receiver_report_callback_set(rtp_sender, rtcp_rr_cb);
938
939 /* Return status. */
940 return(status);
941 }
942
943 /**************************************************************************/
944 /* */
945 /* FUNCTION RELEASE */
946 /* */
947 /* _nx_rtp_sender_rtcp_receiver_report_callback_set PORTABLE C */
948 /* 6.3.0 */
949 /* AUTHOR */
950 /* */
951 /* Ting Zhu, Microsoft Corporation */
952 /* */
953 /* DESCRIPTION */
954 /* */
955 /* This function sets a callback routine for RTCP RR packet receive */
956 /* notification. If a NULL pointer is supplied the receive notify */
957 /* function is disabled. Note that this callback function is invoked */
958 /* from the IP thread, Application shall not block the thread. */
959 /* */
960 /* INPUT */
961 /* */
962 /* rtp_sender Pointer to RTP sender */
963 /* rtcp_rr_cb Application specified */
964 /* callback function */
965 /* */
966 /* OUTPUT */
967 /* */
968 /* status Completion status */
969 /* */
970 /* CALLS */
971 /* */
972 /* None */
973 /* */
974 /* CALLED BY */
975 /* */
976 /* Application Code */
977 /* */
978 /* RELEASE HISTORY */
979 /* */
980 /* DATE NAME DESCRIPTION */
981 /* */
982 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
983 /* */
984 /**************************************************************************/
_nx_rtp_sender_rtcp_receiver_report_callback_set(NX_RTP_SENDER * rtp_sender,UINT (* rtcp_rr_cb)(NX_RTP_SESSION *,NX_RTCP_RECEIVER_REPORT *))985 UINT _nx_rtp_sender_rtcp_receiver_report_callback_set(NX_RTP_SENDER *rtp_sender, UINT (*rtcp_rr_cb)(NX_RTP_SESSION *, NX_RTCP_RECEIVER_REPORT *))
986 {
987 rtp_sender -> nx_rtp_sender_rtcp_receiver_report_cb = rtcp_rr_cb;
988
989 return(NX_SUCCESS);
990 }
991
992 /**************************************************************************/
993 /* */
994 /* FUNCTION RELEASE */
995 /* */
996 /* _nxe_rtp_sender_rtcp_sdes_callback_set PORTABLE C */
997 /* 6.3.0 */
998 /* AUTHOR */
999 /* */
1000 /* Ting Zhu, Microsoft Corporation */
1001 /* */
1002 /* DESCRIPTION */
1003 /* */
1004 /* This function checks errors in rtcp sdes callback set function call.*/
1005 /* */
1006 /* INPUT */
1007 /* */
1008 /* rtp_sender Pointer to RTP sender */
1009 /* rtcp_sdes_cb Application specified */
1010 /* callback function */
1011 /* */
1012 /* OUTPUT */
1013 /* */
1014 /* status Completion status */
1015 /* */
1016 /* CALLS */
1017 /* */
1018 /* _nx_rtp_sender_rtcp_sdes_callback_set Set RTCP SDES packet receive */
1019 /* notify function */
1020 /* */
1021 /* CALLED BY */
1022 /* */
1023 /* Application Code */
1024 /* */
1025 /* RELEASE HISTORY */
1026 /* */
1027 /* DATE NAME DESCRIPTION */
1028 /* */
1029 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
1030 /* */
1031 /**************************************************************************/
_nxe_rtp_sender_rtcp_sdes_callback_set(NX_RTP_SENDER * rtp_sender,UINT (* rtcp_sdes_cb)(NX_RTCP_SDES_INFO *))1032 UINT _nxe_rtp_sender_rtcp_sdes_callback_set(NX_RTP_SENDER *rtp_sender, UINT (*rtcp_sdes_cb)(NX_RTCP_SDES_INFO *))
1033 {
1034
1035 UINT status;
1036
1037
1038 /* Validate user input parameter. */
1039 if ((rtp_sender == NX_NULL) || (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID))
1040 {
1041 return(NX_PTR_ERROR);
1042 }
1043
1044 /* Call actual RTP sender rtcp sdes callback service. */
1045 status = _nx_rtp_sender_rtcp_sdes_callback_set(rtp_sender, rtcp_sdes_cb);
1046
1047 /* Return status. */
1048 return(status);
1049 }
1050
1051 /**************************************************************************/
1052 /* */
1053 /* FUNCTION RELEASE */
1054 /* */
1055 /* _nx_rtp_sender_rtcp_sdes_callback_set PORTABLE C */
1056 /* 6.3.0 */
1057 /* AUTHOR */
1058 /* */
1059 /* Ting Zhu, Microsoft Corporation */
1060 /* */
1061 /* DESCRIPTION */
1062 /* */
1063 /* This function sets a callback routine for RTCP SDES packet receive */
1064 /* notification. If a NULL pointer is supplied the receive notify */
1065 /* function is disabled. Note that this callback function is invoked */
1066 /* from the IP thread, Application shall not block the thread. */
1067 /* */
1068 /* INPUT */
1069 /* */
1070 /* rtp_sender Pointer to RTP sender */
1071 /* rtcp_sdes_cb Application specified */
1072 /* callback function */
1073 /* */
1074 /* OUTPUT */
1075 /* */
1076 /* status Completion status */
1077 /* */
1078 /* CALLS */
1079 /* */
1080 /* None */
1081 /* */
1082 /* CALLED BY */
1083 /* */
1084 /* Application Code */
1085 /* */
1086 /* RELEASE HISTORY */
1087 /* */
1088 /* DATE NAME DESCRIPTION */
1089 /* */
1090 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
1091 /* */
1092 /**************************************************************************/
_nx_rtp_sender_rtcp_sdes_callback_set(NX_RTP_SENDER * rtp_sender,UINT (* rtcp_sdes_cb)(NX_RTCP_SDES_INFO *))1093 UINT _nx_rtp_sender_rtcp_sdes_callback_set(NX_RTP_SENDER *rtp_sender, UINT (*rtcp_sdes_cb)(NX_RTCP_SDES_INFO *))
1094 {
1095 rtp_sender -> nx_rtp_sender_rtcp_sdes_cb = rtcp_sdes_cb;
1096
1097 return(NX_SUCCESS);
1098 }
1099
1100 /**************************************************************************/
1101 /* */
1102 /* FUNCTION RELEASE */
1103 /* */
1104 /* _nxe_rtp_sender_session_packet_allocate PORTABLE C */
1105 /* 6.3.0 */
1106 /* AUTHOR */
1107 /* */
1108 /* Haiqing Zhao, Microsoft Corporation */
1109 /* */
1110 /* DESCRIPTION */
1111 /* */
1112 /* This function checks errors in the RTP sender session packet */
1113 /* allocate function call. */
1114 /* */
1115 /* INPUT */
1116 /* */
1117 /* session Pointer to RTP session */
1118 /* packet_ptr Pointer to allocated packet */
1119 /* wait_option Suspension option */
1120 /* */
1121 /* OUTPUT */
1122 /* */
1123 /* status Completion status */
1124 /* NX_PTR_ERROR Invalid pointer input */
1125 /* */
1126 /* CALLS */
1127 /* */
1128 /* _nx_rtp_sender_session_packet_allocate */
1129 /* Allocate a packet for the user */
1130 /* */
1131 /* CALLED BY */
1132 /* */
1133 /* Application Code */
1134 /* */
1135 /* RELEASE HISTORY */
1136 /* */
1137 /* DATE NAME DESCRIPTION */
1138 /* */
1139 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1140 /* */
1141 /**************************************************************************/
_nxe_rtp_sender_session_packet_allocate(NX_RTP_SESSION * session,NX_PACKET ** packet_ptr,ULONG wait_option)1142 UINT _nxe_rtp_sender_session_packet_allocate(NX_RTP_SESSION *session, NX_PACKET **packet_ptr, ULONG wait_option)
1143 {
1144
1145 UINT status;
1146
1147
1148 /* Check for invalid input pointers. */
1149 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (packet_ptr == NX_NULL))
1150 {
1151 return(NX_PTR_ERROR);
1152 }
1153
1154 /* Call actual RTP sender session packet allocate service. */
1155 status = _nx_rtp_sender_session_packet_allocate(session, packet_ptr, wait_option);
1156
1157 /* Return status. */
1158 return(status);
1159 }
1160
1161 /**************************************************************************/
1162 /* */
1163 /* FUNCTION RELEASE */
1164 /* */
1165 /* _nx_rtp_sender_session_packet_allocate PORTABLE C */
1166 /* 6.3.0 */
1167 /* AUTHOR */
1168 /* */
1169 /* Haiqing Zhao, Microsoft Corporation */
1170 /* */
1171 /* DESCRIPTION */
1172 /* */
1173 /* This function allocate a RTP packet from the packet pool given */
1174 /* by rtp_sender_create, and returns this packet to the user. */
1175 /* */
1176 /* INPUT */
1177 /* */
1178 /* session Pointer to RTP session */
1179 /* packet_ptr Pointer to allocated packet */
1180 /* wait_option Suspension option */
1181 /* */
1182 /* OUTPUT */
1183 /* */
1184 /* status Completion status */
1185 /* */
1186 /* CALLS */
1187 /* */
1188 /* nx_packet_allocate Allocate a new packet */
1189 /* */
1190 /* CALLED BY */
1191 /* */
1192 /* Application Code */
1193 /* */
1194 /* RELEASE HISTORY */
1195 /* */
1196 /* DATE NAME DESCRIPTION */
1197 /* */
1198 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1199 /* */
1200 /**************************************************************************/
_nx_rtp_sender_session_packet_allocate(NX_RTP_SESSION * session,NX_PACKET ** packet_ptr,ULONG wait_option)1201 UINT _nx_rtp_sender_session_packet_allocate(NX_RTP_SESSION *session, NX_PACKET **packet_ptr, ULONG wait_option)
1202 {
1203
1204 UINT status;
1205
1206
1207 /* Allocate and get the packet from IP default packet pool. */
1208 status = nx_packet_allocate(session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, packet_ptr, NX_RTP_PACKET, wait_option);
1209
1210 return(status);
1211 }
1212
1213 /**************************************************************************/
1214 /* */
1215 /* FUNCTION RELEASE */
1216 /* */
1217 /* _nxe_rtp_sender_session_packet_send PORTABLE C */
1218 /* 6.3.0 */
1219 /* AUTHOR */
1220 /* */
1221 /* Haiqing Zhao, Microsoft Corporation */
1222 /* */
1223 /* DESCRIPTION */
1224 /* */
1225 /* This function checks errors in the RTP sender session packet send */
1226 /* function call. */
1227 /* */
1228 /* INPUT */
1229 /* */
1230 /* session Pointer to RTP session */
1231 /* packet_ptr Pointer to packet data to send */
1232 /* timestamp RTP timestamp for current data */
1233 /* ntp_msw Most significant word of */
1234 /* network time */
1235 /* ntp_lsw Least significant word of */
1236 /* network time */
1237 /* marker Marker bit for significant */
1238 /* event such as frame boundary */
1239 /* */
1240 /* OUTPUT */
1241 /* */
1242 /* status Completion status */
1243 /* NX_PTR_ERROR Invalid pointer input */
1244 /* */
1245 /* CALLS */
1246 /* */
1247 /* _nx_rtp_sender_session_packet_send Send packet data */
1248 /* */
1249 /* CALLED BY */
1250 /* */
1251 /* Application Code */
1252 /* */
1253 /* RELEASE HISTORY */
1254 /* */
1255 /* DATE NAME DESCRIPTION */
1256 /* */
1257 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1258 /* */
1259 /**************************************************************************/
_nxe_rtp_sender_session_packet_send(NX_RTP_SESSION * session,NX_PACKET * packet_ptr,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)1260 UINT _nxe_rtp_sender_session_packet_send(NX_RTP_SESSION *session, NX_PACKET *packet_ptr, ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
1261 {
1262
1263 UINT status;
1264
1265
1266 /* Check for invalid input pointers. */
1267 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (packet_ptr == NX_NULL))
1268 {
1269 return(NX_PTR_ERROR);
1270 }
1271
1272 /* Check for an invalid packet prepend pointer. */
1273 if ((INT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < (INT)(NX_RTP_PACKET))
1274 {
1275 return(NX_UNDERFLOW);
1276 }
1277
1278 /* Call actual RTP sender session packet send service. */
1279 status = _nx_rtp_sender_session_packet_send(session, packet_ptr, timestamp, ntp_msw, ntp_lsw, marker);
1280
1281 /* Return status. */
1282 return(status);
1283 }
1284
1285 /**************************************************************************/
1286 /* */
1287 /* FUNCTION RELEASE */
1288 /* */
1289 /* _nx_rtp_sender_session_packet_send PORTABLE C */
1290 /* 6.3.0 */
1291 /* AUTHOR */
1292 /* */
1293 /* Haiqing Zhao, Microsoft Corporation */
1294 /* */
1295 /* DESCRIPTION */
1296 /* */
1297 /* This function sends passed packet data in RTP format, and calls */
1298 /* RTP sender rctp send function as the entry to send RTCP report */
1299 /* */
1300 /* INPUT */
1301 /* */
1302 /* session Pointer to RTP session */
1303 /* packet_ptr Pointer to packet data to send */
1304 /* timestamp RTP timestamp for current data */
1305 /* ntp_msw Most significant word of */
1306 /* network time */
1307 /* ntp_lsw Least significant word of */
1308 /* network time */
1309 /* marker Marker bit for significant */
1310 /* event such as frame boundary */
1311 /* */
1312 /* OUTPUT */
1313 /* */
1314 /* status Completion status */
1315 /* */
1316 /* CALLS */
1317 /* */
1318 /* NX_CHANGE_USHORT_ENDIAN Adjust USHORT variable endian */
1319 /* _nx_rtcp_packet_send Send RTCP report */
1320 /* nxd_udp_socket_source_send Send RTP packet through UDP */
1321 /* */
1322 /* CALLED BY */
1323 /* */
1324 /* Application Code */
1325 /* */
1326 /* RELEASE HISTORY */
1327 /* */
1328 /* DATE NAME DESCRIPTION */
1329 /* */
1330 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1331 /* */
1332 /**************************************************************************/
_nx_rtp_sender_session_packet_send(NX_RTP_SESSION * session,NX_PACKET * packet_ptr,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)1333 UINT _nx_rtp_sender_session_packet_send(NX_RTP_SESSION *session, NX_PACKET *packet_ptr, ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
1334 {
1335
1336 UINT status;
1337 NX_RTP_HEADER *rtp_header_ptr;
1338 NX_PACKET *send_packet;
1339 NX_PACKET *data_packet = packet_ptr;
1340 UCHAR *data_ptr = data_packet -> nx_packet_prepend_ptr;
1341 UINT sample_factor = session -> nx_rtp_session_sample_factor;
1342 ULONG fragment_size = session -> nx_rtp_session_max_packet_size;
1343 ULONG remaining_bytes = packet_ptr -> nx_packet_length;
1344 ULONG payload_data_length;
1345 ULONG copy_size;
1346 UINT fragmentation = NX_FALSE;
1347
1348
1349 /* Transfer marker bit into rtp header field. */
1350 if (marker)
1351 {
1352 marker = (UINT)NX_RTP_HEADER_MARKER_BIT;
1353 }
1354
1355 /* Compare and set the fragmentation flag. */
1356 if (packet_ptr -> nx_packet_length > fragment_size)
1357 {
1358 fragmentation = NX_TRUE;
1359 }
1360
1361 while (remaining_bytes)
1362 {
1363 if (fragmentation == NX_FALSE)
1364 {
1365
1366 /* No fragmentation needed, set send packet to user passed packet directly. */
1367 send_packet = packet_ptr;
1368 }
1369 else
1370 {
1371
1372 /* Allocate a rtp packet for fragmentation. */
1373 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
1374 if (status)
1375 {
1376 return(status);
1377 }
1378
1379 /* Copy data. */
1380 while (send_packet -> nx_packet_length < fragment_size)
1381 {
1382
1383 /* Compute how many data bytes to copy in the current packet. */
1384 copy_size = (ULONG)(data_packet -> nx_packet_append_ptr - data_ptr);
1385 if ((send_packet -> nx_packet_length + copy_size) > fragment_size)
1386 {
1387
1388 /* Compute copy size with the remaining packet space in the send packet. */
1389 copy_size = fragment_size - send_packet -> nx_packet_length;
1390 }
1391
1392 /* Copy data into the send packet. */
1393 status = nx_packet_data_append(send_packet, data_ptr, copy_size, session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
1394 if (status)
1395 {
1396
1397 /* Release the allocated send packet and return error status. */
1398 nx_packet_release(send_packet);
1399 return(status);
1400 }
1401
1402 /* Move the data pointer after a success copy. */
1403 data_ptr += copy_size;
1404
1405 /* Make sure all data in current packet finish copying. */
1406 if (data_ptr >= data_packet -> nx_packet_append_ptr)
1407 {
1408 if (data_packet -> nx_packet_next == NX_NULL)
1409 {
1410
1411 /* Jump out current while loop when finding all data packets finish copying. */
1412 break;
1413 }
1414 else
1415 {
1416
1417 /* Move to the next packet. */
1418 data_packet = data_packet -> nx_packet_next;
1419
1420 /* Move the data pointer to the initial position of the next packet. */
1421 data_ptr = data_packet -> nx_packet_prepend_ptr;
1422 }
1423 }
1424 }
1425 }
1426
1427 /* Obtain payload data length and decrease remaining bytes with it. */
1428 payload_data_length = send_packet -> nx_packet_length;
1429 remaining_bytes -= payload_data_length;
1430
1431 /* Add rtp header information.
1432 0 1 2 3
1433 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1434 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1435 |V=2|P|X| CC |M| PT | sequence number |
1436 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1437 | timestamp |
1438 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1439 | synchronization source (SSRC) identifier |
1440 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1441 */
1442
1443 /* Update the overall packet length, assign rtp_header pointer to the initial position. */
1444 send_packet -> nx_packet_length += NX_RTP_HEADER_LENGTH;
1445 send_packet -> nx_packet_prepend_ptr -= NX_RTP_HEADER_LENGTH;
1446 rtp_header_ptr = (NX_RTP_HEADER *)(send_packet -> nx_packet_prepend_ptr);
1447
1448 /* Fill field 0 which contains following 4 sub-fields (3 of them are considered no need to support so far).
1449 1) The RTP protocol version number is always 2.
1450 2) The padding feature is ignored (i.e not supported) by using lower level padding if required (e.g. tls)
1451 3) The extension bit/feature is set to zero (i.e. not supported)
1452 4) The contributing source identifiers count is set to zero (i.e. not supported) */
1453 rtp_header_ptr -> nx_rtp_header_field0 = (NX_RTP_VERSION << 6);
1454
1455 /* Fill the second byte by the payload type recorded in the session context. */
1456 rtp_header_ptr -> nx_rtp_header_field1 = session -> nx_rtp_session_payload_type;
1457
1458 /* Set the marker bit which is intended to allow significant events such as frame boundaries to be marked in the packet stream.
1459 This is a user selectable flag and allow the user to choose whether to set it. */
1460 if ((remaining_bytes == 0) || (sample_factor))
1461 {
1462 rtp_header_ptr -> nx_rtp_header_field1 |= (UCHAR)marker;
1463 }
1464
1465 /* Fill the sequence number from the session context, convert it from host byte order to network byte order. Increase recorded sequence number by 1. */
1466 rtp_header_ptr -> nx_rtp_header_sequence_number = session -> nx_rtp_session_sequence_number;
1467 NX_CHANGE_USHORT_ENDIAN(rtp_header_ptr -> nx_rtp_header_sequence_number);
1468 session -> nx_rtp_session_sequence_number++;
1469
1470 /* Fill the timestamp passed as an argument from the user, convert it from host byte order to network byte order. */
1471 rtp_header_ptr -> nx_rtp_header_timestamp = timestamp;
1472 NX_CHANGE_ULONG_ENDIAN(rtp_header_ptr -> nx_rtp_header_timestamp);
1473
1474 /* Fill the ssrc from the session context, convert it from host byte order to network byte order. */
1475 rtp_header_ptr -> nx_rtp_header_ssrc = session -> nx_rtp_session_ssrc;
1476 NX_CHANGE_ULONG_ENDIAN(rtp_header_ptr -> nx_rtp_header_ssrc);
1477
1478 /* Store timestamps for rtcp send report. */
1479 session -> nx_rtp_session_rtp_timestamp = timestamp;
1480 session -> nx_rtp_session_ntp_timestamp_msw = ntp_msw;
1481 session -> nx_rtp_session_ntp_timestamp_lsw = ntp_lsw;
1482
1483 _nx_rtcp_packet_send(session);
1484
1485 /* Send out rtp packet */
1486 status = nxd_udp_socket_source_send(&(session -> nx_rtp_sender -> nx_rtp_sender_rtp_socket), send_packet,
1487 &(session -> nx_rtp_session_peer_ip_address), session -> nx_rtp_session_peer_rtp_port,
1488 session -> nx_rtp_session_interface_index);
1489 if (status)
1490 {
1491 if (fragmentation)
1492 {
1493
1494 /* Release the send packet when fragmentation applied. */
1495 nx_packet_release(send_packet);
1496 }
1497 else
1498 {
1499
1500 /* Reset the user packet prepend pointer and the total packet length. */
1501 packet_ptr -> nx_packet_prepend_ptr += NX_RTP_HEADER_LENGTH;
1502 packet_ptr -> nx_packet_length -= NX_RTP_HEADER_LENGTH;
1503 }
1504
1505 /* Return error status and let the user to determine when to release the packet. */
1506 return(status);
1507 }
1508
1509 /* Update sender report statistic. */
1510 session -> nx_rtp_session_packet_count++;
1511 session -> nx_rtp_session_octet_count += payload_data_length;
1512
1513 /* Update timestamp when sample-based mode enabled and there are more data bytes to transmit. */
1514 if (sample_factor && remaining_bytes)
1515 {
1516 timestamp += payload_data_length / sample_factor;
1517 }
1518 }
1519
1520 if (fragmentation)
1521 {
1522
1523 /* Release the user passed packet when fragmentation applied. */
1524 nx_packet_release(packet_ptr);
1525 }
1526
1527 return(NX_SUCCESS);
1528 }
1529
1530 /**************************************************************************/
1531 /* */
1532 /* FUNCTION RELEASE */
1533 /* */
1534 /* _nxe_rtp_sender_session_sequence_number_get PORTABLE C */
1535 /* 6.3.0 */
1536 /* AUTHOR */
1537 /* */
1538 /* Haiqing Zhao, Microsoft Corporation */
1539 /* */
1540 /* DESCRIPTION */
1541 /* */
1542 /* This function checks errors in the RTP sender session sequence */
1543 /* number get function call. */
1544 /* */
1545 /* INPUT */
1546 /* */
1547 /* session Pointer to RTP session */
1548 /* sequence_number Pointer to the sequence number */
1549 /* */
1550 /* OUTPUT */
1551 /* */
1552 /* status Completion status */
1553 /* NX_PTR_ERROR Invalid pointer input */
1554 /* */
1555 /* CALLS */
1556 /* */
1557 /* _nx_rtp_sender_session_sequence_number_get */
1558 /* Get the sequence number value */
1559 /* */
1560 /* CALLED BY */
1561 /* */
1562 /* Application Code */
1563 /* */
1564 /* RELEASE HISTORY */
1565 /* */
1566 /* DATE NAME DESCRIPTION */
1567 /* */
1568 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1569 /* */
1570 /**************************************************************************/
_nxe_rtp_sender_session_sequence_number_get(NX_RTP_SESSION * session,UINT * sequence_number)1571 UINT _nxe_rtp_sender_session_sequence_number_get(NX_RTP_SESSION *session, UINT *sequence_number)
1572 {
1573
1574 UINT status;
1575
1576
1577 /* Check for invalid input pointers. */
1578 if ((session == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (sequence_number == NX_NULL))
1579 {
1580 return(NX_PTR_ERROR);
1581 }
1582
1583 /* Call actual RTP sender session sequence number get service. */
1584 status = _nx_rtp_sender_session_sequence_number_get(session, sequence_number);
1585
1586 /* Return status. */
1587 return(status);
1588 }
1589
1590 /**************************************************************************/
1591 /* */
1592 /* FUNCTION RELEASE */
1593 /* */
1594 /* _nx_rtp_sender_session_sequence_number_get PORTABLE C */
1595 /* 6.3.0 */
1596 /* AUTHOR */
1597 /* */
1598 /* Haiqing Zhao, Microsoft Corporation */
1599 /* */
1600 /* DESCRIPTION */
1601 /* */
1602 /* This function provides the current sequence number value. */
1603 /* */
1604 /* INPUT */
1605 /* */
1606 /* session Pointer to RTP session */
1607 /* sequence_number Pointer to the sequence number */
1608 /* */
1609 /* OUTPUT */
1610 /* */
1611 /* NX_SUCCESS Completion status */
1612 /* */
1613 /* CALLS */
1614 /* */
1615 /* None */
1616 /* */
1617 /* CALLED BY */
1618 /* */
1619 /* Application Code */
1620 /* */
1621 /* RELEASE HISTORY */
1622 /* */
1623 /* DATE NAME DESCRIPTION */
1624 /* */
1625 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1626 /* */
1627 /**************************************************************************/
_nx_rtp_sender_session_sequence_number_get(NX_RTP_SESSION * session,UINT * sequence_number)1628 UINT _nx_rtp_sender_session_sequence_number_get(NX_RTP_SESSION *session, UINT *sequence_number)
1629 {
1630
1631 /* Assign return value with the current sequence number of the session. */
1632 *sequence_number = session -> nx_rtp_session_sequence_number;
1633
1634 return(NX_SUCCESS);
1635 }
1636
1637 /**************************************************************************/
1638 /* */
1639 /* FUNCTION RELEASE */
1640 /* */
1641 /* _nxe_rtp_sender_session_sample_factor_set PORTABLE C */
1642 /* 6.3.0 */
1643 /* AUTHOR */
1644 /* */
1645 /* Haiqing Zhao, Microsoft Corporation */
1646 /* */
1647 /* DESCRIPTION */
1648 /* */
1649 /* This function checks errors in the RTP sender session sampling */
1650 /* factor set function call. */
1651 /* */
1652 /* INPUT */
1653 /* */
1654 /* session Pointer to RTP session */
1655 /* factor The sampling factor */
1656 /* */
1657 /* OUTPUT */
1658 /* */
1659 /* status Completion status */
1660 /* NX_PTR_ERROR Invalid pointer input */
1661 /* */
1662 /* CALLS */
1663 /* */
1664 /* _nx_rtp_sender_session_sample_factor_set */
1665 /* Set the sampling factor value */
1666 /* */
1667 /* CALLED BY */
1668 /* */
1669 /* Application Code */
1670 /* */
1671 /* RELEASE HISTORY */
1672 /* */
1673 /* DATE NAME DESCRIPTION */
1674 /* */
1675 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1676 /* */
1677 /**************************************************************************/
_nxe_rtp_sender_session_sample_factor_set(NX_RTP_SESSION * session,UINT factor)1678 UINT _nxe_rtp_sender_session_sample_factor_set(NX_RTP_SESSION *session, UINT factor)
1679 {
1680
1681 UINT status;
1682
1683
1684 /* Check for invalid input pointers. */
1685 if ((session == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID))
1686 {
1687 return(NX_PTR_ERROR);
1688 }
1689
1690 /* Call actual RTP sender session sampling factor set service. */
1691 status = _nx_rtp_sender_session_sample_factor_set(session, factor);
1692
1693 /* Return status. */
1694 return(status);
1695 }
1696
1697 /**************************************************************************/
1698 /* */
1699 /* FUNCTION RELEASE */
1700 /* */
1701 /* _nx_rtp_sender_session_sample_factor_set PORTABLE C */
1702 /* 6.3.0 */
1703 /* AUTHOR */
1704 /* */
1705 /* Haiqing Zhao, Microsoft Corporation */
1706 /* */
1707 /* DESCRIPTION */
1708 /* */
1709 /* This function sets the sample factor value for sample-based payload */
1710 /* in rtp. The sample factor determines the timestamp increasing rate */
1711 /* in the function _nx_rtp_sender_session_packet_send when the */
1712 /* fragmentation feature triggered in sample-based mode since timestamp*/
1713 /* shall be increased in a pace for each fragmentation packet. */
1714 /* */
1715 /* The default sample factor value 0, representing frame-based mode. */
1716 /* User can use this function to set a non-zero sample factor, with */
1717 /* automatically triggering sample-based mode. */
1718 /* Examples about how the sample factor is computed for audio: */
1719 /* 1) sample bits: 8, channel number: 1, factor = 1 * (8/8) = 1 */
1720 /* 2) sample bits: 16, channel number: 1, factor = 1 * (16/8) = 2 */
1721 /* 3) sample bits: 16, channel number: 2, factor = 2 * (16/8) = 4 */
1722 /* */
1723 /* INPUT */
1724 /* */
1725 /* session Pointer to RTP session */
1726 /* factor The sampling factor */
1727 /* */
1728 /* OUTPUT */
1729 /* */
1730 /* NX_SUCCESS Completion status */
1731 /* */
1732 /* CALLS */
1733 /* */
1734 /* None */
1735 /* */
1736 /* CALLED BY */
1737 /* */
1738 /* Application Code */
1739 /* */
1740 /* RELEASE HISTORY */
1741 /* */
1742 /* DATE NAME DESCRIPTION */
1743 /* */
1744 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1745 /* */
1746 /**************************************************************************/
_nx_rtp_sender_session_sample_factor_set(NX_RTP_SESSION * session,UINT factor)1747 UINT _nx_rtp_sender_session_sample_factor_set(NX_RTP_SESSION *session, UINT factor)
1748 {
1749
1750 /* Store the factor value into the session. */
1751 session -> nx_rtp_session_sample_factor = factor;
1752
1753 return(NX_SUCCESS);
1754 }
1755
1756 /**************************************************************************/
1757 /* */
1758 /* FUNCTION RELEASE */
1759 /* */
1760 /* _nxe_rtp_sender_session_ssrc_get PORTABLE C */
1761 /* 6.3.0 */
1762 /* AUTHOR */
1763 /* */
1764 /* Haiqing Zhao, Microsoft Corporation */
1765 /* */
1766 /* DESCRIPTION */
1767 /* */
1768 /* This function checks errors in the RTP sender session ssrc get */
1769 /* function call. */
1770 /* */
1771 /* INPUT */
1772 /* */
1773 /* session Pointer to RTP session */
1774 /* ssrc Pointer to ssrc */
1775 /* */
1776 /* OUTPUT */
1777 /* */
1778 /* status Completion status */
1779 /* NX_PTR_ERROR Invalid pointer input */
1780 /* */
1781 /* CALLS */
1782 /* */
1783 /* _nx_rtp_sender_session_ssrc_get Get ssrc value */
1784 /* */
1785 /* CALLED BY */
1786 /* */
1787 /* Application Code */
1788 /* */
1789 /* RELEASE HISTORY */
1790 /* */
1791 /* DATE NAME DESCRIPTION */
1792 /* */
1793 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1794 /* */
1795 /**************************************************************************/
_nxe_rtp_sender_session_ssrc_get(NX_RTP_SESSION * session,ULONG * ssrc)1796 UINT _nxe_rtp_sender_session_ssrc_get(NX_RTP_SESSION *session, ULONG *ssrc)
1797 {
1798
1799 UINT status;
1800
1801
1802 /* Check for invalid input pointers. */
1803 if ((session == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (ssrc == NX_NULL))
1804 {
1805 return(NX_PTR_ERROR);
1806 }
1807
1808 /* Call actual RTP sender session ssrc get service. */
1809 status = _nx_rtp_sender_session_ssrc_get(session, ssrc);
1810
1811 /* Return status. */
1812 return(status);
1813 }
1814
1815 /**************************************************************************/
1816 /* */
1817 /* FUNCTION RELEASE */
1818 /* */
1819 /* _nx_rtp_sender_session_ssrc_get PORTABLE C */
1820 /* 6.3.0 */
1821 /* AUTHOR */
1822 /* */
1823 /* Haiqing Zhao, Microsoft Corporation */
1824 /* */
1825 /* DESCRIPTION */
1826 /* */
1827 /* This function provides the current ssrc value. */
1828 /* */
1829 /* INPUT */
1830 /* */
1831 /* session Pointer to RTP session */
1832 /* ssrc Pointer to ssrc */
1833 /* */
1834 /* OUTPUT */
1835 /* */
1836 /* NX_SUCCESS Completion status */
1837 /* */
1838 /* CALLS */
1839 /* */
1840 /* None */
1841 /* */
1842 /* CALLED BY */
1843 /* */
1844 /* Application Code */
1845 /* */
1846 /* RELEASE HISTORY */
1847 /* */
1848 /* DATE NAME DESCRIPTION */
1849 /* */
1850 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1851 /* */
1852 /**************************************************************************/
_nx_rtp_sender_session_ssrc_get(NX_RTP_SESSION * session,ULONG * ssrc)1853 UINT _nx_rtp_sender_session_ssrc_get(NX_RTP_SESSION *session, ULONG *ssrc)
1854 {
1855
1856 /* Assign return value with the current ssrc of the session */
1857 *ssrc = session -> nx_rtp_session_ssrc;
1858
1859 return(NX_SUCCESS);
1860 }
1861
1862 /**************************************************************************/
1863 /* */
1864 /* FUNCTION RELEASE */
1865 /* */
1866 /* _nx_rtp_sender_cleanup PORTABLE C */
1867 /* 6.3.0 */
1868 /* AUTHOR */
1869 /* */
1870 /* Haiqing Zhao, Microsoft Corporation */
1871 /* */
1872 /* DESCRIPTION */
1873 /* */
1874 /* This function cleans up resources created in rtp sender. */
1875 /* */
1876 /* INPUT */
1877 /* */
1878 /* rtp_sender Pointer to RTP sender instance */
1879 /* */
1880 /* OUTPUT */
1881 /* */
1882 /* NX_SUCCESS Completion status */
1883 /* */
1884 /* CALLS */
1885 /* */
1886 /* nx_udp_socket_unbind Unbind RTP/RTCP sockets */
1887 /* nx_udp_socket_delete Delete RTP/RTCP sockets */
1888 /* tx_mutex_delete Delete RTP sender mutex */
1889 /* */
1890 /* CALLED BY */
1891 /* */
1892 /* _nx_rtp_sender_create Create RTP sender */
1893 /* _nx_rtp_sender_delete Delete RTP sender */
1894 /* */
1895 /* RELEASE HISTORY */
1896 /* */
1897 /* DATE NAME DESCRIPTION */
1898 /* */
1899 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
1900 /* */
1901 /**************************************************************************/
_nx_rtp_sender_cleanup(NX_RTP_SENDER * rtp_sender)1902 UINT _nx_rtp_sender_cleanup(NX_RTP_SENDER *rtp_sender)
1903 {
1904
1905 /* Unbind and delete created rtp and rtcp sockets */
1906 nx_udp_socket_unbind(&(rtp_sender -> nx_rtp_sender_rtp_socket));
1907 nx_udp_socket_delete(&(rtp_sender -> nx_rtp_sender_rtp_socket));
1908 nx_udp_socket_unbind(&(rtp_sender -> nx_rtp_sender_rtcp_socket));
1909 nx_udp_socket_delete(&(rtp_sender -> nx_rtp_sender_rtcp_socket));
1910
1911 /* Delete generated mutex */
1912 tx_mutex_delete(&(rtp_sender -> nx_rtp_sender_protection));
1913
1914 return(NX_SUCCESS);
1915 }
1916
1917 /**************************************************************************/
1918 /* */
1919 /* FUNCTION RELEASE */
1920 /* */
1921 /* _nx_rtp_sender_session_find PORTABLE C */
1922 /* 6.3.0 */
1923 /* AUTHOR */
1924 /* */
1925 /* Ting Zhu, Microsoft Corporation */
1926 /* */
1927 /* DESCRIPTION */
1928 /* */
1929 /* This function finds a RTP session through the specified ssrc. */
1930 /* */
1931 /* INPUT */
1932 /* */
1933 /* rtp_sender Pointer to RTP sender */
1934 /* ssrc The specified session ssrc */
1935 /* session Pointer to RTP session */
1936 /* destination */
1937 /* */
1938 /* OUTPUT */
1939 /* */
1940 /* status Completion status */
1941 /* */
1942 /* CALLS */
1943 /* */
1944 /* None */
1945 /* */
1946 /* CALLED BY */
1947 /* */
1948 /* _nx_rtcp_packet_rr_process Handle RTCP RR packet */
1949 /* */
1950 /* RELEASE HISTORY */
1951 /* */
1952 /* DATE NAME DESCRIPTION */
1953 /* */
1954 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
1955 /* */
1956 /**************************************************************************/
_nx_rtp_sender_session_find(NX_RTP_SENDER * rtp_sender,UINT ssrc,NX_RTP_SESSION ** session)1957 UINT _nx_rtp_sender_session_find(NX_RTP_SENDER *rtp_sender, UINT ssrc, NX_RTP_SESSION **session)
1958 {
1959
1960 NX_RTP_SESSION *start = rtp_sender -> nx_rtp_sender_session_created_ptr;
1961
1962
1963 while (start)
1964 {
1965 if (start -> nx_rtp_session_ssrc == ssrc)
1966 {
1967 *session = start;
1968 return(NX_SUCCESS);
1969 }
1970 start = start -> nx_rtp_session_next;
1971 }
1972
1973 return(NX_NOT_FOUND);
1974 }
1975
1976 /**************************************************************************/
1977 /* */
1978 /* FUNCTION RELEASE */
1979 /* */
1980 /* _nx_rtp_sender_session_link PORTABLE C */
1981 /* 6.3.0 */
1982 /* AUTHOR */
1983 /* */
1984 /* Ting Zhu, Microsoft Corporation */
1985 /* */
1986 /* DESCRIPTION */
1987 /* */
1988 /* This function links a RTP session to the RTP sender control block. */
1989 /* */
1990 /* INPUT */
1991 /* */
1992 /* rtp_sender Pointer to RTP sender */
1993 /* session Pointer to RTP session */
1994 /* */
1995 /* OUTPUT */
1996 /* */
1997 /* None */
1998 /* */
1999 /* CALLS */
2000 /* */
2001 /* None */
2002 /* */
2003 /* CALLED BY */
2004 /* */
2005 /* _nx_rtp_sender_session_create Create RTP session */
2006 /* */
2007 /* RELEASE HISTORY */
2008 /* */
2009 /* DATE NAME DESCRIPTION */
2010 /* */
2011 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2012 /* */
2013 /**************************************************************************/
_nx_rtp_sender_session_link(NX_RTP_SENDER * rtp_sender,NX_RTP_SESSION * session)2014 VOID _nx_rtp_sender_session_link(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session)
2015 {
2016
2017 NX_RTP_SESSION *tail;
2018
2019
2020 if (rtp_sender -> nx_rtp_sender_session_created_ptr)
2021 {
2022
2023 /* Search the tail ptr. */
2024 tail = rtp_sender -> nx_rtp_sender_session_created_ptr;
2025
2026 while (tail -> nx_rtp_session_next)
2027 {
2028 tail = tail -> nx_rtp_session_next;
2029 }
2030
2031 /* Put the session at the end of the list. */
2032 tail -> nx_rtp_session_next = session;
2033 }
2034 else
2035 {
2036
2037 /* The created session list is empty, simply add the session. */
2038 rtp_sender -> nx_rtp_sender_session_created_ptr = session;
2039 }
2040 }
2041
2042 /**************************************************************************/
2043 /* */
2044 /* FUNCTION RELEASE */
2045 /* */
2046 /* _nx_rtp_sender_session_unlink PORTABLE C */
2047 /* 6.3.0 */
2048 /* AUTHOR */
2049 /* */
2050 /* Ting Zhu, Microsoft Corporation */
2051 /* */
2052 /* DESCRIPTION */
2053 /* */
2054 /* This function unlinks a RTP session from the RTP sender control */
2055 /* block. */
2056 /* */
2057 /* INPUT */
2058 /* */
2059 /* rtp_sender Pointer to RTP sender */
2060 /* session Pointer to RTP session */
2061 /* */
2062 /* OUTPUT */
2063 /* */
2064 /* status Completion status */
2065 /* */
2066 /* CALLS */
2067 /* */
2068 /* None */
2069 /* */
2070 /* CALLED BY */
2071 /* */
2072 /* _nx_rtp_sender_session_delete Delete RTP session */
2073 /* */
2074 /* RELEASE HISTORY */
2075 /* */
2076 /* DATE NAME DESCRIPTION */
2077 /* */
2078 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2079 /* */
2080 /**************************************************************************/
_nx_rtp_sender_session_unlink(NX_RTP_SENDER * rtp_sender,NX_RTP_SESSION * session)2081 UINT _nx_rtp_sender_session_unlink(NX_RTP_SENDER *rtp_sender, NX_RTP_SESSION *session)
2082 {
2083
2084 NX_RTP_SESSION *current;
2085 NX_RTP_SESSION *pre;
2086
2087
2088 /* Find the session and unlink it from the list. */
2089 if (rtp_sender -> nx_rtp_sender_session_created_ptr == session)
2090 {
2091 rtp_sender -> nx_rtp_sender_session_created_ptr = session -> nx_rtp_session_next;
2092 }
2093 else
2094 {
2095 pre = rtp_sender -> nx_rtp_sender_session_created_ptr;
2096 current = pre -> nx_rtp_session_next;
2097
2098 while (current)
2099 {
2100 if (current == session)
2101 {
2102 pre -> nx_rtp_session_next = current -> nx_rtp_session_next;
2103 break;
2104 }
2105
2106 pre = current;
2107 current = pre -> nx_rtp_session_next;
2108 }
2109 }
2110
2111 return(NX_SUCCESS);
2112 }
2113
2114 /**************************************************************************/
2115 /* */
2116 /* FUNCTION RELEASE */
2117 /* */
2118 /* _nx_rtcp_packet_process PORTABLE C */
2119 /* 6.3.0 */
2120 /* AUTHOR */
2121 /* */
2122 /* Ting Zhu, Microsoft Corporation */
2123 /* */
2124 /* DESCRIPTION */
2125 /* */
2126 /* This function handles reception of RTCP packet. */
2127 /* */
2128 /* INPUT */
2129 /* */
2130 /* rtp_sender Pointer to RTP sender */
2131 /* packet_ptr Pointer to packet */
2132 /* */
2133 /* OUTPUT */
2134 /* */
2135 /* status Completion status */
2136 /* */
2137 /* CALLS */
2138 /* */
2139 /* _nx_rtcp_packet_rr_process Handle RR packet */
2140 /* _nx_rtcp_packet_sdes_process Handle SDES packet */
2141 /* */
2142 /* CALLED BY */
2143 /* */
2144 /* _nx_rtcp_packet_receive_notify RTCP packet receive notify */
2145 /* service */
2146 /* */
2147 /* RELEASE HISTORY */
2148 /* */
2149 /* DATE NAME DESCRIPTION */
2150 /* */
2151 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2152 /* */
2153 /**************************************************************************/
_nx_rtcp_packet_process(NX_RTP_SENDER * rtp_sender,NX_PACKET * packet_ptr)2154 UINT _nx_rtcp_packet_process(NX_RTP_SENDER *rtp_sender, NX_PACKET *packet_ptr)
2155 {
2156
2157 UINT status = NX_SUCCESS;
2158 NX_RTCP_HEADER *header;
2159 NX_RTCP_HEADER *next;
2160 UCHAR *end;
2161
2162
2163 if (rtp_sender -> nx_rtp_sender_id != NX_RTP_SENDER_ID)
2164 {
2165
2166 /* Not valid RTP sender. */
2167 return(NX_PTR_ERROR);
2168 }
2169
2170 #ifndef NX_DISABLE_PACKET_CHAIN
2171 if (packet_ptr -> nx_packet_next)
2172 {
2173
2174 /* Chained packet, not supported. */
2175 return(NX_NOT_SUPPORTED);
2176 }
2177 #endif /* NX_DISABLE_PACKET_CHAIN */
2178
2179 header = (NX_RTCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
2180 end = packet_ptr -> nx_packet_append_ptr;
2181
2182 if ((UCHAR *)header + sizeof(NX_RTCP_HEADER) > end)
2183 {
2184 return(NX_INVALID_PACKET);
2185 }
2186
2187 /* Check the first RTCP packet header:
2188 1) The Padding bit should be zero for the first packet of a compound RTCP packet.
2189 2) The payload type field of the first RTCP packet in a compound packet must be equal to SR or RR.
2190 */
2191 if (((header -> nx_rtcp_byte0 & NX_RTCP_PAD_MASK) != NX_RTCP_PAD_VALUE) ||
2192 ((header -> nx_rtcp_packet_type & NX_RTCP_TYPE_MASK) != NX_RTCP_TYPE_SR))
2193 {
2194
2195 /* Wrong packet format. */
2196 return(NX_INVALID_PACKET);
2197 }
2198
2199 do
2200 {
2201 NX_CHANGE_USHORT_ENDIAN(header -> nx_rtcp_length);
2202
2203 next = (NX_RTCP_HEADER *)((ULONG *)header + header -> nx_rtcp_length + 1);
2204
2205 /* RTP version field must equal 2. */
2206 if (((header -> nx_rtcp_byte0 & NX_RTCP_VERSION_MASK) != NX_RTCP_VERSION_VALUE) || ((UCHAR *)next > end))
2207 {
2208 status = NX_INVALID_PACKET;
2209 break;
2210 }
2211
2212 switch (header -> nx_rtcp_packet_type)
2213 {
2214 case NX_RTCP_TYPE_RR:
2215
2216 /* Process rr packet. */
2217 status = _nx_rtcp_packet_rr_process(rtp_sender, header);
2218 break;
2219
2220 case NX_RTCP_TYPE_SDES:
2221
2222 /* Process sdes packet. */
2223 status = _nx_rtcp_packet_sdes_process(rtp_sender, header);
2224 break;
2225 }
2226
2227 if (status != NX_SUCCESS)
2228 {
2229 break;
2230 }
2231
2232 header = next;
2233 } while ((UCHAR *)header + sizeof(NX_RTCP_HEADER) <= end);
2234
2235 return(status);
2236 }
2237
2238 /**************************************************************************/
2239 /* */
2240 /* FUNCTION RELEASE */
2241 /* */
2242 /* _nx_rtcp_packet_rr_process PORTABLE C */
2243 /* 6.3.0 */
2244 /* AUTHOR */
2245 /* */
2246 /* Ting Zhu, Microsoft Corporation */
2247 /* */
2248 /* DESCRIPTION */
2249 /* */
2250 /* This function handles RTCP RR packet. */
2251 /* */
2252 /* INPUT */
2253 /* */
2254 /* rtp_sender Pointer to RTP sender */
2255 /* header Pointer to RTCP packet header */
2256 /* */
2257 /* OUTPUT */
2258 /* */
2259 /* status Completion status */
2260 /* */
2261 /* CALLS */
2262 /* */
2263 /* _nx_rtp_sender_session_find Find rtp session */
2264 /* tx_mutex_get Get mutex */
2265 /* tx_mutex_put Release mutex */
2266 /* nx_rtp_sender_rtcp_receiver_report_cb Application's RTCP RR packet */
2267 /* notify callback */
2268 /* */
2269 /* CALLED BY */
2270 /* */
2271 /* _nx_rtcp_packet_process Handle RTCP packet */
2272 /* */
2273 /* RELEASE HISTORY */
2274 /* */
2275 /* DATE NAME DESCRIPTION */
2276 /* */
2277 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2278 /* */
2279 /**************************************************************************/
_nx_rtcp_packet_rr_process(NX_RTP_SENDER * rtp_sender,NX_RTCP_HEADER * header)2280 UINT _nx_rtcp_packet_rr_process(NX_RTP_SENDER *rtp_sender, NX_RTCP_HEADER *header)
2281 {
2282
2283 UINT status;
2284 NX_RTCP_RR *rtcp_rr;
2285 NX_RTCP_RECEIVER_REPORT report;
2286 UINT (*rr_callback)(struct NX_RTP_SESSION_STRUCT *, NX_RTCP_RECEIVER_REPORT *);
2287 NX_RTP_SESSION *session;
2288
2289
2290 rr_callback = rtp_sender -> nx_rtp_sender_rtcp_receiver_report_cb;
2291 if (rr_callback == NX_NULL)
2292 {
2293
2294 /* No RTCP receiver report callback set. */
2295 return(NX_SUCCESS);
2296 }
2297
2298 if ((header -> nx_rtcp_byte0 & NX_RTCP_COUNT_MASK) &&
2299 ((sizeof(NX_RTCP_RR) >> 2) <= (UINT)((header -> nx_rtcp_length + 1))))
2300 {
2301 rtcp_rr = (NX_RTCP_RR *)header;
2302
2303 /* Take care of endian-ness. */
2304 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_ssrc);
2305
2306 /* Obtain the mutex. */
2307 status = tx_mutex_get(&(rtp_sender -> nx_rtp_sender_protection), TX_NO_WAIT);
2308
2309 if (status != NX_SUCCESS)
2310 {
2311 return(status);
2312 }
2313
2314 if (_nx_rtp_sender_session_find(rtp_sender, rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_ssrc, &session) == NX_SUCCESS)
2315 {
2316 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_ssrc);
2317 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_loss);
2318 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_extended_max);
2319 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_jitter);
2320 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_last_sr);
2321 NX_CHANGE_ULONG_ENDIAN(rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_delay);
2322
2323 /* Copy the values out for the callback function. */
2324 report.receiver_ssrc = rtcp_rr -> nx_rtcp_rr_ssrc;
2325 report.fraction_loss = rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_loss >> 24;
2326 report.packet_loss = ((((INT)rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_loss) << 8) >> 8);
2327 report.extended_max = rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_extended_max;
2328 report.jitter = rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_jitter;
2329 report.last_sr = rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_last_sr;
2330 report.delay = rtcp_rr -> nx_rtcp_rr_report.nx_rtcp_report_delay;
2331
2332 /* Invoke the callback function to process data inside the RTCP RR packet. */
2333 rr_callback(session, &report);
2334 }
2335
2336 /* Release the mutex. */
2337 tx_mutex_put(&(rtp_sender -> nx_rtp_sender_protection));
2338 }
2339
2340 return(NX_SUCCESS);
2341 }
2342
2343 /**************************************************************************/
2344 /* */
2345 /* FUNCTION RELEASE */
2346 /* */
2347 /* _nx_rtcp_packet_sdes_process PORTABLE C */
2348 /* 6.3.0 */
2349 /* AUTHOR */
2350 /* */
2351 /* Ting Zhu, Microsoft Corporation */
2352 /* */
2353 /* DESCRIPTION */
2354 /* */
2355 /* This function handles RTCP SDES packet. */
2356 /* */
2357 /* INPUT */
2358 /* */
2359 /* rtp_sender Pointer to RTP sender */
2360 /* header Pointer to RTCP packet header */
2361 /* */
2362 /* OUTPUT */
2363 /* */
2364 /* status Completion status */
2365 /* */
2366 /* CALLS */
2367 /* */
2368 /* nx_rtp_sender_rtcp_sdes_cb Application's RTCP SDES */
2369 /* packet notify callback */
2370 /* */
2371 /* CALLED BY */
2372 /* */
2373 /* _nx_rtcp_packet_process Handle RTCP packet */
2374 /* */
2375 /* RELEASE HISTORY */
2376 /* */
2377 /* DATE NAME DESCRIPTION */
2378 /* */
2379 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2380 /* */
2381 /**************************************************************************/
_nx_rtcp_packet_sdes_process(NX_RTP_SENDER * rtp_sender,NX_RTCP_HEADER * header)2382 UINT _nx_rtcp_packet_sdes_process(NX_RTP_SENDER *rtp_sender, NX_RTCP_HEADER *header)
2383 {
2384
2385 UINT (*sdes_callback)(NX_RTCP_SDES_INFO *);
2386 NX_RTCP_SDES_CHUNK *chunk;
2387 NX_RTCP_SDES_ITEM *item;
2388 UCHAR *end;
2389 NX_RTCP_SDES_INFO sdes_info;
2390 INT count;
2391
2392
2393 sdes_callback = rtp_sender -> nx_rtp_sender_rtcp_sdes_cb;
2394 if (sdes_callback == NX_NULL)
2395 {
2396
2397 /* No RTCP receiver report callback set. */
2398 return(NX_SUCCESS);
2399 }
2400
2401 chunk = (NX_RTCP_SDES_CHUNK *)((UCHAR *)header + sizeof(NX_RTCP_HEADER));
2402 count = (header -> nx_rtcp_byte0 & NX_RTCP_COUNT_MASK);
2403
2404 end = (UCHAR *)((ULONG *)header + header -> nx_rtcp_length + 1);
2405
2406 while (((UCHAR *)chunk + sizeof(NX_RTCP_SDES_CHUNK) <= end) && (count-- > 0))
2407 {
2408 item = &chunk -> nx_rtcp_sdes_item[0];
2409
2410 NX_CHANGE_ULONG_ENDIAN(chunk -> nx_rtcp_sdes_ssrc);
2411
2412 while (((UCHAR *)item + sizeof(NX_RTCP_SDES_ITEM) <= end) && item -> nx_rtcp_sdes_type)
2413 {
2414
2415 if (item -> nx_rtcp_sdes_data + item -> nx_rtcp_sdes_length > end)
2416 {
2417 return(NX_INVALID_PACKET);
2418 }
2419
2420 if (item -> nx_rtcp_sdes_type == NX_RTCP_SDES_TYPE_CNAME)
2421 {
2422
2423 /* Copy the values out for the callback function. */
2424 sdes_info.ssrc = chunk -> nx_rtcp_sdes_ssrc;
2425 sdes_info.cname_length = item -> nx_rtcp_sdes_length;
2426
2427 /* CNAME string is UTF-8 encoded and is not null terminated. */
2428 sdes_info.cname = &item -> nx_rtcp_sdes_data[0];
2429
2430 /* Invoke the callback function to process data inside the RTCP SDES packet. */
2431 sdes_callback(&sdes_info);
2432
2433 break;
2434 }
2435
2436 /* Advance to the next item. */
2437 item = (NX_RTCP_SDES_ITEM *)((UCHAR *)item + 2 + item -> nx_rtcp_sdes_length);
2438 }
2439
2440 /* RFC 3550, chapter 6.5.
2441 The list of items in each chunk MUST be terminated by one or more null octets,
2442 the first of which is interpreted as an item type of zero to denote the end of the list. */
2443 chunk = (NX_RTCP_SDES_CHUNK *)((UCHAR *)chunk + (((UCHAR *)item - (UCHAR *)chunk) >> 2) + 1);
2444 }
2445
2446 return(NX_SUCCESS);
2447 }
2448
2449
2450 /**************************************************************************/
2451 /* */
2452 /* FUNCTION RELEASE */
2453 /* */
2454 /* _nx_rtcp_sr_data_append PORTABLE C */
2455 /* 6.3.0 */
2456 /* AUTHOR */
2457 /* */
2458 /* Ting Zhu, Microsoft Corporation */
2459 /* */
2460 /* DESCRIPTION */
2461 /* */
2462 /* This function generates an RTCP SR packet and copies it to the end */
2463 /* of the specifed RTCP packet. */
2464 /* */
2465 /* INPUT */
2466 /* */
2467 /* session Pointer to RTP session */
2468 /* packet_ptr Pointer to RTCP packet */
2469 /* */
2470 /* OUTPUT */
2471 /* */
2472 /* status Completion status */
2473 /* */
2474 /* CALLS */
2475 /* */
2476 /* nx_packet_data_append Copy the specified data to */
2477 /* the end of specified packet */
2478 /* */
2479 /* CALLED BY */
2480 /* */
2481 /* _nx_rtcp_packet_send Send RTCP packet */
2482 /* */
2483 /* RELEASE HISTORY */
2484 /* */
2485 /* DATE NAME DESCRIPTION */
2486 /* */
2487 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2488 /* */
2489 /**************************************************************************/
_nx_rtcp_sr_data_append(NX_RTP_SESSION * session,NX_PACKET * packet_ptr)2490 UINT _nx_rtcp_sr_data_append(NX_RTP_SESSION *session, NX_PACKET *packet_ptr)
2491 {
2492
2493 NX_RTCP_SR rtcp_sr;
2494
2495
2496 /* Pack SR packet. */
2497 rtcp_sr.nx_rtcp_sr_header.nx_rtcp_byte0 = (NX_RTP_VERSION << 6); /* Version 2 */
2498 rtcp_sr.nx_rtcp_sr_header.nx_rtcp_packet_type = NX_RTCP_TYPE_SR;
2499 rtcp_sr.nx_rtcp_sr_header.nx_rtcp_length = sizeof(NX_RTCP_SR) / sizeof(ULONG) - 1; /* RTCP SR size. */
2500 rtcp_sr.nx_rtcp_sr_ssrc = session -> nx_rtp_session_ssrc;
2501 rtcp_sr.nx_rtcp_sr_ntp_timestamp_msw = session -> nx_rtp_session_ntp_timestamp_msw;
2502 rtcp_sr.nx_rtcp_sr_ntp_timestamp_lsw = session -> nx_rtp_session_ntp_timestamp_lsw;
2503 rtcp_sr.nx_rtcp_sr_rtp_timestamp = session -> nx_rtp_session_rtp_timestamp;
2504 rtcp_sr.nx_rtcp_sr_rtp_packet_count = session -> nx_rtp_session_packet_count;
2505 rtcp_sr.nx_rtcp_sr_rtp_octet_count = session -> nx_rtp_session_octet_count;
2506
2507 /* Take care of endian-ness. */
2508 NX_CHANGE_USHORT_ENDIAN(rtcp_sr.nx_rtcp_sr_header.nx_rtcp_length);
2509 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_ssrc);
2510 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_ntp_timestamp_msw);
2511 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_ntp_timestamp_lsw);
2512 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_rtp_timestamp);
2513 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_rtp_packet_count);
2514 NX_CHANGE_ULONG_ENDIAN(rtcp_sr.nx_rtcp_sr_rtp_octet_count);
2515
2516 /* Append SR packet. */
2517 nx_packet_data_append(packet_ptr, &rtcp_sr, sizeof(rtcp_sr), session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
2518
2519 return(NX_SUCCESS);
2520 }
2521
2522 /**************************************************************************/
2523 /* */
2524 /* FUNCTION RELEASE */
2525 /* */
2526 /* _nx_rtcp_sdes_data_append PORTABLE C */
2527 /* 6.3.0 */
2528 /* AUTHOR */
2529 /* */
2530 /* Ting Zhu, Microsoft Corporation */
2531 /* */
2532 /* DESCRIPTION */
2533 /* */
2534 /* This function generates an RTCP SDES packet and copies it to the */
2535 /* end of the specifed RTCP packet. */
2536 /* */
2537 /* INPUT */
2538 /* */
2539 /* session Pointer to RTP session */
2540 /* packet_ptr Pointer to RTCP packet */
2541 /* */
2542 /* OUTPUT */
2543 /* */
2544 /* status Completion status */
2545 /* */
2546 /* CALLS */
2547 /* */
2548 /* nx_packet_data_append Copy the specified data to */
2549 /* the end of specified packet */
2550 /* */
2551 /* CALLED BY */
2552 /* */
2553 /* _nx_rtcp_packet_send Send RTCP packet */
2554 /* */
2555 /* RELEASE HISTORY */
2556 /* */
2557 /* DATE NAME DESCRIPTION */
2558 /* */
2559 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2560 /* */
2561 /**************************************************************************/
_nx_rtcp_sdes_data_append(NX_RTP_SESSION * session,NX_PACKET * packet_ptr)2562 UINT _nx_rtcp_sdes_data_append(NX_RTP_SESSION *session, NX_PACKET *packet_ptr)
2563 {
2564
2565 UINT status;
2566 NX_RTCP_HEADER header;
2567 NX_RTCP_SDES_CHUNK sdes_chunk;
2568 NX_PACKET_POOL *packet_pool = session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr;
2569 NX_RTP_SENDER *sender = session -> nx_rtp_sender;
2570 ULONG pad = 0;
2571 UCHAR pad_value[] = {0, 0, 0};
2572 UINT length;
2573
2574
2575 /*
2576 SDES packet format:
2577 0 1 2 3
2578 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2579 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2580 header |V=2|P| SC | PT=SDES=202 | length |
2581 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
2582 chunk | SSRC/CSRC_1 |
2583 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2584 | SDES items |
2585 | ... |
2586 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
2587 chunk | SSRC/CSRC_2 |
2588 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2589 | SDES items |
2590 | ... |
2591 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
2592
2593 SDES item format for CNAME:
2594 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2595 | CNAME=1 | length | user and domain name ...
2596 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2597 */
2598
2599 /* packet size = rtcp header size + 4 bytes ssrc + 1 byte type + 1 byte length + data length. */
2600 length = sizeof(NX_RTCP_HEADER) + 6 + sender -> nx_rtp_sender_cname_length;
2601
2602 if (length & 0x3)
2603 {
2604 pad = 4 - (length & 0x3);
2605 }
2606
2607 /* Pack SDES packet header. */
2608 header.nx_rtcp_byte0 = (NX_RTP_VERSION << 6) | 1; /* Sender Desc with 1 item */
2609 header.nx_rtcp_packet_type = NX_RTCP_TYPE_SDES;
2610 header.nx_rtcp_length = (USHORT)(((length + pad) / sizeof(ULONG)) - 1);
2611
2612 NX_CHANGE_USHORT_ENDIAN(header.nx_rtcp_length);
2613
2614 /* Append SDES packet header. */
2615 status = nx_packet_data_append(packet_ptr, &header, sizeof(header), packet_pool, NX_RTP_SENDER_PACKET_TIMEOUT);
2616 if (status)
2617 {
2618 return(status);
2619 }
2620
2621 /* Pack CNAME item. */
2622 sdes_chunk.nx_rtcp_sdes_ssrc = session -> nx_rtp_session_ssrc;
2623 sdes_chunk.nx_rtcp_sdes_item[0].nx_rtcp_sdes_type = NX_RTCP_SDES_TYPE_CNAME;
2624 sdes_chunk.nx_rtcp_sdes_item[0].nx_rtcp_sdes_length = sender -> nx_rtp_sender_cname_length;
2625
2626 NX_CHANGE_ULONG_ENDIAN(sdes_chunk.nx_rtcp_sdes_ssrc);
2627
2628 /* Append 4 bytes ssrc + 1 byte item type + 1 byte data length. */
2629 status = nx_packet_data_append(packet_ptr, &sdes_chunk, 6, packet_pool, NX_RTP_SENDER_PACKET_TIMEOUT);
2630 if (status)
2631 {
2632 return(status);
2633 }
2634
2635 /* Append cname string. */
2636 status = nx_packet_data_append(packet_ptr, sender -> nx_rtp_sender_cname, sender -> nx_rtp_sender_cname_length, packet_pool, NX_RTP_SENDER_PACKET_TIMEOUT);
2637 if (status)
2638 {
2639 return(status);
2640 }
2641
2642 if (pad)
2643 {
2644 status = nx_packet_data_append(packet_ptr, pad_value, pad, packet_pool, NX_RTP_SENDER_PACKET_TIMEOUT);
2645 if (status)
2646 {
2647 return(status);
2648 }
2649 }
2650
2651 return(NX_SUCCESS);
2652 }
2653
2654 /**************************************************************************/
2655 /* */
2656 /* FUNCTION RELEASE */
2657 /* */
2658 /* _nx_rtcp_packet_send PORTABLE C */
2659 /* 6.3.0 */
2660 /* AUTHOR */
2661 /* */
2662 /* Ting Zhu, Microsoft Corporation */
2663 /* */
2664 /* DESCRIPTION */
2665 /* */
2666 /* This function sends a compound RTCP packet through the UDP layer to */
2667 /* the supplied IP address and rtcp port. */
2668 /* */
2669 /* INPUT */
2670 /* */
2671 /* session Pointer to RTP session */
2672 /* */
2673 /* OUTPUT */
2674 /* */
2675 /* status Completion status */
2676 /* */
2677 /* CALLS */
2678 /* */
2679 /* tx_time_get Get current system clock */
2680 /* nx_packet_allocate Allocate packet */
2681 /* nx_packet_release Release packet */
2682 /* nxd_udp_socket_source_send Send a UDP packet */
2683 /* _nx_rtcp_sr_data_append Append SR packet */
2684 /* _nx_rtcp_sdes_data_append Append SDES packet */
2685 /* */
2686 /* CALLED BY */
2687 /* */
2688 /* _nx_rtp_sender_session_packet_send Send rtp packet */
2689 /* */
2690 /* RELEASE HISTORY */
2691 /* */
2692 /* DATE NAME DESCRIPTION */
2693 /* */
2694 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2695 /* */
2696 /**************************************************************************/
_nx_rtcp_packet_send(NX_RTP_SESSION * session)2697 UINT _nx_rtcp_packet_send(NX_RTP_SESSION *session)
2698 {
2699
2700 UINT status = NX_SUCCESS;
2701 NX_PACKET *packet_ptr;
2702 UINT current_time = tx_time_get();
2703
2704
2705 if (session -> nx_rtp_session_rtcp_time &&
2706 ((current_time - session -> nx_rtp_session_rtcp_time) / TX_TIMER_TICKS_PER_SECOND < NX_RTCP_INTERVAL))
2707 {
2708 return(NX_SUCCESS);
2709 }
2710
2711 status = nx_packet_allocate(session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_RTP_SENDER_PACKET_TIMEOUT);
2712
2713 if (status != NX_SUCCESS)
2714 {
2715 return(status);
2716 }
2717
2718 /* Chain rtcp packets into one compound packet. */
2719 status = _nx_rtcp_sr_data_append(session, packet_ptr);
2720
2721 if (status == NX_SUCCESS)
2722 {
2723 status = _nx_rtcp_sdes_data_append(session, packet_ptr);
2724 }
2725
2726 if (status == NX_SUCCESS)
2727 {
2728
2729 /* Send the packet. */
2730 status = nxd_udp_socket_source_send(&session -> nx_rtp_sender -> nx_rtp_sender_rtcp_socket, packet_ptr,
2731 &(session -> nx_rtp_session_peer_ip_address), session -> nx_rtp_session_peer_rtcp_port,
2732 session -> nx_rtp_session_interface_index);
2733 }
2734
2735 /* Check the status. */
2736 if (status == NX_SUCCESS)
2737 {
2738 session -> nx_rtp_session_rtcp_time = tx_time_get();
2739 }
2740 else
2741 {
2742 nx_packet_release(packet_ptr);
2743 }
2744
2745 return(status);
2746 }
2747
2748 /**************************************************************************/
2749 /* */
2750 /* FUNCTION RELEASE */
2751 /* */
2752 /* _nx_rtcp_packet_receive_notify PORTABLE C */
2753 /* 6.3.0 */
2754 /* AUTHOR */
2755 /* */
2756 /* Ting Zhu, Microsoft Corporation */
2757 /* */
2758 /* DESCRIPTION */
2759 /* */
2760 /* This function serves as RTCP packet receive notify routine, which */
2761 /* is called whenever a packet is received on the rtcp port. */
2762 /* */
2763 /* INPUT */
2764 /* */
2765 /* socket_ptr Pointer to RTCP port */
2766 /* */
2767 /* OUTPUT */
2768 /* */
2769 /* status Completion status */
2770 /* */
2771 /* CALLS */
2772 /* */
2773 /* nx_udp_socket_receive Check for UDP packet on the */
2774 /* specified port */
2775 /* nx_packet_release Release packet */
2776 /* _nx_rtcp_packet_process Handle rtcp packet */
2777 /* */
2778 /* CALLED BY */
2779 /* */
2780 /* _nx_rtp_sender_create Create RTP sender */
2781 /* */
2782 /* RELEASE HISTORY */
2783 /* */
2784 /* DATE NAME DESCRIPTION */
2785 /* */
2786 /* 10-31-2023 Ting Zhu Initial Version 6.3.0 */
2787 /* */
2788 /**************************************************************************/
_nx_rtcp_packet_receive_notify(NX_UDP_SOCKET * socket_ptr)2789 VOID _nx_rtcp_packet_receive_notify(NX_UDP_SOCKET *socket_ptr)
2790 {
2791
2792 /* Drain the packet */
2793 NX_PACKET *packet_ptr;
2794 NX_RTP_SENDER *rtp_sender;
2795
2796
2797 /* Get packet(s) from the passed socket. */
2798 if (nx_udp_socket_receive(socket_ptr, &packet_ptr, NX_NO_WAIT) != NX_SUCCESS)
2799 {
2800 return;
2801 }
2802
2803 /* Check and determine whether to process received rtcp packet. */
2804 rtp_sender = (NX_RTP_SENDER *)socket_ptr -> nx_udp_socket_reserved_ptr;
2805 if ((rtp_sender) &&
2806 (rtp_sender -> nx_rtp_sender_rtcp_receiver_report_cb || rtp_sender -> nx_rtp_sender_rtcp_sdes_cb))
2807 {
2808 _nx_rtcp_packet_process(rtp_sender, packet_ptr);
2809 }
2810
2811 /* Release the packet and return. */
2812 nx_packet_release(packet_ptr);
2813 return;
2814 }
2815
2816 /**************************************************************************/
2817 /* */
2818 /* FUNCTION RELEASE */
2819 /* */
2820 /* _nxe_rtp_sender_session_jpeg_send PORTABLE C */
2821 /* 6.3.0 */
2822 /* AUTHOR */
2823 /* */
2824 /* Haiqing Zhao, Microsoft Corporation */
2825 /* */
2826 /* DESCRIPTION */
2827 /* */
2828 /* This function checks errors in the RTP sender session jpeg send */
2829 /* function call. */
2830 /* */
2831 /* INPUT */
2832 /* */
2833 /* session Pointer to RTP session */
2834 /* frame_data Pointer to data buffer to send */
2835 /* frame_data_size Size of data to send */
2836 /* timestamp RTP timestamp for current data */
2837 /* ntp_msw Most significant word of */
2838 /* network time */
2839 /* ntp_lsw Least significant word of */
2840 /* network time */
2841 /* marker Marker bit for significant */
2842 /* event such as frame boundary */
2843 /* */
2844 /* OUTPUT */
2845 /* */
2846 /* status Completion status */
2847 /* NX_PTR_ERROR Invalid pointer input */
2848 /* */
2849 /* CALLS */
2850 /* */
2851 /* _nx_rtp_sender_session_jpeg_send Send packet data */
2852 /* */
2853 /* CALLED BY */
2854 /* */
2855 /* Application Code */
2856 /* */
2857 /* RELEASE HISTORY */
2858 /* */
2859 /* DATE NAME DESCRIPTION */
2860 /* */
2861 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
2862 /* */
2863 /**************************************************************************/
_nxe_rtp_sender_session_jpeg_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)2864 UINT _nxe_rtp_sender_session_jpeg_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
2865 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
2866 {
2867
2868 UINT status;
2869
2870
2871 /* Check for invalid input pointers. */
2872 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (frame_data == NX_NULL))
2873 {
2874 return(NX_PTR_ERROR);
2875 }
2876
2877 /* Call actual RTP sender session packet send service. */
2878 status = _nx_rtp_sender_session_jpeg_send(session, frame_data, frame_data_size, timestamp, ntp_msw, ntp_lsw, marker);
2879
2880 /* Return status. */
2881 return(status);
2882 }
2883
2884 /**************************************************************************/
2885 /* */
2886 /* FUNCTION RELEASE */
2887 /* */
2888 /* _nx_rtp_sender_session_jpeg_send PORTABLE C */
2889 /* 6.3.0 */
2890 /* AUTHOR */
2891 /* */
2892 /* Haiqing Zhao, Microsoft Corporation */
2893 /* */
2894 /* DESCRIPTION */
2895 /* */
2896 /* This function parses and makes the passed data in RTP/JPEG format, */
2897 /* and then calls RTP session send function to send these data in RTP */
2898 /* packet. */
2899 /* The function references RFC 2435 as the standard with below notes: */
2900 /* 1) A complete jpeg scan file inside frame data buffer is required. */
2901 /* 2) Use dynamic quantization table mapping. */
2902 /* 3) The provided jpeg scan file shall be 8-bit sample precision, */
2903 /* YUV420 or YUV422 type, and encoded with standard huffman tables. */
2904 /* 4) Restart marker is not supported. */
2905 /* */
2906 /* INPUT */
2907 /* */
2908 /* session Pointer to RTP session */
2909 /* frame_data Pointer to data buffer to send */
2910 /* frame_data_size Size of data to send */
2911 /* timestamp RTP timestamp for current data */
2912 /* ntp_msw Most significant word of */
2913 /* network time */
2914 /* ntp_lsw Least significant word of */
2915 /* network time */
2916 /* marker Marker bit for significant */
2917 /* event such as frame boundary */
2918 /* */
2919 /* OUTPUT */
2920 /* */
2921 /* status Completion status */
2922 /* */
2923 /* CALLS */
2924 /* */
2925 /* _nx_rtp_sender_session_packet_allocate */
2926 /* Allocate a packet for the user */
2927 /* nx_packet_data_append Copy the specified data to */
2928 /* the end of specified packet */
2929 /* nx_packet_data_release Release the packet */
2930 /* _nx_rtp_sender_session_packet_send Send RTP packet */
2931 /* */
2932 /* CALLED BY */
2933 /* */
2934 /* Application Code */
2935 /* */
2936 /* RELEASE HISTORY */
2937 /* */
2938 /* DATE NAME DESCRIPTION */
2939 /* */
2940 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
2941 /* */
2942 /**************************************************************************/
_nx_rtp_sender_session_jpeg_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)2943 UINT _nx_rtp_sender_session_jpeg_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
2944 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
2945 {
2946
2947 UINT status;
2948 UCHAR *data_ptr;
2949 UCHAR *data_end_ptr;
2950 UCHAR jpeg_header[8];
2951 UCHAR quantization_header[4];
2952 USHORT section_length;
2953 UCHAR type = 255; /* type field for main jpeg header. */
2954 UCHAR marker_code; /* jpeg marker code to indicate different sections. */
2955 USHORT width = 0, height = 0; /* resolution information for main jpeg header. */
2956 ULONG q_table_num = 0;
2957 ULONG q_overall_table_num = 0;
2958 UCHAR *q_table_ptr[NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_MAX_NUM];
2959 ULONG data_payload_length = 0;
2960 ULONG transferred_data_size = 0;
2961 ULONG single_frame_length;
2962 ULONG copy_length;
2963 UINT temp_rtp_marker = NX_FALSE;
2964 NX_PACKET *send_packet = NX_NULL;
2965
2966
2967 /* In current design, the marker bit shall be always 1 (i.e. a complete jpeg scan file required to be passed). */
2968 if (marker != NX_TRUE)
2969 {
2970 return(NX_NOT_SUPPORTED);
2971 }
2972
2973 /* Initialize local variables for searching. */
2974 data_ptr = frame_data;
2975 data_end_ptr = frame_data + frame_data_size;
2976
2977 /* Check jpeg constant file header. */
2978 if ((frame_data_size < 2) || ((data_ptr[0] != 0xFF) || (data_ptr[1] != 0xD8)))
2979 {
2980 return(NX_NOT_SUCCESSFUL);
2981 }
2982
2983 /* Skip the 2 bytes jpeg file header. */
2984 data_ptr += 2;
2985
2986 do
2987 {
2988
2989 /* Check there are enough bytes remaining in the data buffer for 2 bytes section marker and 2 bytes section length. */
2990 if ((data_ptr + 4) > data_end_ptr)
2991 {
2992 return(NX_SIZE_ERROR);
2993 }
2994
2995 /* Check the first byte for section marker. */
2996 if (data_ptr[0] != 0xFF)
2997 {
2998 return(NX_NOT_SUCCESSFUL);
2999 }
3000
3001 /* Update the marker code. */
3002 marker_code = data_ptr[1];
3003
3004 /* Update and skip the whole 2 bytes section marker. */
3005 data_ptr += 2;
3006
3007 /* Compute data length in this section. */
3008 section_length = (USHORT)((data_ptr[0] << 8) | data_ptr[1]);
3009
3010 /* Check there are enough bytes remaining in the data buffer. */
3011 if ((data_ptr + section_length) > data_end_ptr)
3012 {
3013 return(NX_SIZE_ERROR);
3014 }
3015
3016 /* Now it is time to parse the marker code and its corresponding section. */
3017 switch (marker_code)
3018 {
3019
3020 /* SOF0: image baseline information. */
3021 case 0xC0:
3022 {
3023
3024 /* For a standard RTP/JPEG image baseline information, this section length shall be
3025 at least 17, in order to contain enough baseline information for the image. */
3026 if (section_length < 17)
3027 {
3028 return(NX_SIZE_ERROR);
3029 }
3030
3031 /* Skip 2 bytes section length. */
3032 data_ptr += 2;
3033
3034 /* 8-bit sample precision is required. */
3035 if (data_ptr[0] != 8)
3036 {
3037 return(NX_NOT_SUPPORTED);
3038 }
3039
3040 /* Check the number of image components which shall be 3 for YUV. */
3041 if (data_ptr[5] != 3)
3042 {
3043 return(NX_NOT_SUPPORTED);
3044 }
3045
3046 /* Check the quantization table number for all YUV dimensions. */
3047 if ((data_ptr[8] != 0x00) || (data_ptr[11] != 0x01) || (data_ptr[14] != 0x01))
3048 {
3049 return(NX_NOT_SUPPORTED);
3050 }
3051
3052 /* Check the horizontal and vertical sampling factor for both U dimension and V dimension. */
3053 if ((data_ptr[10] != 0x11) || (data_ptr[13] != 0x11))
3054 {
3055 return(NX_NOT_SUPPORTED);
3056 }
3057
3058 /* Determine the RTP/JPEG type in jpeg main header through different vertical sampling factor of Y dimension. */
3059 if (data_ptr[7] == 0x21)
3060 {
3061 type = 0; /* YUV420. */
3062 }
3063 else if (data_ptr[7] == 0x22)
3064 {
3065 type = 1; /* YUV422. */
3066 }
3067 else
3068 {
3069 return(NX_NOT_SUPPORTED);
3070 }
3071
3072 /* Compute width and height. */
3073 height = (USHORT)((data_ptr[1] << 8) | data_ptr[2]);
3074 width = (USHORT)((data_ptr[3] << 8) | data_ptr[4]);
3075
3076 /* Skip the current section. */
3077 data_ptr += 15; /* 15 bytes section data. */
3078 break;
3079 }
3080
3081 /* DQT: define quantization table. */
3082 case 0xDB:
3083 {
3084
3085 /* Skip 2 bytes section length. */
3086 data_ptr += 2;
3087
3088 /* Compute the number of quantization tables (each table shall contain 65 bytes). */
3089 q_table_num = section_length / (NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH + 1);
3090
3091 /* Check current table number. */
3092 if ((q_table_num == 0) || ((q_table_num + q_overall_table_num) > NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_MAX_NUM))
3093 {
3094 return(NX_NOT_SUCCESSFUL);
3095 }
3096
3097 for (UINT i = q_overall_table_num; i < (q_overall_table_num + q_table_num); i++)
3098 {
3099
3100 /* Skip the first no meaning byte. */
3101 data_ptr++;
3102
3103 /* Record the current table position. */
3104 q_table_ptr[i] = data_ptr;
3105
3106 /* Move to the next table position. */
3107 data_ptr += NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH;
3108 }
3109
3110 /* Update overall number of tables. This variable is introduced because there may be more than 1 DQT come. */
3111 q_overall_table_num += q_table_num;
3112 break;
3113 }
3114
3115 /* SOS: the start of the scan. */
3116 case 0xDA:
3117 {
3118
3119 /* Skip the scan header. */
3120 data_ptr += section_length;
3121
3122 /* Move the end pointer to the last 2 byte to make the check easier */
3123 data_end_ptr -= 2;
3124
3125 /* Search and try to find EOI in current packet. */
3126 while (data_ptr < data_end_ptr)
3127 {
3128 if ((data_end_ptr[0] == 0xFF) && (data_end_ptr[1] == 0xD9))
3129 {
3130 break;
3131 }
3132 else
3133 {
3134 data_end_ptr--;
3135 }
3136 }
3137
3138 /* Check if EOI has been found. */
3139 if (data_ptr < data_end_ptr)
3140 {
3141 data_payload_length = (ULONG)(data_end_ptr - data_ptr);
3142 }
3143 else /* data_ptr == data_end_ptr */
3144 {
3145
3146 /* If EOI has not been found, consider all remaining data are scan data. */
3147 data_payload_length = frame_data_size - (ULONG)(data_ptr - frame_data);
3148 }
3149
3150 /* When SOS found, the while loop will also be jumped out. */
3151 break;
3152 }
3153
3154 /* EOI */
3155 case 0xD9:
3156 {
3157
3158 /* SOS shall be found before EOI. */
3159 return(NX_NOT_SUCCESSFUL);
3160 }
3161
3162 /* Unsupported SOFs or other markers. */
3163 case 0xC1: /* Extended sequential DCT */
3164 case 0xC2: /* Progressive DCT */
3165 case 0xC3: /* Lossless (sequential) */
3166 case 0xC5: /* Differential sequential DCT */
3167 case 0xC6: /* Differential progressive DCT */
3168 case 0xC7: /* Differential lossless (sequential) */
3169 case 0xC8: /* Reserved for JPEG extensions */
3170 case 0xC9: /* Extended sequential DCT */
3171 case 0xCA: /* Progressive DCT */
3172 case 0xCB: /* Lossless (sequential) */
3173 case 0xCC: /* Define arithmetic coding conditionings */
3174 case 0xCD: /* Differential sequential DCT */
3175 case 0xCE: /* Differential progressive DCT */
3176 case 0xCF: /* Differential lossless (sequential) */
3177 case 0xDD: /* DRI */
3178 {
3179 return(NX_NOT_SUPPORTED);
3180 }
3181
3182 /* Possible sections in default:
3183 1) APP0 ~ APPn: define exchange format and image identifications.
3184 2) Huffman table: it is assumed that standard Huffman table applied. */
3185 default:
3186 {
3187
3188 /* Marker code 0x01 is not supported. Marker codes inside 0x02 ~ 0xBF are reserved. */
3189 if (marker_code < 0xC0)
3190 {
3191 return(NX_NOT_SUPPORTED);
3192 }
3193
3194 /* Move the data_ptr and offset to skip the whole section. */
3195 data_ptr += section_length;
3196 break;
3197 }
3198 }
3199
3200 } while (marker_code != 0xDA); /* Jump out when find SOS. */
3201
3202 /* Check the type has been confirmed, and quantization. */
3203 if (((type != 0) && (type != 1)) || (q_overall_table_num == 0))
3204 {
3205 return(NX_NOT_SUCCESSFUL);
3206 }
3207
3208 /* Check there is any scan data to send. */
3209 if (data_payload_length == 0)
3210 {
3211 return(NX_SIZE_ERROR);
3212 }
3213
3214 /* Allocate a packet for the first data packet to transmit. */
3215 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
3216 if (status)
3217 {
3218 return(NX_NOT_SUCCESSFUL);
3219 }
3220
3221 /* Initialize main JPEG header, and append it into the send packet. */
3222 jpeg_header[0] = 0; /* Always 0 since no interpretation is specified. */
3223 jpeg_header[1] = 0; /* High byte of 24 bytes size offset. */
3224 jpeg_header[2] = 0; /* Middle byte 24 bytes size offset. */
3225 jpeg_header[3] = 0; /* Low byte of 24 bytes size offset. */
3226 jpeg_header[4] = type;
3227 jpeg_header[5] = 255; /* Q values 255 indicates the quantization table header appears after the main JPEG header,
3228 and the quantization table is allowed to be changeable among different frames. */
3229 jpeg_header[6] = (UCHAR)(width >> 3); /* Maximum width: 2040 pixels. */
3230 jpeg_header[7] = (UCHAR)(height >> 3); /* Maximum height: 2040 pixels. */
3231
3232 status = nx_packet_data_append(send_packet, (void *)jpeg_header, sizeof(jpeg_header),
3233 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3234 if (status)
3235 {
3236 nx_packet_release(send_packet);
3237 return(NX_NOT_SUCCESSFUL);
3238 }
3239
3240 /* Update quantization table header, and append it into the send packet. */
3241 quantization_header[0] = 0; /* MBZ. */
3242 quantization_header[1] = 0; /* Precision: 8 bits. */
3243 quantization_header[2] = (UCHAR)((NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH * q_overall_table_num) >> 8); /* High byte if tables length. */
3244 quantization_header[3] = (UCHAR)(NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH * q_overall_table_num); /* Low byte if tables length. */
3245
3246 status = nx_packet_data_append(send_packet, (void *)quantization_header, sizeof(quantization_header),
3247 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3248 if (status)
3249 {
3250 nx_packet_release(send_packet);
3251 return(NX_NOT_SUCCESSFUL);
3252 }
3253
3254 /* Copy quantization table(s) into the packet. It is assume that these table(s) are not in different packets of a chain packet. */
3255 for (UINT i = 0; i < q_overall_table_num; i++)
3256 {
3257 status = nx_packet_data_append(send_packet, (void *)(q_table_ptr[i]), NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH,
3258 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3259 if (status)
3260 {
3261 nx_packet_release(send_packet);
3262 return(NX_NOT_SUCCESSFUL);
3263 }
3264 }
3265
3266 /* Compute the current single frame length and check if mtu size match the requirement for putting all jpeg header info into one packet. */
3267 single_frame_length = sizeof(jpeg_header) + sizeof(quantization_header) + NX_RTP_SENDER_JPEG_QUANTIZATION_TABLE_LENGTH * q_overall_table_num;
3268 if (single_frame_length > session -> nx_rtp_session_max_packet_size)
3269 {
3270 nx_packet_release(send_packet);
3271 return(NX_NOT_SUPPORTED);
3272 }
3273
3274 /* Begin data frame(s) transmit. */
3275 while (1)
3276 {
3277
3278 /* Check and execute packet fragmentation. */
3279 copy_length = session -> nx_rtp_session_max_packet_size - single_frame_length;
3280 if (data_payload_length <= copy_length)
3281 {
3282 copy_length = data_payload_length;
3283 temp_rtp_marker = NX_TRUE;
3284 }
3285
3286 /* Copy payload data into the packet. */
3287 status = nx_packet_data_append(send_packet, (void *)data_ptr, copy_length,
3288 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3289 if (status)
3290 {
3291 nx_packet_release(send_packet);
3292 return(status);
3293 }
3294
3295 /* Send the data packet. */
3296 status = _nx_rtp_sender_session_packet_send(session, send_packet, timestamp, ntp_msw, ntp_lsw, temp_rtp_marker);
3297 if (status)
3298 {
3299 nx_packet_release(send_packet);
3300 return(status);
3301 }
3302
3303 /* Decrease transmitted data payload length and check whether all data finish transmitting. */
3304 data_payload_length -= copy_length;
3305 if (data_payload_length == 0)
3306 {
3307
3308 /* Jump out the while loop when all data finish transmitting. */
3309 break;
3310 }
3311
3312 /* Move data pointer to the begin of remaining data. */
3313 data_ptr += copy_length;
3314
3315 /* Update 24-bit transferred data offset with bytes order. */
3316 transferred_data_size += copy_length;
3317 jpeg_header[1] = (UCHAR)(transferred_data_size >> 16);
3318 jpeg_header[2] = (UCHAR)(transferred_data_size >> 8);
3319 jpeg_header[3] = (UCHAR)(transferred_data_size);
3320
3321 /* Allocate a packet for next packet. */
3322 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
3323 if (status)
3324 {
3325 return(status);
3326 }
3327
3328 /* Copy jpeg header into the packet. */
3329 status = nx_packet_data_append(send_packet, (void *)jpeg_header, sizeof(jpeg_header),
3330 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3331 if (status)
3332 {
3333 nx_packet_release(send_packet);
3334 return(status);
3335 }
3336
3337 /* Update single frame length. */
3338 single_frame_length = sizeof(jpeg_header);
3339 }
3340
3341 /* Return success status. */
3342 return(NX_SUCCESS);
3343 }
3344
3345 /**************************************************************************/
3346 /* */
3347 /* FUNCTION RELEASE */
3348 /* */
3349 /* _nxe_rtp_sender_session_h264_send PORTABLE C */
3350 /* 6.3.0 */
3351 /* AUTHOR */
3352 /* */
3353 /* Haiqing Zhao, Microsoft Corporation */
3354 /* */
3355 /* DESCRIPTION */
3356 /* */
3357 /* This function checks errors in the RTP sender session h264 send */
3358 /* function call. */
3359 /* */
3360 /* INPUT */
3361 /* */
3362 /* session Pointer to RTP session */
3363 /* frame_data Pointer to data buffer to send */
3364 /* frame_data_size Size of data to send */
3365 /* timestamp RTP timestamp for current data */
3366 /* ntp_msw Most significant word of */
3367 /* network time */
3368 /* ntp_lsw Least significant word of */
3369 /* network time */
3370 /* marker Marker bit for significant */
3371 /* event such as frame boundary */
3372 /* */
3373 /* OUTPUT */
3374 /* */
3375 /* status Completion status */
3376 /* NX_PTR_ERROR Invalid pointer input */
3377 /* */
3378 /* CALLS */
3379 /* */
3380 /* _nx_rtp_sender_session_h264_send Send h264 frame data */
3381 /* */
3382 /* CALLED BY */
3383 /* */
3384 /* Application Code */
3385 /* */
3386 /* RELEASE HISTORY */
3387 /* */
3388 /* DATE NAME DESCRIPTION */
3389 /* */
3390 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
3391 /* */
3392 /**************************************************************************/
_nxe_rtp_sender_session_h264_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)3393 UINT _nxe_rtp_sender_session_h264_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
3394 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
3395 {
3396
3397 UINT status;
3398
3399
3400 /* Check for invalid input pointers. */
3401 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (frame_data == NX_NULL))
3402 {
3403 return(NX_PTR_ERROR);
3404 }
3405
3406 /* Call actual RTP sender session frame send service. */
3407 status = _nx_rtp_sender_session_h264_send(session, frame_data, frame_data_size, timestamp, ntp_msw, ntp_lsw, marker);
3408
3409 /* Return status. */
3410 return(status);
3411 }
3412
3413 /**************************************************************************/
3414 /* */
3415 /* FUNCTION RELEASE */
3416 /* */
3417 /* _nx_rtp_sender_session_h264_send PORTABLE C */
3418 /* 6.3.0 */
3419 /* AUTHOR */
3420 /* */
3421 /* Haiqing Zhao, Microsoft Corporation */
3422 /* */
3423 /* DESCRIPTION */
3424 /* */
3425 /* This function parses and separates the passed data into h264 frames */
3426 /* or slices, and processes each frame/slice from VCL format to NAL */
3427 /* format, and finally calls RTP session send function to send these */
3428 /* frame/slice(s) in RTP packet. */
3429 /* The function references RFC 6184 as the standard with below notes: */
3430 /* 1) A complete h264 data frame shall be inside the frame data buffer.*/
3431 /* 2) Special frame(s) such as SEI, SPS and PPS can be inside the */
3432 /* frame data buffer. */
3433 /* 3) Each H264 frame/slice inside the frame data buffer shall be in */
3434 /* VCL (video coding layer) format. */
3435 /* 4) SDP shall indicate that non-interleaved mode is applied (i.e. */
3436 /* packetization-mode=1), which supports the use of single NAL unit */
3437 /* packet and FU-A packets. */
3438 /* */
3439 /* INPUT */
3440 /* */
3441 /* session Pointer to RTP session */
3442 /* frame_data Pointer to data buffer to send */
3443 /* frame_data_size Size of data to send */
3444 /* timestamp RTP timestamp for current data */
3445 /* ntp_msw Most significant word of */
3446 /* network time */
3447 /* ntp_lsw Least significant word of */
3448 /* network time */
3449 /* marker Marker bit for significant */
3450 /* event such as frame boundary */
3451 /* */
3452 /* OUTPUT */
3453 /* */
3454 /* status Completion status */
3455 /* */
3456 /* CALLS */
3457 /* */
3458 /* _nx_rtp_sender_session_packet_allocate */
3459 /* Allocate a packet for the user */
3460 /* nx_packet_data_append Copy the specified data to */
3461 /* the end of specified packet */
3462 /* nx_packet_data_release Release the packet */
3463 /* _nx_rtp_sender_session_packet_send Send RTP packet */
3464 /* */
3465 /* CALLED BY */
3466 /* */
3467 /* Application Code */
3468 /* */
3469 /* RELEASE HISTORY */
3470 /* */
3471 /* DATE NAME DESCRIPTION */
3472 /* */
3473 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
3474 /* */
3475 /**************************************************************************/
_nx_rtp_sender_session_h264_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)3476 UINT _nx_rtp_sender_session_h264_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
3477 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
3478 {
3479
3480 UINT status;
3481 UINT i;
3482 ULONG nal_unit_size;
3483 ULONG max_packet_length;
3484 ULONG send_packet_length;
3485 UCHAR *frame_end;
3486 UCHAR *nal_unit_start;
3487 UCHAR *data_ptr = frame_data;
3488 UINT send_marker = NX_FALSE;
3489 UINT temp_marker = NX_FALSE;
3490 UCHAR nal_unit_type;
3491 UCHAR fu_a_header[2];
3492 ULONG packet_num;
3493 ULONG last_packet_size;
3494 NX_PACKET *send_packet = NX_NULL;
3495
3496
3497 /* In current design, the marker bit shall be always 1 (i.e. a complete h264 frame required to be passed). */
3498 if (marker != NX_TRUE)
3499 {
3500 return(NX_NOT_SUPPORTED);
3501 }
3502
3503 /* Obtain the maximum frame packet length. */
3504 max_packet_length = session -> nx_rtp_session_max_packet_size;
3505
3506 /* Check frame minimum length. */
3507 if (frame_data_size <= 4)
3508 {
3509 return(NX_SIZE_ERROR);
3510 }
3511
3512 /* Record frame end position. */
3513 frame_end = frame_data + frame_data_size - 1;
3514
3515 /* Is the h264 4 bytes or 3 bytes header found. */
3516 if ((data_ptr[0] == 0x00) && (data_ptr[1] == 0x00) && (data_ptr[2] == 0x00) && (data_ptr[3] == 0x01))
3517 {
3518
3519 /* Yes, skip the 4 bytes header. */
3520 data_ptr += 4;
3521 }
3522 else if ((data_ptr[0] == 0x00) && (data_ptr[1] == 0x00) && (data_ptr[2] == 0x01))
3523 {
3524
3525 /* Yes, skip the 3 bytes header. */
3526 data_ptr += 3;
3527 }
3528 else
3529 {
3530
3531 /* Wrong h264 header, return not successful. */
3532 return(NX_NOT_SUCCESSFUL);
3533 }
3534
3535 /* There are conditions requiring below while loop to guarantee the procedure of separation and transmission:
3536 1) Special frame(s) such as SEI, SPS and PPS are passed with a data frame.
3537 2) The data frame is composed of several slices
3538 */
3539 while (data_ptr <= (frame_end - 4))
3540 {
3541
3542 /* Set the start position and reset the single frame size. */
3543 nal_unit_start = data_ptr;
3544 nal_unit_size = 0;
3545
3546 /* Extract a complete frame from the raw source file through finding the next 4/3 bytes header or the end of data buffer. */
3547 while (1)
3548 {
3549
3550 /* Check if there is a new slice header found */
3551 if ((data_ptr[0] == 0x00) && (data_ptr[1] == 0x00))
3552 {
3553
3554 if ((data_ptr[2] == 0x00) && (data_ptr[3] == 0x01))
3555 {
3556
3557 /* Jump out if 4 bytes header of next frame/slice found. */
3558 nal_unit_size = (ULONG)(data_ptr - nal_unit_start + 1);
3559 data_ptr += 4;
3560 break;
3561 }
3562 else if (data_ptr[2] == 0x01)
3563 {
3564
3565 /* Jump out if 3 bytes header of next frame/slice found. */
3566 nal_unit_size = (ULONG)(data_ptr - nal_unit_start + 1);
3567 data_ptr += 3;
3568 break;
3569 }
3570 }
3571
3572 /* Skip the check last 4 bytes if no header found is current position. */
3573 if (data_ptr >= (frame_end - 4))
3574 {
3575
3576 /* Compute nal unit size and move data pointer to the end. */
3577 nal_unit_size = (ULONG)(frame_end - nal_unit_start + 1);
3578 data_ptr = frame_end;
3579
3580 /* Set the send marker and jump out. */
3581 send_marker = NX_TRUE;
3582 break;
3583 }
3584
3585 /* Move and check next byte. */
3586 data_ptr++;
3587 }
3588
3589 /* Initialize NAL unit type with the first byte after the h264 header. */
3590 nal_unit_type = nal_unit_start[0];
3591
3592 /* Check NAL unit type. */
3593 if (((nal_unit_type & NX_RTP_SENDER_H264_TYPE_MASK_BITS) == NX_RTP_SENDER_H264_TYPE_SEI) ||
3594 ((nal_unit_type & NX_RTP_SENDER_H264_TYPE_MASK_BITS) == NX_RTP_SENDER_H264_TYPE_SPS) ||
3595 ((nal_unit_type & NX_RTP_SENDER_H264_TYPE_MASK_BITS) == NX_RTP_SENDER_H264_TYPE_PPS))
3596 {
3597
3598 /* Clear the send marker for special frames. */
3599 send_marker = NX_FALSE;
3600 }
3601
3602 /* Check the frame size and determine if more than 1 packet are needed. */
3603 if (nal_unit_size <= max_packet_length)
3604 {
3605
3606 /* RTP payload format for single NAL unit packet (in this case, the NAL header byte is the same as VCL header byte):
3607 0 1 2 3
3608 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3609 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3610 |F|NRI| Type | |
3611 +-+-+-+-+-+-+-+-+ |
3612 | |
3613 | Bytes 2..n of a single NAL unit |
3614 | |
3615 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3616 | :...OPTIONAL RTP padding |
3617 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3618 */
3619
3620 /* Allocate a rtp packet */
3621 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
3622 if (status)
3623 {
3624 return(status);
3625 }
3626
3627 /* Copy payload data into the packet. */
3628 status = nx_packet_data_append(send_packet, (void*)nal_unit_start, nal_unit_size,
3629 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr,
3630 NX_RTP_SENDER_PACKET_TIMEOUT);
3631 if (status)
3632 {
3633 nx_packet_release(send_packet);
3634 return(status);
3635 }
3636
3637 /* Send packet data */
3638 status = _nx_rtp_sender_session_packet_send(session, send_packet, timestamp, ntp_msw, ntp_lsw, send_marker);
3639 if (status)
3640 {
3641 nx_packet_release(send_packet);
3642 return(status);
3643 }
3644 }
3645 else
3646 {
3647
3648 /* RTP payload format for FU-A packets (in this case, 1 byte VCL header extends to 2 bytes NAL header):
3649 0 1 2 3
3650 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3651 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3652 | FU indicator | FU header | |
3653 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
3654 | |
3655 | FU payload |
3656 | |
3657 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3658 | :...OPTIONAL RTP padding |
3659 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3660
3661 1) Format for FU indicator octet: 2) Format for FU header:
3662 +---------------+ +---------------+
3663 |0|1|2|3|4|5|6|7| |0|1|2|3|4|5|6|7|
3664 +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
3665 |F|NRI| Type | |S|E|R| Type |
3666 +---------------+ +---------------+
3667 */
3668
3669 /* Reserve the bytes space for fu-a header. */
3670 max_packet_length -= sizeof(fu_a_header);
3671
3672 /* Compute the number of packets with the size of the last packet. */
3673 packet_num = ((nal_unit_size - 1) / max_packet_length) + 1;
3674 last_packet_size = nal_unit_size % max_packet_length;
3675
3676 /* Initialize fu-a header's first byte with the source priority and fu-a type. */
3677 fu_a_header[0] = (UCHAR)((nal_unit_type & NX_RTP_SENDER_H264_NRI_MASK_BITS) | NX_RTP_SENDER_H264_TYPE_FU_A);
3678
3679 /* Initialize fu-a header's second byte with the source nal unit type. */
3680 fu_a_header[1] = (UCHAR)(nal_unit_type & NX_RTP_SENDER_H264_TYPE_MASK_BITS);
3681
3682 for (i = 0; i < packet_num; i++)
3683 {
3684
3685 /* Check which packet to transmit and execute different corresponding logic. */
3686 if (i == 0)
3687 {
3688
3689 /* Set the fu-a start bit for the first frame fragment. */
3690 fu_a_header[1] |= NX_RTP_SENDER_H264_FU_A_S_MASK_BIT;
3691
3692 /* Set the send marker as false. */
3693 temp_marker = NX_FALSE;
3694
3695 /* Skip the first NAL unit type byte, and update the send packet length. */
3696 nal_unit_start++;
3697 send_packet_length = max_packet_length - 1;
3698 }
3699 else if (i == (packet_num - 1))
3700 {
3701
3702 /* Clear the fu-a start bit and set fu-a end bit for the last frame fragment. */
3703 fu_a_header[1] &= (UCHAR)(~NX_RTP_SENDER_H264_FU_A_S_MASK_BIT);
3704 fu_a_header[1] |= NX_RTP_SENDER_H264_FU_A_E_MASK_BIT;
3705
3706 /* Update send marker by the final data frame flag. */
3707 temp_marker = send_marker;
3708
3709 /* Update packet length based on whether the last packet size is not zero. */
3710 send_packet_length = last_packet_size ? last_packet_size : max_packet_length;
3711 }
3712 else
3713 {
3714
3715 /* Clear the fu-a start bit for middle slices. */
3716 fu_a_header[1] &= (UCHAR)(~NX_RTP_SENDER_H264_FU_A_S_MASK_BIT);
3717
3718 /* Update the send packet length. */
3719 send_packet_length = max_packet_length;
3720 }
3721
3722 /* Allocate a packet */
3723 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
3724 if (status)
3725 {
3726 return(status);
3727 }
3728
3729 /* Copy fu-a header into the packet. */
3730 status = nx_packet_data_append(send_packet, (void *)fu_a_header, sizeof(fu_a_header),
3731 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr,
3732 NX_RTP_SENDER_PACKET_TIMEOUT);
3733 if (status)
3734 {
3735 nx_packet_release(send_packet);
3736 return(status);
3737 }
3738
3739 /* Copy payload data into the packet. */
3740 status = nx_packet_data_append(send_packet, (void *)nal_unit_start, send_packet_length,
3741 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr,
3742 NX_RTP_SENDER_PACKET_TIMEOUT);
3743 if (status)
3744 {
3745 nx_packet_release(send_packet);
3746 return(status);
3747 }
3748
3749 /* Send packet data */
3750 status = _nx_rtp_sender_session_packet_send(session, send_packet, timestamp, ntp_msw, ntp_lsw, temp_marker);
3751 if (status)
3752 {
3753 nx_packet_release(send_packet);
3754 return(status);
3755 }
3756
3757 /* Move start pointer to following position. */
3758 nal_unit_start += send_packet_length;
3759 }
3760 }
3761 }
3762
3763 /* Return success status. */
3764 return(NX_SUCCESS);
3765 }
3766
3767 /**************************************************************************/
3768 /* */
3769 /* FUNCTION RELEASE */
3770 /* */
3771 /* _nxe_rtp_sender_session_aac_send PORTABLE C */
3772 /* 6.3.0 */
3773 /* AUTHOR */
3774 /* */
3775 /* Haiqing Zhao, Microsoft Corporation */
3776 /* */
3777 /* DESCRIPTION */
3778 /* */
3779 /* This function checks errors in the RTP sender session aac send */
3780 /* function call. */
3781 /* */
3782 /* INPUT */
3783 /* */
3784 /* session Pointer to RTP session */
3785 /* frame_data Pointer to data buffer to send */
3786 /* frame_data_size Size of data to send */
3787 /* timestamp RTP timestamp for current data */
3788 /* ntp_msw Most significant word of */
3789 /* network time */
3790 /* ntp_lsw Least significant word of */
3791 /* network time */
3792 /* marker Marker bit for significant */
3793 /* event such as frame boundary */
3794 /* */
3795 /* OUTPUT */
3796 /* */
3797 /* status Completion status */
3798 /* NX_PTR_ERROR Invalid pointer input */
3799 /* */
3800 /* CALLS */
3801 /* */
3802 /* _nx_rtp_sender_session_aac_send Send aac frame data */
3803 /* */
3804 /* CALLED BY */
3805 /* */
3806 /* Application Code */
3807 /* */
3808 /* RELEASE HISTORY */
3809 /* */
3810 /* DATE NAME DESCRIPTION */
3811 /* */
3812 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
3813 /* */
3814 /**************************************************************************/
_nxe_rtp_sender_session_aac_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)3815 UINT _nxe_rtp_sender_session_aac_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
3816 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
3817 {
3818
3819 UINT status;
3820
3821
3822 /* Check for invalid input pointers. */
3823 if ((session == NX_NULL) || (session -> nx_rtp_sender == NX_NULL) || (session -> nx_rtp_session_id != NX_RTP_SESSION_ID) || (frame_data == NX_NULL))
3824 {
3825 return(NX_PTR_ERROR);
3826 }
3827
3828 /* Call actual RTP sender session frame send service. */
3829 status = _nx_rtp_sender_session_aac_send(session, frame_data, frame_data_size, timestamp, ntp_msw, ntp_lsw, marker);
3830
3831 /* Return status. */
3832 return(status);
3833 }
3834
3835 /**************************************************************************/
3836 /* */
3837 /* FUNCTION RELEASE */
3838 /* */
3839 /* _nx_rtp_sender_session_aac_send PORTABLE C */
3840 /* 6.3.0 */
3841 /* AUTHOR */
3842 /* */
3843 /* Haiqing Zhao, Microsoft Corporation */
3844 /* */
3845 /* DESCRIPTION */
3846 /* */
3847 /* This function parses and makes the passed data in RTP/AAC format, */
3848 /* and then calls RTP session send function to send these data in RTP */
3849 /* packet, with AAC-HBR mode. */
3850 /* The function references RFC 3640 as the standard with below notes: */
3851 /* 1) A complete aac frame data shall be inside frame data buffer */
3852 /* 2) SDP shall indicate that aac-hbr mode is applied, with SizeLength */
3853 /* field to be 13 since 13-bit frame length is applied for */
3854 /* computing the length in AU header. */
3855 /* */
3856 /* INPUT */
3857 /* */
3858 /* session Pointer to RTP session */
3859 /* frame_data Pointer to data buffer to send */
3860 /* frame_data_size Size of data to send */
3861 /* timestamp RTP timestamp for current data */
3862 /* ntp_msw Most significant word of */
3863 /* network time */
3864 /* ntp_lsw Least significant word of */
3865 /* network time */
3866 /* marker Marker bit for significant */
3867 /* event such as frame boundary */
3868 /* */
3869 /* OUTPUT */
3870 /* */
3871 /* status Completion status */
3872 /* */
3873 /* CALLS */
3874 /* */
3875 /* _nx_rtp_sender_session_packet_allocate */
3876 /* Allocate a packet for the user */
3877 /* nx_packet_data_append Copy the specified data to */
3878 /* the end of specified packet */
3879 /* nx_packet_data_release Release the packet */
3880 /* _nx_rtp_sender_session_packet_send Send RTP packet */
3881 /* */
3882 /* CALLED BY */
3883 /* */
3884 /* Application Code */
3885 /* */
3886 /* RELEASE HISTORY */
3887 /* */
3888 /* DATE NAME DESCRIPTION */
3889 /* */
3890 /* 10-31-2023 Haiqing Zhao Initial Version 6.3.0 */
3891 /* */
3892 /**************************************************************************/
_nx_rtp_sender_session_aac_send(NX_RTP_SESSION * session,UCHAR * frame_data,ULONG frame_data_size,ULONG timestamp,ULONG ntp_msw,ULONG ntp_lsw,UINT marker)3893 UINT _nx_rtp_sender_session_aac_send(NX_RTP_SESSION *session, UCHAR *frame_data, ULONG frame_data_size,
3894 ULONG timestamp, ULONG ntp_msw, ULONG ntp_lsw, UINT marker)
3895 {
3896
3897 UINT status;
3898 UCHAR au_header[4] = {0x00, 0x10, 0x00, 0x00}; /* First 2 bytes represent au header length, with default 16 bits. */
3899 ULONG send_packet_length;
3900 ULONG max_packet_length = session -> nx_rtp_session_max_packet_size - sizeof(au_header);
3901 NX_PACKET *send_packet = NX_NULL;
3902 UCHAR *data_ptr;
3903 UINT temp_marker;
3904
3905
3906 /* In current design, the marker bit shall be always 1 (i.e. a complete aac frame required to be passed). */
3907 if (marker != NX_TRUE)
3908 {
3909 return(NX_NOT_SUPPORTED);
3910 }
3911
3912 /* When frame data exceeds maximum defined value, it requires access unit fragment feature which is not supported so far.
3913 This check is specific for aac-hbr mode. */
3914 if (frame_data_size > NX_RTP_SENDER_AAC_HBR_MODE_MAX_DATA_SIZE)
3915 {
3916 return(NX_NOT_SUPPORTED);
3917 }
3918
3919 /* Initialize data_ptr to where data bytes begin. */
3920 data_ptr = frame_data;
3921
3922 while (frame_data_size > 0)
3923 {
3924
3925 /* Allocate a rtp packet. */
3926 status = _nx_rtp_sender_session_packet_allocate(session, &send_packet, NX_RTP_SENDER_PACKET_TIMEOUT);
3927 if (status)
3928 {
3929 return(status);
3930 }
3931
3932 /* Check if fragmentation needed, and assign data length. */
3933 if (frame_data_size > max_packet_length)
3934 {
3935 send_packet_length = max_packet_length;
3936 temp_marker = NX_FALSE;
3937 }
3938 else
3939 {
3940 send_packet_length = frame_data_size;
3941 temp_marker = NX_TRUE;
3942 }
3943
3944 /* Compute the data length inside the current packet. */
3945 au_header[2] = (UCHAR)((send_packet_length & NX_RTP_SENDER_AAC_FRAME_DATA_LENGTH_HIGH_BITS_MASK) >> 5);
3946 au_header[3] = (UCHAR)((send_packet_length & NX_RTP_SENDER_AAC_FRAME_DATA_LENGTH_LOW_BITS_MASK) << 3);
3947
3948 /* Copy aac header data into the packet. */
3949 status = nx_packet_data_append(send_packet, (void *)au_header, sizeof(au_header),
3950 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3951 if (status)
3952 {
3953 nx_packet_release(send_packet);
3954 return(status);
3955 }
3956
3957 /* Copy payload data into the packet. */
3958 status = nx_packet_data_append(send_packet, (void *)data_ptr, send_packet_length,
3959 session -> nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_RTP_SENDER_PACKET_TIMEOUT);
3960 if (status)
3961 {
3962 nx_packet_release(send_packet);
3963 return(status);
3964 }
3965
3966 /* Send AAC frame through rtp; passed marker bit with true when this is the last frame packet. */
3967 status = _nx_rtp_sender_session_packet_send(session, send_packet, timestamp, ntp_msw, ntp_lsw, temp_marker);
3968 if (status)
3969 {
3970 nx_packet_release(send_packet);
3971 return(status);
3972 }
3973
3974 /* Compute remaining frame length and move data pointer. */
3975 frame_data_size -= send_packet_length;
3976 data_ptr += send_packet_length;
3977 }
3978
3979 /* Return success status. */
3980 return(NX_SUCCESS);
3981 }
3982