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 TEST_SAMPLE_FACTOR         2
29 
30 /* Define the number of tests to do */
31 #define TEST_CYCLES                7
32 
33 static UCHAR test_rtp_packet_data[] = "test rtp packet data";
34 static UCHAR test_long_rtp_packet_data[200];
35 
36 /* Define the ThreadX object control blocks...  */
37 
38 static TX_THREAD                   ntest_0;
39 static TX_THREAD                   ntest_1;
40 
41 static NX_PACKET_POOL              pool_0;
42 static NX_IP                       ip_0;
43 static NX_IP                       ip_1;
44 static NX_UDP_SOCKET               rtp_client_socket;
45 
46 static TX_SEMAPHORE                semaphore_test_0_done;
47 static TX_SEMAPHORE                semaphore_test_1_done;
48 
49 /* Define rtp sender control block.  */
50 static NX_RTP_SENDER               rtp_0;
51 static NX_RTP_SESSION              rtp_session_0;
52 static UINT                        rtp_port;
53 static UINT                        rtcp_port;
54 
55 
56 /* Define thread prototypes.  */
57 
58 static void ntest_0_entry(ULONG thread_input);
59 static void ntest_1_entry(ULONG thread_input);
60 extern void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
61 extern void test_control_return(UINT status);
62 
63 #ifdef CTEST
test_application_define(void * first_unused_memory)64 VOID test_application_define(void *first_unused_memory)
65 #else
66 void    netx_rtp_session_packet_send_test_application_define(void *first_unused_memory)
67 #endif
68 {
69 
70 CHAR       *pointer;
71 UINT        status;
72 
73     /* Print out test information banner.  */
74     printf("NetX Test:   RTP Session Packet Send Test............................................");
75 
76     /* Setup the working pointer.  */
77     pointer = (CHAR *)first_unused_memory;
78 
79     /* Create the server thread.  */
80     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
81                      pointer, DEMO_STACK_SIZE,
82                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
83 
84     pointer = pointer + DEMO_STACK_SIZE;
85 
86     /* Create the client thread.  */
87     tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
88                      pointer, DEMO_STACK_SIZE,
89                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
90 
91     pointer = pointer + DEMO_STACK_SIZE;
92 
93     /* Initialize the NetX system.  */
94     nx_system_initialize();
95 
96     /* Create a packet pool.  */
97     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pointer, PACKET_POOL_SIZE);
98     pointer = pointer + PACKET_POOL_SIZE;
99     CHECK_STATUS(0, status);
100 
101     /* Create server IP instance.  */
102     status = nx_ip_create(&ip_0, "NetX IP Instance 0", RTP_SERVER_ADDRESS, 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
103                           pointer, 2048, 1);
104     pointer = pointer + 2048;
105     CHECK_STATUS(0, status);
106 
107     /* Create client IP instance.  */
108     status = nx_ip_create(&ip_1, "NetX IP Instance 1", RTP_CLIENT_ADDRESS, 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
109                           pointer, 2048, 1);
110     pointer = pointer + 2048;
111     CHECK_STATUS(0, status);
112 
113     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
114     status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
115     pointer = pointer + 1024;
116     CHECK_STATUS(0, status);
117 
118     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
119     status = nx_arp_enable(&ip_1, (void *) pointer, 1024);
120     pointer = pointer + 1024;
121     CHECK_STATUS(0, status);
122 
123     /* Enable UDP processing for both IP instances.  */
124     status = nx_udp_enable(&ip_0);
125     CHECK_STATUS(0, status);
126     status = nx_udp_enable(&ip_1);
127     CHECK_STATUS(0, status);
128 
129     /* Create semaphores for test done notification */
130     tx_semaphore_create(&semaphore_test_0_done, "semaphore test 0", 0);
131     tx_semaphore_create(&semaphore_test_1_done, "semaphore test 1", 0);
132 }
133 
134 /* Define server threads.  */
ntest_0_entry(ULONG thread_input)135 static void    ntest_0_entry(ULONG thread_input)
136 {
137 UINT          status;
138 NXD_ADDRESS   client_ip_address;
139 NX_PACKET    *send_packet;
140 UINT          time_start;
141 ULONG         temp_socket_id;
142 
143 
144     /* Create RTP sender.  */
145     status = nx_rtp_sender_create(&rtp_0, &ip_0, &pool_0, CNAME, sizeof(CNAME) - 1);
146     CHECK_STATUS(0, status);
147 
148     /* Get the udp port pair for rtp and rtcp */
149     status = nx_rtp_sender_port_get(&rtp_0, &rtp_port, &rtcp_port);
150     CHECK_STATUS(0, status);
151 
152     /* Setup rtp sender session.  */
153     client_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
154     client_ip_address.nxd_ip_address.v4 = RTP_CLIENT_ADDRESS;
155     status = nx_rtp_sender_session_create(&rtp_0, &rtp_session_0, RTP_PAYLOAD_TYPE,
156                                           0, &client_ip_address,
157                                           RTP_CLIENT_RTP_PORT, RTP_CLIENT_RTCP_PORT);
158     CHECK_STATUS(0, status);
159 
160     /* If more than one rtp packet is sent during the first tick, rtcp packet will also be sent more than once.
161        To make a stable test result, wait for a tick here to avoid this situation. */
162     tx_thread_sleep(1);
163 
164     /* ---- Test cycle 1 ---- */
165 
166     /* Allocate a packet */
167     status = nx_rtp_sender_session_packet_allocate(&rtp_session_0, &send_packet, 5 * NX_IP_PERIODIC_RATE);
168     CHECK_STATUS(0, status);
169 
170     /* Copy payload data into the packet. */
171     status = nx_packet_data_append(send_packet, (void*)test_rtp_packet_data, sizeof(test_rtp_packet_data), rtp_0.nx_rtp_sender_ip_ptr->nx_ip_default_packet_pool, 5 * NX_IP_PERIODIC_RATE);
172     CHECK_STATUS(0, status);
173 
174 #ifndef TX_DISABLE_ERROR_CHECKING
175     /* Reserver the rtp socket id, set the rtp socket id to 0 to force the send fail */
176     temp_socket_id = rtp_session_0.nx_rtp_sender -> nx_rtp_sender_rtp_socket.nx_udp_socket_id;
177     rtp_session_0.nx_rtp_sender -> nx_rtp_sender_rtp_socket.nx_udp_socket_id = 0;
178     status = nx_rtp_sender_session_packet_send(&rtp_session_0, send_packet, TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
179     CHECK_STATUS(NX_PTR_ERROR, status);
180 
181     /* Recover the socket id */
182     rtp_session_0.nx_rtp_sender -> nx_rtp_sender_rtp_socket.nx_udp_socket_id = temp_socket_id;
183 
184     /* Check if the function can return error status when prepend pointer is incorrect */
185     send_packet -> nx_packet_prepend_ptr--;
186     status = nx_rtp_sender_session_packet_send(&rtp_session_0, send_packet, TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
187     CHECK_STATUS(NX_UNDERFLOW, status);
188 
189     /* Set back prepend pointer to correct position and check the send function could execute correctly */
190     send_packet -> nx_packet_prepend_ptr++;
191 #endif /* TX_DISABLE_ERROR_CHECKING */
192 
193     status = nx_rtp_sender_session_packet_send(&rtp_session_0, send_packet, TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
194     CHECK_STATUS(0, status);
195 
196     /* ---- Test cycle 2 ~ 4 ---- */
197     send_packet = NX_NULL;
198 
199     /* Allocate a packet */
200     status = nx_rtp_sender_session_packet_allocate(&rtp_session_0, &send_packet, 5 * NX_IP_PERIODIC_RATE);
201     CHECK_STATUS(0, status);
202 
203     /* Copy payload data into the packet many times to have 3 fragmentation packets. */
204     for (UINT i = 0; i < sizeof(test_long_rtp_packet_data); i++)
205     {
206         test_long_rtp_packet_data[i] = i % 100;
207     }
208     status = nx_packet_data_append(send_packet, (void*)test_long_rtp_packet_data, sizeof(test_long_rtp_packet_data), rtp_0.nx_rtp_sender_ip_ptr->nx_ip_default_packet_pool, 5 * NX_IP_PERIODIC_RATE);
209     CHECK_STATUS(0, status);
210     status = nx_rtp_sender_session_packet_send(&rtp_session_0, send_packet, TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
211     CHECK_STATUS(0, status);
212 
213     /* ---- Test cycle 5 ~ 7 ---- */
214     send_packet = NX_NULL;
215 
216     /* Allocate a packet */
217     status = nx_rtp_sender_session_packet_allocate(&rtp_session_0, &send_packet, 5 * NX_IP_PERIODIC_RATE);
218     CHECK_STATUS(0, status);
219     status = nx_packet_data_append(send_packet, (void*)test_long_rtp_packet_data, sizeof(test_long_rtp_packet_data), rtp_0.nx_rtp_sender_ip_ptr->nx_ip_default_packet_pool, 5 * NX_IP_PERIODIC_RATE);
220     CHECK_STATUS(0, status);
221 
222     /* Set the sample factor to trigger sample-based mode, and then send fragmentation packets in order to observer timestamp automatical change */
223     status = nx_rtp_sender_session_sample_factor_set(&rtp_session_0, TEST_SAMPLE_FACTOR);
224     status = nx_rtp_sender_session_packet_send(&rtp_session_0, send_packet, TEST_TIMESTAMP, TEST_MSW, TEST_LSW, 1);
225     CHECK_STATUS(0, status);
226 
227     /* Wait for the check in test thread 1 done. */
228     status = tx_semaphore_get(&semaphore_test_1_done, 5 * NX_IP_PERIODIC_RATE);
229     CHECK_STATUS(0, status);
230 
231     /* Delete and release resources */
232     status = nx_rtp_sender_session_delete(&rtp_session_0);
233     CHECK_STATUS(0, status);
234 
235     status = nx_rtp_sender_delete(&rtp_0);
236     CHECK_STATUS(0, status);
237 
238     /* Put the semaphore to notify thread 1 it is fine to check resource leakage. */
239     tx_semaphore_put(&semaphore_test_0_done);
240 }
241 
242 /* Define the client threads.  */
ntest_1_entry(ULONG thread_input)243 static void    ntest_1_entry(ULONG thread_input)
244 {
245 NX_PACKET *received_packet;
246 UINT       status;
247 UCHAR     *data;
248 UINT       test_data_pos = 0;
249 
250 
251     /* Create the rtp client socket.  */
252     status = nx_udp_socket_create(&ip_1, &rtp_client_socket, "RTCP Client Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5);
253     CHECK_STATUS(0, status);
254 
255     status =  nx_udp_socket_bind(&rtp_client_socket, RTP_CLIENT_RTP_PORT, NX_IP_PERIODIC_RATE);
256     CHECK_STATUS(0, status);
257 
258     for (UINT i = 0; i < TEST_CYCLES; i++)
259     {
260 
261         /* Receive rtp data packet. */
262         status = nx_udp_socket_receive(&rtp_client_socket, &received_packet, 5 * TX_TIMER_TICKS_PER_SECOND);
263         CHECK_STATUS(0, status);
264 
265         /* Validate RTP payload data */
266         data = received_packet -> nx_packet_prepend_ptr;
267 
268         /* Check RTP version byte */
269         CHECK_STATUS(0x80, *data);
270 
271         /* Move to check RTP data byte for payload type with marker */
272         data++;
273         if (i == 1 || i == 2)
274         {
275             CHECK_STATUS((RTP_PAYLOAD_TYPE), *data);
276         }
277         else
278         {
279             CHECK_STATUS((NX_RTP_HEADER_MARKER_BIT | RTP_PAYLOAD_TYPE), *data);
280         }
281 
282         /* Move to check RTP data bytes for sequence number */
283         data++;
284         CHECK_STATUS((rtp_session_0.nx_rtp_session_sequence_number - 1), (data[0] << 8 | data[1]));
285 
286         /* Move to check RTP data bytes for time stamp */
287         data += 2;
288         CHECK_STATUS(rtp_session_0.nx_rtp_session_rtp_timestamp, (ULONG)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]));
289 
290         /* Move to check RTP data bytes for ssrc */
291         data += 4;
292         CHECK_STATUS(rtp_session_0.nx_rtp_session_ssrc, (ULONG)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]));
293 
294         /* Move to check RTP data bytes for data payload */
295         data += 4;
296         if (i == 0)
297         {
298             for (UINT j = 0; j < sizeof(test_rtp_packet_data); j++)
299             {
300                 CHECK_STATUS(*(test_rtp_packet_data + j), data[j]);
301             }
302         }
303         else if (i >= 1 && i <= 6)
304         {
305 
306             /* Check fragmentation packets in frame-based mode */
307             while (data < received_packet -> nx_packet_append_ptr)
308             {
309                 CHECK_STATUS(test_long_rtp_packet_data[test_data_pos], *data);
310                 test_data_pos++;
311                 data++;
312             }
313 
314             /* Check and reset test data position for following test to use */
315             if (i == 3 || i == 6)
316             {
317                 test_data_pos = 0;
318             }
319         }
320 
321         /* Release the receive packet when the check finishes. */
322         nx_packet_release(received_packet);
323     }
324 
325     /* Set the flag to notify test thread 0 that the check finishes. */
326     tx_semaphore_put(&semaphore_test_1_done);
327 
328     /* Wait for the check in test thread 0 done. */
329     status = tx_semaphore_get(&semaphore_test_0_done, 5 * NX_IP_PERIODIC_RATE);
330     CHECK_STATUS(0, status);
331 
332     /* Check if there is memory leak. */
333     CHECK_STATUS(pool_0.nx_packet_pool_total, pool_0.nx_packet_pool_available);
334 
335     /* Return the test result.  */
336     printf("SUCCESS!\n");
337     test_control_return(0);
338 }
339 
340 #else
341 
342 #ifdef CTEST
test_application_define(void * first_unused_memory)343 VOID test_application_define(void *first_unused_memory)
344 #else
345 void    netx_rtp_session_packet_send_test_application_define(void *first_unused_memory)
346 #endif
347 {
348 
349     /* Print out test information banner.  */
350     printf("NetX Test:   RTP Session Packet Send Test............................................N/A\n");
351 
352     test_control_return(3);
353 }
354 #endif
355 
356