1 #include "tx_api.h"
2 #include "nx_api.h"
3 #include "netxtestcontrol.h"
4
5 extern void test_control_return(UINT);
6
7 #if !defined(NX_DISABLE_IPV4) && defined(__PRODUCT_NETXDUO__) && !defined(NX_DISABLE_PACKET_CHAIN)
8 #include "nx_rtp_sender.h"
9
10 #define DEMO_STACK_SIZE 4096
11
12 #define NUM_PACKETS 10
13 #define PACKET_SIZE 1536
14 #define PACKET_POOL_SIZE (NUM_PACKETS * (PACKET_SIZE + sizeof(NX_PACKET)))
15
16 #define RTP_SERVER_ADDRESS IP_ADDRESS(1,2,3,4)
17 #define RTP_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5)
18 #define RTP_CLIENT_RTP_PORT 6002
19 #define RTP_CLIENT_RTCP_PORT 6003
20 #define RTP_PAYLOAD_TYPE 96
21 #define CNAME "AzureRTOS@microsoft.com"
22
23 /* Define test data. */
24 #define TEST_TIMESTAMP 1234
25 #define TEST_MSW 123
26 #define TEST_LSW 456
27
28 /* Define the number of tests to do */
29 #define TEST_CYCLES (6 + 8) /* 6 packets, 8 slices */
30
31 /* Define h264 test data */
32 static UCHAR test_rtp_packet_data[] = { 0x00, 0x00, 0x01, 0x65, /* h264 header started with 0x000001 */
33 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, /* Test data */
34 }; /* test_rtp_packet_data */
35
36 static UCHAR test_medium_rtp_packet_data[] = { 0x00, 0x00, 0x00, 0x01, 0x65, /* h264 header started with 0x00000001 */
37
38 /* Test data */
39 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
40 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
41 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
42 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
43 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
44 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
45 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
46 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
47 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
48 }; /* test_rtp_packet_data */
49
50 static UCHAR test_long_rtp_packet_data[] = { 0x00, 0x00, 0x00, 0x01, 0x65, /* h264 header started with 0x00000001 */
51
52 /* Test data */
53 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
54 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
55 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
56 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
57 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
58 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
59 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
60 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
61 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
62 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
63 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
64 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
65 }; /* test_rtp_packet_data */
66
67 static UCHAR test_rtp_packet_slices_data[] = { 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
68 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
69 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
70 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
71 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
72 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
73 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
74 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
75 }; /* test_rtp_packet_data */
76
77 /* Define the ThreadX object control blocks... */
78
79 static TX_THREAD ntest_0;
80 static TX_THREAD ntest_1;
81
82 static NX_PACKET_POOL pool_0;
83 static NX_IP ip_0;
84 static NX_IP ip_1;
85 static NX_UDP_SOCKET rtp_client_socket;
86
87 static TX_SEMAPHORE semaphore_test_0_done;
88 static TX_SEMAPHORE semaphore_test_1_done;
89
90 /* Define rtp sender control block. */
91 static NX_RTP_SENDER rtp_0;
92 static NX_RTP_SESSION rtp_session_0;
93 static UINT rtp_port;
94 static UINT rtcp_port;
95
96
97 /* Define thread prototypes. */
98
99 static void ntest_0_entry(ULONG thread_input);
100 static void ntest_1_entry(ULONG thread_input);
101 extern void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
102 extern void test_control_return(UINT status);
103
104 #ifdef CTEST
test_application_define(void * first_unused_memory)105 VOID test_application_define(void *first_unused_memory)
106 #else
107 void netx_rtp_session_h264_send_test_application_define(void *first_unused_memory)
108 #endif
109 {
110
111 CHAR *pointer;
112 UINT status;
113
114 /* Print out test information banner. */
115 printf("NetX Test: RTP Session H264 Send Test............................................");
116
117 /* Setup the working pointer. */
118 pointer = (CHAR *)first_unused_memory;
119
120 /* Create the server thread. */
121 tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
122 pointer, DEMO_STACK_SIZE,
123 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
124
125 pointer = pointer + DEMO_STACK_SIZE;
126
127 /* Create the client thread. */
128 tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
129 pointer, DEMO_STACK_SIZE,
130 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
131
132 pointer = pointer + DEMO_STACK_SIZE;
133
134 /* Initialize the NetX system. */
135 nx_system_initialize();
136
137 /* Create a packet pool. */
138 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pointer, PACKET_POOL_SIZE);
139 pointer = pointer + PACKET_POOL_SIZE;
140 CHECK_STATUS(0, status);
141
142 /* Create server IP instance. */
143 status = nx_ip_create(&ip_0, "NetX IP Instance 0", RTP_SERVER_ADDRESS, 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
144 pointer, 2048, 1);
145 pointer = pointer + 2048;
146 CHECK_STATUS(0, status);
147
148 /* Create client IP instance. */
149 status = nx_ip_create(&ip_1, "NetX IP Instance 1", RTP_CLIENT_ADDRESS, 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
150 pointer, 2048, 1);
151 pointer = pointer + 2048;
152 CHECK_STATUS(0, status);
153
154 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
155 status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
156 pointer = pointer + 1024;
157 CHECK_STATUS(0, status);
158
159 /* Enable ARP and supply ARP cache memory for IP Instance 1. */
160 status = nx_arp_enable(&ip_1, (void *) pointer, 1024);
161 pointer = pointer + 1024;
162 CHECK_STATUS(0, status);
163
164 /* Enable UDP processing for both IP instances. */
165 status = nx_udp_enable(&ip_0);
166 CHECK_STATUS(0, status);
167 status = nx_udp_enable(&ip_1);
168 CHECK_STATUS(0, status);
169
170 /* Create semaphores for test done notification */
171 tx_semaphore_create(&semaphore_test_0_done, "semaphore test 0", 0);
172 tx_semaphore_create(&semaphore_test_1_done, "semaphore test 1", 0);
173 }
174
validate_rtp_h264_data(UCHAR * data,UINT data_length)175 static UINT validate_rtp_h264_data(UCHAR *data, UINT data_length)
176 {
177 UINT i;
178 UCHAR *data_ptr = data;
179
180
181 /* In single NAL mode, the first byte shall be the same as the first pointful byte in the source h264 header*/
182 if (data_ptr[0] != 0x65)
183 {
184 return(NX_NOT_SUCCESSFUL);
185 }
186 data_ptr++;
187
188 /* Check h264 image data */
189 i = 0;
190 while (data_ptr < (data + data_length))
191 {
192 if (*data_ptr != test_rtp_packet_data[4 + i]) /* Skip 4 header bytes */
193 {
194 return(NX_NOT_SUCCESSFUL);
195 }
196
197 i++;
198 data_ptr++;
199 }
200
201 return(NX_SUCCESS);
202 }
203
validate_rtp_h264_fragmentation_data(UINT index,UCHAR * data,UINT data_length)204 static UINT validate_rtp_h264_fragmentation_data(UINT index, UCHAR *data, UINT data_length)
205 {
206 UCHAR *test_data;
207 UCHAR *data_ptr = data;
208 static ULONG offset = 0;
209
210
211 /* 0x7C: high priority and FU-A mode */
212 if (data_ptr[0] != 0x7C)
213 {
214 return(NX_NOT_SUCCESSFUL);
215 }
216 data_ptr++;
217
218 switch (index)
219 {
220 case 1:
221 test_data = test_medium_rtp_packet_data;
222 /* 0x85: start bit set and IDR picture */
223 if (data_ptr[0] != 0x85)
224 {
225 return(NX_NOT_SUCCESSFUL);
226 }
227 break;
228
229 case 3:
230 test_data = test_long_rtp_packet_data;
231 /* 0x85: start bit set and IDR picture */
232 if (data_ptr[0] != 0x85)
233 {
234 return(NX_NOT_SUCCESSFUL);
235 }
236 break;
237
238 case 4:
239 test_data = test_long_rtp_packet_data;
240 /* 0x05: IDR picture */
241 if (data_ptr[0] != 0x05)
242 {
243 return(NX_NOT_SUCCESSFUL);
244 }
245 break;
246
247 case 2:
248 test_data = test_medium_rtp_packet_data;
249 /* 0x45: end bit set and IDR picture */
250 if (data_ptr[0] != 0x45)
251 {
252 return(NX_NOT_SUCCESSFUL);
253 }
254 break;
255 case 5:
256 test_data = test_long_rtp_packet_data;
257 /* 0x45: end bit set and IDR picture */
258 if (data_ptr[0] != 0x45)
259 {
260 return(NX_NOT_SUCCESSFUL);
261 }
262 break;
263
264 default:
265 return(NX_NOT_SUCCESSFUL);
266 }
267 data_ptr++;
268
269 /* Check JPEG image data */
270 while (data_ptr < (data + data_length))
271 {
272 if (*data_ptr != test_data[5 + offset]) /* Skip 5 header bytes */
273 {
274 return(NX_NOT_SUCCESSFUL);
275 }
276
277 offset++;
278 data_ptr++;
279 }
280
281 /* Clear offset for long data test */
282 if (index == 2)
283 {
284 offset = 0;
285 }
286
287 return(NX_SUCCESS);
288 }
289
validate_rtp_h264_slice_data(UCHAR * data,UINT data_length)290 static UINT validate_rtp_h264_slice_data(UCHAR *data, UINT data_length)
291 {
292 UINT i;
293 UCHAR *data_ptr = data;
294
295
296 /* In single NAL mode, the first byte shall be the same as the first pointful byte in the source h264 header*/
297 if (data_ptr[0] != 0x61)
298 {
299 return(NX_NOT_SUCCESSFUL);
300 }
301 data_ptr++;
302
303 /* Check h264 image data */
304 i = 0;
305 while (1)
306 {
307 if (*data_ptr != test_rtp_packet_data[4 + i]) /* Skip 4 header bytes */
308 {
309 return(NX_NOT_SUCCESSFUL);
310 }
311
312 if (data_ptr >= (data + data_length - 4)) /* Skip 4 byte h264 header */
313 {
314 break;
315 }
316
317 i++;
318 data_ptr++;
319 }
320
321 return(NX_SUCCESS);
322 }
323
324 /* Define server threads. */
ntest_0_entry(ULONG thread_input)325 static void ntest_0_entry(ULONG thread_input)
326 {
327 UINT status;
328 NXD_ADDRESS client_ip_address;
329 NX_PACKET *send_packet;
330 UINT time_start;
331 ULONG temp_socket_id;
332
333
334 /* Create RTP sender. */
335 status = nx_rtp_sender_create(&rtp_0, &ip_0, &pool_0, CNAME, sizeof(CNAME) - 1);
336 CHECK_STATUS(0, status);
337
338 /* Get the udp port pair for rtp and rtcp */
339 status = nx_rtp_sender_port_get(&rtp_0, &rtp_port, &rtcp_port);
340 CHECK_STATUS(0, status);
341
342 /* Setup rtp sender session. */
343 client_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
344 client_ip_address.nxd_ip_address.v4 = RTP_CLIENT_ADDRESS;
345 status = nx_rtp_sender_session_create(&rtp_0, &rtp_session_0, RTP_PAYLOAD_TYPE,
346 0, &client_ip_address,
347 RTP_CLIENT_RTP_PORT, RTP_CLIENT_RTCP_PORT);
348 CHECK_STATUS(0, status);
349
350 /* If more than one rtp packet is sent during the first tick, rtcp packet will also be sent more than once.
351 To make a stable test result, wait for a tick here to avoid this situation. */
352 tx_thread_sleep(1);
353
354 /* ---- Test cycle 1 ---- */
355
356 /* Send h264 data. */
357 status = nx_rtp_sender_session_h264_send(&rtp_session_0, test_rtp_packet_data, sizeof(test_rtp_packet_data), TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
358 CHECK_STATUS(NX_SUCCESS, status);
359
360 /* ---- Test cycle 2 ~ 3 ---- */
361 /* Send h264 data. */
362 status = nx_rtp_sender_session_h264_send(&rtp_session_0, test_medium_rtp_packet_data, sizeof(test_medium_rtp_packet_data), TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
363 CHECK_STATUS(NX_SUCCESS, status);
364
365 /* ---- Test cycle 4 ~ 6 ---- */
366
367 /* Send h264 data. */
368 status = nx_rtp_sender_session_h264_send(&rtp_session_0, test_long_rtp_packet_data, sizeof(test_long_rtp_packet_data), TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
369 CHECK_STATUS(NX_SUCCESS, status);
370
371 /* ---- Test cycle 7 ~ 14 ---- */
372
373 /* Send h264 data. */
374 status = nx_rtp_sender_session_h264_send(&rtp_session_0, test_rtp_packet_slices_data, sizeof(test_rtp_packet_slices_data), TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
375 CHECK_STATUS(NX_SUCCESS, status);
376
377 /* Wait for the check in test thread 1 done. */
378 status = tx_semaphore_get(&semaphore_test_1_done, 5 * NX_IP_PERIODIC_RATE);
379 CHECK_STATUS(0, status);
380
381 /* Delete and release resources */
382 status = nx_rtp_sender_session_delete(&rtp_session_0);
383 CHECK_STATUS(0, status);
384
385 status = nx_rtp_sender_delete(&rtp_0);
386 CHECK_STATUS(0, status);
387
388 /* Put the semaphore to notify thread 1 it is fine to check resource leakage. */
389 tx_semaphore_put(&semaphore_test_0_done);
390 }
391
392 /* Define the client threads. */
ntest_1_entry(ULONG thread_input)393 static void ntest_1_entry(ULONG thread_input)
394 {
395 NX_PACKET *received_packet;
396 UINT j;
397 UINT status;
398 UCHAR *data;
399 UINT test_data_pos = 0;
400 ULONG offset = 0;
401
402
403 /* Create the rtp client socket. */
404 status = nx_udp_socket_create(&ip_1, &rtp_client_socket, "RTCP Client Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5);
405 CHECK_STATUS(0, status);
406
407 status = nx_udp_socket_bind(&rtp_client_socket, RTP_CLIENT_RTP_PORT, NX_IP_PERIODIC_RATE);
408 CHECK_STATUS(0, status);
409
410 for (UINT i = 0; i < TEST_CYCLES; i++)
411 {
412
413 /* Receive rtp data packet. */
414 status = nx_udp_socket_receive(&rtp_client_socket, &received_packet, 5 * TX_TIMER_TICKS_PER_SECOND);
415 CHECK_STATUS(0, status);
416
417 /* Validate RTP payload data */
418 data = received_packet -> nx_packet_prepend_ptr;
419
420 /* Check RTP version byte */
421 CHECK_STATUS(0x80, *data);
422
423 /* Move to check RTP data byte for payload type with marker */
424 data++;
425 if (i == 0 || i == 2 || i == 5 || i == 13)
426 {
427 CHECK_STATUS((NX_RTP_HEADER_MARKER_BIT | RTP_PAYLOAD_TYPE), *data);
428 }
429 else
430 {
431 CHECK_STATUS((RTP_PAYLOAD_TYPE), *data);
432 }
433
434 /* Move to check RTP data bytes for sequence number */
435 data++;
436 CHECK_STATUS((rtp_session_0.nx_rtp_session_sequence_number - 1), (data[0] << 8 | data[1]));
437
438 /* Move to check RTP data bytes for time stamp */
439 data += 2;
440 CHECK_STATUS(rtp_session_0.nx_rtp_session_rtp_timestamp, (ULONG)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]));
441
442 /* Move to check RTP data bytes for ssrc */
443 data += 4;
444 CHECK_STATUS(rtp_session_0.nx_rtp_session_ssrc, (ULONG)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]));
445
446 /* Move to check RTP data bytes for data payload */
447 data += 4;
448 if (i == 0)
449 {
450 status = validate_rtp_h264_data(data, received_packet -> nx_packet_length - 12);
451 CHECK_STATUS(NX_SUCCESS, status);
452 }
453 else if (i >= 1 && i <= 5)
454 {
455 status = validate_rtp_h264_fragmentation_data(i, data, received_packet -> nx_packet_length - 12);
456 CHECK_STATUS(NX_SUCCESS, status);
457 }
458 else
459 {
460 status = validate_rtp_h264_slice_data(data, received_packet -> nx_packet_length - 12);
461 if (status)
462 CHECK_STATUS(NX_SUCCESS, status);
463 }
464
465 /* Release the receive packet when the check finishes. */
466 nx_packet_release(received_packet);
467 }
468
469 /* Set the flag to notify test thread 0 that the check finishes. */
470 tx_semaphore_put(&semaphore_test_1_done);
471
472 /* Wait for the check in test thread 0 done. */
473 status = tx_semaphore_get(&semaphore_test_0_done, 5 * NX_IP_PERIODIC_RATE);
474 CHECK_STATUS(0, status);
475
476 /* Check if there is memory leak. */
477 CHECK_STATUS(pool_0.nx_packet_pool_total, pool_0.nx_packet_pool_available);
478
479 /* Return the test result. */
480 printf("SUCCESS!\n");
481 test_control_return(0);
482 }
483
484 #else
485
486 #ifdef CTEST
test_application_define(void * first_unused_memory)487 VOID test_application_define(void *first_unused_memory)
488 #else
489 void netx_rtp_session_h264_send_test_application_define(void *first_unused_memory)
490 #endif
491 {
492
493 /* Print out test information banner. */
494 printf("NetX Test: RTP Session H264 Send Test............................................N/A\n");
495
496 test_control_return(3);
497 }
498 #endif
499
500