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