1 /* This is the test control routine the NetX RTSP module.  All tests are dispatched from this routine.  */
2 
3 #include "tx_api.h"
4 #include "nx_api.h"
5 #include "nx_rtsp_server.h"
6 #include "nx_rtp_sender.h"
7 #include "demo_rtsp_over_rtp.h"
8 
9 
10 /* Define the stack size for demo tasks. */
11 #define DEMO_TEST_STACK_SIZE              2048
12 #define DEMO_RTSP_SERVER_STACK_SIZE       2048
13 static UCHAR test_thread_stack[DEMO_TEST_STACK_SIZE];
14 static UCHAR rtsp_server_stack[DEMO_RTSP_SERVER_STACK_SIZE];
15 
16 /* Define rtp cname which is typically used in rtcp sender report. */
17 #define DEMO_RTP_CNAME                    "AzureRTOS@microsoft.com"
18 
19 /* Define multicast corresponding parameters. !Note: these parameters in sdp shall be changed with the same values. */
20 #ifdef DEMO_MULTICAST_ENABLED
21 
22 #ifndef DEMO_MULTICAST_IP_ADDRESS
23 #define DEMO_MULTICAST_IP_ADDRESS         IP_ADDRESS(224, 1, 0, 55)
24 #endif /* DEMO_MULTICAST_IP_ADDRESS */
25 
26 #ifndef DEMO_MULTICAST_RTP_PORT
27 #define DEMO_MULTICAST_RTP_PORT           6002
28 #endif /* DEMO_MULTICAST_RTP_PORT */
29 
30 #ifndef DEMO_MULTICAST_RTCP_PORT
31 #define DEMO_MULTICAST_RTCP_PORT          6003
32 #endif /* DEMO_MULTICAST_RTCP_PORT */
33 
34 #endif /* DEMO_MULTICAST_ENABLED */
35 
36 /* The RTSP server listening port.  */
37 #ifndef DEMO_RTSP_SERVER_PORT
38 #define DEMO_RTSP_SERVER_PORT             554
39 #endif /* DEMO_RTSP_SERVER_PORT */
40 
41 /* The RTSP server thread priority.  */
42 #ifndef DEMO_RTSP_SERVER_PRIORITY
43 #define DEMO_RTSP_SERVER_PRIORITY         3
44 #endif /* DEMO_RTSP_SERVER_PRIORITY */
45 
46 /* File name shown in rtsp SETUP request */
47 #ifndef DEMO_RTSP_VIDEO_FILE_NAME
48 #define DEMO_RTSP_VIDEO_FILE_NAME         "trackID=0"
49 #endif /* DEMO_RTSP_VIDEO_FILE_NAME */
50 
51 #ifndef DEMO_RTSP_AUDIO_FILE_NAME
52 #define DEMO_RTSP_AUDIO_FILE_NAME         "trackID=1"
53 #endif /* DEMO_RTSP_AUDIO_FILE_NAME */
54 
55 /* Define RTP payload type for medias. !Note: payload type in sdp shall be changed with the same values */
56 #ifndef DEMO_RTP_PAYLOAD_TYPE_VIDEO
57 #if (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_MJPEG)
58 #define DEMO_RTP_PAYLOAD_TYPE_VIDEO       26
59 #else
60 #define DEMO_RTP_PAYLOAD_TYPE_VIDEO       96 /* Use dynamic type range from 96 to 127 */
61 #endif /* (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_MJPEG) */
62 #endif /* DEMO_RTP_PAYLOAD_TYPE_VIDEO */
63 
64 #ifndef DEMO_RTP_PAYLOAD_TYPE_AUDIO
65 #if (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_AAC)
66 #define DEMO_RTP_PAYLOAD_TYPE_AUDIO       97
67 #else
68 #define DEMO_RTP_PAYLOAD_TYPE_AUDIO       11
69 #endif /* (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_AAC) */
70 #endif /* DEMO_RTP_PAYLOAD_TYPE_AUDIO */
71 
72 /* Define video & audio play fps. !Note: this macro shall be the same as the real FPS to guarantee video playing normally */
73 #ifndef DEMO_VIDEO_FRAME_PER_SECOND
74 #define DEMO_VIDEO_FRAME_PER_SECOND       30
75 #endif /* DEMO_VIDEO_FRAME_PER_SECOND */
76 
77 #ifndef DEMO_AUDIO_FRAME_PER_SECOND
78 #define DEMO_AUDIO_FRAME_PER_SECOND       43 /* Reference the comment of DEMO_RTP_AUDIO_SAMPLING_PERIOD
79                                                 to understand how this macro is calculated and defined. */
80 #endif /* DEMO_AUDIO_FRAME_PER_SECOND */
81 
82 #ifndef DEMO_AUDIO_SAMPLE_SIZE
83 #define DEMO_AUDIO_SAMPLE_SIZE            16 /* Indicate the size in bits for each audio sample. */
84 #endif /* DEMO_AUDIO_SAMPLE_SIZE */
85 
86 #ifndef DEMO_AUDIO_CHANNEL_NUM
87 #define DEMO_AUDIO_CHANNEL_NUM            1
88 #endif /* DEMO_AUDIO_CHANNEL_NUM */
89 
90 /* The sampling periods define rtp timestamp increase rate for medias. */
91 #define DEMO_RTP_VIDEO_SAMPLING_PERIOD    (90000 / DEMO_VIDEO_FRAME_PER_SECOND)
92 #define DEMO_RTP_AUDIO_SAMPLING_PERIOD    (44100 / DEMO_AUDIO_FRAME_PER_SECOND)  /* Assume the default AAC sampling rate is 44100.
93                                                                                     Normally, a single ACC frame contains 1024 samples;
94                                                                                     So, there are 44100 / 1024 = 43 frames per second.
95                                                                                     Therefore, sampling period is 44100 / 43 = 1025. */
96 
97 /* Define frame play internal for medias */
98 #define DEMO_RTP_VIDEO_PLAY_INTERVAL      (1000 / DEMO_VIDEO_FRAME_PER_SECOND)
99 #define DEMO_RTP_AUDIO_PLAY_INTERVAL      (1000 / DEMO_AUDIO_FRAME_PER_SECOND)
100 
101 #ifndef DEMO_PLAY_TIMER_INTERVAL
102 #define DEMO_PLAY_TIMER_INTERVAL          10 /* Per miliseconds */
103 #endif /* DEMO_PLAY_TIMER_INTERVAL */
104 
105 /* Declare the prototypes for the test entry points. */
106 TX_THREAD            test_thread;
107 NX_RTSP_SERVER       rtsp_0;
108 NX_RTP_SENDER        rtp_0;
109 
110 /* Declare events to use in threads. */
111 TX_EVENT_FLAGS_GROUP demo_test_events;
112 
113 /* Declare the timer to trigger events (e.g., playing video/audio). */
114 TX_TIMER             demo_timer;
115 
116 /* Declare the sample structure to support multiple clients interaction. */
117 typedef struct SAMPLE_CLIENT_STRUCT
118 {
119     NX_RTSP_CLIENT   *rtsp_client_ptr;
120 
121     /* RTP sessions */
122     NX_RTP_SESSION   rtp_session_video;
123     NX_RTP_SESSION   rtp_session_audio;
124 
125     /* Count the number of clients setup in the specific rtp session */
126     USHORT           rtp_session_video_client_count;
127     USHORT           rtp_session_audio_client_count;
128 
129     /* RTP timestamp and NTP timestamp */
130     ULONG            rtp_session_video_timestamp;
131     ULONG            rtp_session_audio_timestamp;
132 
133 #ifdef DEMO_PLAY_BY_TIMER
134     /* Accumulated ticks for determining when to play a video/audio frame */
135     volatile ULONG   video_play_time_ms;
136     volatile ULONG   audio_play_time_ms;
137 #endif /* DEMO_PLAY_BY_TIMER */
138 } SAMPLE_CLIENT;
139 
140 #ifdef DEMO_MULTICAST_ENABLED
141 SAMPLE_CLIENT        sample_client_multicast;
142 #else
143 SAMPLE_CLIENT        sample_client[NX_RTSP_SERVER_MAX_CLIENTS];
144 #endif  /* DEMO_MULTICAST_ENABLED */
145 
146 /* Define an error counter.  */
147 ULONG                error_counter;
148 
149 
150 /* Internal functions prototype. */
151 static UINT rtsp_describe_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length);
152 static UINT rtsp_setup_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, NX_RTSP_TRANSPORT *transport_ptr);
153 static UINT rtsp_play_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *range_ptr, UINT range_length);
154 static UINT rtsp_teardown_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length);
155 static UINT rtsp_pause_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *range_ptr, UINT range_length);
156 static UINT rtsp_set_parameter_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *parameter_ptr, ULONG parameter_length);
157 static UINT rtsp_disconnect_callback(NX_RTSP_CLIENT *rtsp_client_ptr);
158 
159 static UINT test_rtcp_receiver_report_callback(NX_RTP_SESSION *session, NX_RTCP_RECEIVER_REPORT *report);
160 static UINT test_rtcp_sdes_callback(NX_RTCP_SDES_INFO *sdes_info);
161 
162 static VOID (*demo_media_data_init_callback)(VOID) = DEMO_MEDIA_DATA_INIT;
163 static UINT (*demo_video_data_read_callback)(ULONG *ntp_msw, ULONG *ntp_lsw, UCHAR **data_ptr, ULONG *data_size) = DEMO_VIDEO_DATA_READ;
164 static UINT (*demo_audio_data_read_callback)(ULONG *ntp_msw, ULONG *ntp_lsw, UCHAR **data_ptr, ULONG *data_size) = DEMO_AUDIO_DATA_READ;
165 
166 
167 #ifdef DEMO_PLAY_BY_TIMER
demo_timer_entry(ULONG address)168 static VOID demo_timer_entry(ULONG address)
169 {
170 SAMPLE_CLIENT *client_ptr;
171 
172 #ifdef DEMO_MULTICAST_ENABLED
173     client_ptr = &sample_client_multicast;
174 #else
175     for (UINT i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
176     {
177         client_ptr = &sample_client[i];
178 #endif /* DEMO_MULTICAST_ENABLED */
179 
180         if (client_ptr -> rtp_session_video_client_count)
181         {
182             client_ptr -> video_play_time_ms += DEMO_PLAY_TIMER_INTERVAL;
183             if (client_ptr -> video_play_time_ms >= DEMO_RTP_VIDEO_PLAY_INTERVAL)
184             {
185 
186                 /* Send the video ready event. */
187                 tx_event_flags_set(&demo_test_events, DEMO_VIDEO_DATA_READY_EVENT, TX_OR);
188             }
189         }
190         if (client_ptr -> rtp_session_audio_client_count)
191         {
192             client_ptr -> audio_play_time_ms += DEMO_PLAY_TIMER_INTERVAL;
193             if (client_ptr -> audio_play_time_ms >= DEMO_RTP_AUDIO_PLAY_INTERVAL)
194             {
195 
196                 /* Send the audio ready event. */
197                 tx_event_flags_set(&demo_test_events, DEMO_AUDIO_DATA_READY_EVENT, TX_OR);
198             }
199         }
200 #ifndef DEMO_MULTICAST_ENABLED
201     }
202 #endif /* DEMO_MULTICAST_ENABLED */
203 }
204 #endif /* DEMO_PLAY_BY_TIMER */
205 
206 /* Define what the initial system looks like.  */
sample_entry(NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,VOID * dns_ptr,UINT (* unix_time_callback)(ULONG * unix_time))207 void sample_entry(NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, VOID *dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time))
208 {
209 UINT           i = 0;
210 UINT           status;
211 ULONG          events = 0;
212 UCHAR          initialized = NX_FALSE;
213 ULONG          ntp_msw, ntp_lsw;
214 UCHAR         *data;
215 ULONG          data_length;
216 #if (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_PCM)
217 NX_PACKET     *send_packet = NX_NULL;
218 #endif /* (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_PCM) */
219 #ifndef DEMO_MULTICAST_ENABLED
220 SAMPLE_CLIENT *client_ptr;
221 #else
222 SAMPLE_CLIENT *client_ptr = &sample_client_multicast;
223 
224 
225     /* Enable IGMP.  */
226     status = nx_igmp_enable(ip_ptr);
227 
228     /* Join multicast group. */
229     status += nx_ipv4_multicast_interface_join(ip_ptr, DEMO_MULTICAST_IP_ADDRESS, 0);
230     if (status)
231         error_counter++;
232 #endif  /* DEMO_MULTICAST_ENABLED */
233 
234     status = nx_ip_fragment_enable(ip_ptr);
235     if (status)
236         error_counter++;
237 
238     /* Create RTP sender */
239     nx_rtp_sender_create(&rtp_0, ip_ptr, pool_ptr, DEMO_RTP_CNAME, sizeof(DEMO_RTP_CNAME) - 1);
240     nx_rtp_sender_rtcp_receiver_report_callback_set(&rtp_0, test_rtcp_receiver_report_callback);
241     nx_rtp_sender_rtcp_sdes_callback_set(&rtp_0, test_rtcp_sdes_callback);
242 
243     /* Create RTSP server. */
244     nx_rtsp_server_create(&rtsp_0, "RTSP Server", sizeof("RTSP Server") - 1, ip_ptr, pool_ptr,
245                           rtsp_server_stack, DEMO_RTSP_SERVER_STACK_SIZE, DEMO_RTSP_SERVER_PRIORITY, DEMO_RTSP_SERVER_PORT, rtsp_disconnect_callback);
246 
247     /* Set callback functions. */
248     nx_rtsp_server_describe_callback_set(&rtsp_0, rtsp_describe_callback);
249     nx_rtsp_server_setup_callback_set(&rtsp_0, rtsp_setup_callback);
250     nx_rtsp_server_play_callback_set(&rtsp_0, rtsp_play_callback);
251     nx_rtsp_server_teardown_callback_set(&rtsp_0, rtsp_teardown_callback);
252     nx_rtsp_server_pause_callback_set(&rtsp_0, rtsp_pause_callback);
253     nx_rtsp_server_set_parameter_callback_set(&rtsp_0, rtsp_set_parameter_callback);
254 
255     /* Start RTSP server. */
256     nx_rtsp_server_start(&rtsp_0);
257 
258     printf("RTSP server started!\r\n");
259 
260     /* Create event for the play thread */
261     status = tx_event_flags_create(&demo_test_events, "Demo events");
262     if (status)
263         error_counter++;
264 
265 #ifdef DEMO_PLAY_BY_TIMER
266     /* Create the global timeout timer.  */
267     status = tx_timer_create(&demo_timer, "Demo Timer", demo_timer_entry, 0,
268                              (DEMO_PLAY_TIMER_INTERVAL * NX_IP_PERIODIC_RATE / 1000),
269                              (DEMO_PLAY_TIMER_INTERVAL * NX_IP_PERIODIC_RATE / 1000),
270                              TX_AUTO_ACTIVATE);
271     if (status)
272         error_counter++;
273 #endif /* DEMO_PLAY_BY_TIMER */
274 
275     /* Enter server test. */
276     while (1)
277     {
278 
279         tx_event_flags_get(&demo_test_events, DEMO_ALL_EVENTS, TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
280 
281         /*********************************************
282         ************** DEMO_PLAY_EVENT ***************
283         *********************************************/
284         if (events & DEMO_PLAY_EVENT)
285         {
286             if (initialized == NX_FALSE)
287             {
288 
289                 /* Call user registered callback function to initialize. */
290                 if (demo_media_data_init_callback)
291                 {
292                     demo_media_data_init_callback();
293                 }
294 
295 #ifdef DEMO_PLAY_BY_TIMER
296                 /* Set an initial value to eliminate too many ticks accumulation. */
297 #ifdef DEMO_MULTICAST_ENABLED
298                 client_ptr -> video_play_time_ms = 0;
299                 client_ptr -> audio_play_time_ms = 0;
300 #else
301                 for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
302                 {
303                     client_ptr = &sample_client[i];
304                     sample_client[i].video_play_time_ms = 0;
305                     sample_client[i].audio_play_time_ms = 0;
306                 }
307 #endif /* DEMO_MULTICAST_ENABLED */
308 #endif /* DEMO_PLAY_BY_TIMER */
309             }
310 
311             /* Set the initialized flag */
312             initialized = NX_TRUE;
313         }
314 
315         /*********************************************
316         ************ DEMO_TEARDOWN_EVENT *************
317         *********************************************/
318         if (events & DEMO_TEARDOWN_EVENT)
319         {
320 #ifdef DEMO_MULTICAST_ENABLED
321             if ((client_ptr -> rtp_session_video_client_count == 0) &&
322                 (client_ptr -> rtp_session_audio_client_count == 0))
323             {
324                 initialized = NX_FALSE;
325             }
326 
327 #ifdef DEMO_PLAY_BY_TIMER
328             client_ptr -> video_play_time_ms = 0;
329             client_ptr -> audio_play_time_ms = 0;
330 #endif /* DEMO_PLAY_BY_TIMER */
331 #else
332             /* Check all client count to determine whether to clear the initialized flag */
333             for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
334             {
335                 client_ptr = &sample_client[i];
336                 if ((client_ptr -> rtp_session_video_client_count) ||
337                     (client_ptr -> rtp_session_audio_client_count))
338                 {
339                     break;
340                 }
341             }
342             if (i == NX_RTSP_SERVER_MAX_CLIENTS)
343             {
344                 initialized = NX_FALSE;
345 
346 #ifdef DEMO_PLAY_BY_TIMER
347                 for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
348                 {
349                     client_ptr -> video_play_time_ms = 0;
350                     client_ptr -> audio_play_time_ms = 0;
351                 }
352 #endif /* DEMO_PLAY_BY_TIMER */
353             }
354 #endif
355         }
356 
357         /*********************************************
358         ******** DEMO_VIDEO_DATA_READY_EVENT *********
359         *********************************************/
360         if (events & DEMO_VIDEO_DATA_READY_EVENT)
361         {
362 
363             /* Check if a play event has already triggered. */
364             if (initialized == NX_TRUE)
365             {
366 
367                 /* Check if the user has redefined DEMO_VIDEO_DATA_READ which registers video data read callback function. */
368                 if (demo_video_data_read_callback == NX_NULL)
369                 {
370                     printf("User must implement video data read function and redefine DEMO_VIDEO_DATA_READ\r\n");
371                     continue;
372                 }
373 
374                 /* Read video data and transmit it */
375                 data_length = 0;
376                 if ((demo_video_data_read_callback(&ntp_msw, &ntp_lsw, &data, &data_length) == NX_SUCCESS) && (data_length > 0))
377                 {
378 #ifndef DEMO_MULTICAST_ENABLED
379                     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
380                     {
381                         client_ptr = &sample_client[i];
382 #endif /* DEMO_MULTICAST_ENABLED */
383 
384                         /* Make sure at least one client having setup the connection. */
385                         if (client_ptr -> rtp_session_video_client_count == 0)
386                         {
387                             continue;
388                         }
389 
390 #if (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264)
391                         status = nx_rtp_sender_session_h264_send(&(client_ptr -> rtp_session_video), data, data_length,
392                                                                  client_ptr -> rtp_session_video_timestamp, ntp_msw, ntp_lsw, NX_TRUE);
393 #else
394                         status = nx_rtp_sender_session_jpeg_send(&(client_ptr -> rtp_session_video), data, data_length,
395                                                                  client_ptr -> rtp_session_video_timestamp, ntp_msw, ntp_lsw, NX_TRUE);
396 #endif /* (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264) */
397                         if (status)
398                         {
399                             printf("Fail to send video frame: %d, %d\r\n", i, status);
400                         }
401 
402                         /* Update rtp timestamp video sampling period. */
403                         client_ptr -> rtp_session_video_timestamp += DEMO_RTP_VIDEO_SAMPLING_PERIOD;
404 
405 #ifdef DEMO_PLAY_BY_TIMER
406                         if (client_ptr -> video_play_time_ms >= DEMO_RTP_VIDEO_PLAY_INTERVAL)
407                         {
408                             client_ptr -> video_play_time_ms -= DEMO_RTP_VIDEO_PLAY_INTERVAL;
409                         }
410 #endif /* DEMO_PLAY_BY_TIMER */
411 #ifndef DEMO_MULTICAST_ENABLED
412                     }
413 #endif /* DEMO_MULTICAST_ENABLED */
414                 }
415             }
416         }
417 
418         /*********************************************
419         ******** DEMO_AUDIO_DATA_READY_EVENT *********
420         *********************************************/
421         if (events & DEMO_AUDIO_DATA_READY_EVENT)
422         {
423 
424             /* Check if a play event has already triggered. */
425             if (initialized == NX_TRUE)
426             {
427 
428                 /* Check if the user has redefined DEMO_AUDIO_DATA_READ which registers audio data read callback function. */
429                 if (demo_audio_data_read_callback == NX_NULL)
430                 {
431                     printf("User must implement audio data read function and redefine DEMO_AUDIO_DATA_READ\r\n");
432                     continue;
433                 }
434 
435                 /* Read audio data and transmit it */
436                 data_length = 0;
437                 if ((demo_audio_data_read_callback(&ntp_msw, &ntp_lsw, &data, &data_length) == NX_SUCCESS) && (data_length > 0))
438                 {
439 #ifndef DEMO_MULTICAST_ENABLED
440                     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
441                     {
442                         client_ptr = &sample_client[i];
443 #endif /* DEMO_MULTICAST_ENABLED */
444 
445                         /* Make sure at least one client having setup the connection. */
446                         if (client_ptr -> rtp_session_audio_client_count == 0)
447                         {
448                             continue;
449                         }
450 
451 #if (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_AAC)
452                         status = nx_rtp_sender_session_aac_send(&(client_ptr -> rtp_session_audio), data, data_length,
453                                                                 client_ptr -> rtp_session_audio_timestamp, ntp_msw, ntp_lsw, NX_TRUE);
454                         if (status)
455                         {
456                             printf("Fail to send audio frame: %d, %d\r\n", i, status);
457                         }
458 
459                         client_ptr -> rtp_session_audio_timestamp += DEMO_RTP_AUDIO_SAMPLING_PERIOD;
460 #else
461                         /* Allocate a rtp packet. */
462                         nx_rtp_sender_session_packet_allocate(&(client_ptr -> rtp_session_audio), &send_packet, NX_WAIT_FOREVER);
463 
464                         /* Copy payload data into the packet. */
465                         status = nx_packet_data_append(send_packet, (void *)data, data_length,
466                                                     client_ptr -> rtp_session_audio.nx_rtp_sender -> nx_rtp_sender_packet_pool_ptr, NX_WAIT_FOREVER);
467                         if (status)
468                         {
469                             nx_packet_release(send_packet);
470                         }
471 
472                         /* Send audio data frame through rtp */
473                         status = nx_rtp_sender_session_packet_send(&(client_ptr -> rtp_session_audio), send_packet,
474                                                                 client_ptr -> rtp_session_audio_timestamp, ntp_msw, ntp_lsw, NX_FALSE);
475                         if (status)
476                         {
477                             nx_packet_release(send_packet);
478                             printf("Fail to send audio data: %d, %d\r\n", i, status);
479                         }
480 
481                         /* Update rtp timestamp by the number of sampling bytes. */
482                         client_ptr -> rtp_session_audio_timestamp += (data_length / (DEMO_AUDIO_SAMPLE_SIZE / 8));
483 #endif /* (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_AAC) */
484 
485 #ifdef DEMO_PLAY_BY_TIMER
486                         if (client_ptr -> audio_play_time_ms >= DEMO_RTP_AUDIO_PLAY_INTERVAL)
487                         {
488                             client_ptr -> audio_play_time_ms -= DEMO_RTP_AUDIO_PLAY_INTERVAL;
489                         }
490 #endif /* DEMO_PLAY_BY_TIMER */
491 #ifndef DEMO_MULTICAST_ENABLED
492                     }
493 #endif /* DEMO_MULTICAST_ENABLED */
494                 }
495             }
496         }
497     }
498 }
499 
500 
501 /* SDP string options. */
502 #ifdef DEMO_MULTICAST_ENABLED
503 #if (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264)
504 #define DEMO_SDP \
505 "v=0\r\ns=H264 video with AAC audio, streamed by the NetX RTSP Server\r\n"\
506 "m=video 6002 RTP/AVP 96\r\n"\
507 "c=IN IP4 224.1.0.55/128\r\n"\
508 "a=rtpmap:96 H264/90000\r\n"\
509 "a=fmtp:96 profile-level-id=42A01E; packetization-mode=1\r\n"\
510 "a=control:trackID=0\r\n"\
511 "m=audio 6002 RTP/AVP 97\r\n"\
512 "c=IN IP4 224.1.0.55/128\r\n"\
513 "a=rtpmap:97 mpeg4-generic/44100/1\r\n"\
514 "a=fmtp:97 mode=AAC-hbr; SizeLength=13\r\n"\
515 "a=control:trackID=1\r\n"
516 #else
517 #define DEMO_SDP \
518 "v=0\r\ns=MJPEG video with AAC audio, streamed by the NetX RTSP Server\r\n"\
519 "m=video 6002 RTP/AVP 26\r\n"\
520 "c=IN IP4 224.1.0.55/128\r\n"\
521 "a=rtpmap:26 JPEG/90000\r\n"\
522 "a=control:trackID=0\r\n"\
523 "m=audio 6002 RTP/AVP 11\r\n"\
524 "c=IN IP4 224.1.0.55/128\r\n"\
525 "a=rtpmap:11 L16/44100/1\r\n"\
526 "a=fmtp:11 emphasis=50-15\r\n"\
527 "a=ptime:5\r\n"\
528 "a=control:trackID=1\r\n"
529 #endif /* (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264) */
530 #else
531 #if (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264)
532 #define DEMO_SDP \
533 "v=0\r\ns=H264 video with AAC audio, streamed by the NetX RTSP Server\r\n"\
534 "m=video 0 RTP/AVP 96\r\n"\
535 "a=rtpmap:96 H264/90000\r\n"\
536 "a=fmtp:96 profile-level-id=42A01E; packetization-mode=1\r\n"\
537 "a=control:trackID=0\r\n"\
538 "m=audio 0 RTP/AVP 97\r\n"\
539 "a=rtpmap:97 mpeg4-generic/44100/1\r\n"\
540 "a=fmtp:97 mode=AAC-hbr; SizeLength=13\r\n"\
541 "a=control:trackID=1\r\n"
542 #else
543 #define DEMO_SDP \
544 "v=0\r\ns=MJPEG video with AAC audio, streamed by the NetX RTSP Server\r\n"\
545 "m=video 0 RTP/AVP 26\r\n"\
546 "a=rtpmap:26 JPEG/90000\r\n"\
547 "a=control:trackID=0\r\n"\
548 "m=audio 0 RTP/AVP 11\r\n"\
549 "a=rtpmap:11 L16/44100/1\r\n"\
550 "a=fmtp:11 emphasis=50-15\r\n"\
551 "a=ptime:5\r\n"\
552 "a=control:trackID=1\r\n"
553 #endif /* (DEMO_VIDEO_FORMAT == DEMO_VIDEO_FORMAT_H264) */
554 #endif /* DEMO_MULTICAST_ENABLED */
555 
556 
rtsp_describe_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length)557 static UINT rtsp_describe_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length)
558 {
559 UINT status;
560 
561 
562     status = nx_rtsp_server_sdp_set(rtsp_client_ptr, (UCHAR *)DEMO_SDP, sizeof(DEMO_SDP));
563     printf("RTSP request received: DESCRIBE.\r\n");
564     return(status);
565 }
566 
rtsp_setup_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length,NX_RTSP_TRANSPORT * transport_ptr)567 static UINT rtsp_setup_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, NX_RTSP_TRANSPORT *transport_ptr)
568 {
569 UINT status;
570 UINT rtp_port, rtcp_port;
571 SAMPLE_CLIENT *client_ptr = NX_NULL;
572 #ifndef DEMO_MULTICAST_ENABLED
573 UINT i;
574 #endif /* DEMO_MULTICAST_ENABLED */
575 
576 
577     /* Print information from the client */
578     printf("RTSP request received: SETUP.\r\nuri: %s\r\nclient RTP port %d, RTCP port %d, IP %lu.%lu.%lu.%lu\r\n", uri,
579            transport_ptr -> client_rtp_port, transport_ptr -> client_rtcp_port,
580            (transport_ptr -> client_ip_address.nxd_ip_address.v4 >> 24),
581            (transport_ptr -> client_ip_address.nxd_ip_address.v4 >> 16) & 0xFF,
582            (transport_ptr -> client_ip_address.nxd_ip_address.v4 >> 8) & 0xFF,
583            (transport_ptr -> client_ip_address.nxd_ip_address.v4 & 0xFF));
584 
585     /* Get the created and found ports */
586     status = nx_rtp_sender_port_get(&rtp_0, &rtp_port, &rtcp_port);
587     if (status)
588     {
589         return(status);
590     }
591     transport_ptr -> server_rtp_port = rtp_port;
592     transport_ptr -> server_rtcp_port = rtcp_port;
593 
594 #ifdef DEMO_MULTICAST_ENABLED
595     /* Judge and change to multicast if received ip address is 0 */
596     if (transport_ptr -> client_ip_address.nxd_ip_address.v4 != 0)
597     {
598         return(NX_NOT_SUCCESSFUL);
599     }
600 
601     /* Assign multicast ip address and rtp/rtcp ports */
602     transport_ptr -> client_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
603     transport_ptr -> client_ip_address.nxd_ip_address.v4 = DEMO_MULTICAST_IP_ADDRESS;
604     transport_ptr -> client_rtp_port = DEMO_MULTICAST_RTP_PORT;
605     transport_ptr -> client_rtcp_port = DEMO_MULTICAST_RTCP_PORT;
606     transport_ptr -> multicast_ttl = NX_RTP_SENDER_TIME_TO_LIVE;
607 
608     /* Directly use sample_client_multicast */
609     client_ptr = &sample_client_multicast;
610 #else
611     /* Find and store the RTSP client pointer.  */
612     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
613     {
614 
615         /* Check if the client is already linked. */
616         if (sample_client[i].rtsp_client_ptr == rtsp_client_ptr)
617         {
618             client_ptr = &(sample_client[i]);
619             break;
620         }
621 
622         if ((client_ptr == NX_NULL) && (sample_client[i].rtsp_client_ptr == NX_NULL))
623         {
624 
625             /* Record the unused position. */
626             client_ptr = &(sample_client[i]);
627         }
628     }
629 
630     /* Check and return error if reach max connected clients limitation. */
631     if (client_ptr == NX_NULL)
632     {
633         return(NX_NOT_SUCCESSFUL);
634     }
635 
636     /* Link the client pointer if it is newly assigned. */
637     if (i == NX_RTSP_SERVER_MAX_CLIENTS)
638     {
639         client_ptr -> rtsp_client_ptr = rtsp_client_ptr;
640     }
641 
642 #endif /* DEMO_MULTICAST_ENABLED */
643 
644     if (strstr((const char *)uri, DEMO_RTSP_VIDEO_FILE_NAME))
645     {
646         printf("Setup Video (track 0)..\r\n");
647 
648 #ifdef DEMO_MULTICAST_ENABLED
649         if (client_ptr -> rtp_session_video_client_count == 0)
650         {
651 #endif /* DEMO_MULTICAST_ENABLED */
652 
653             /* Setup rtp sender video session */
654             status = nx_rtp_sender_session_create(&rtp_0, &(client_ptr -> rtp_session_video), DEMO_RTP_PAYLOAD_TYPE_VIDEO,
655                                                   transport_ptr -> interface_index, &(transport_ptr -> client_ip_address),
656                                                   transport_ptr -> client_rtp_port, transport_ptr -> client_rtcp_port);
657             if (status)
658             {
659                 printf("Fail to create video session\r\n");
660 
661                 /* Reset the client pointer if error status happens */
662                 client_ptr -> rtsp_client_ptr = NX_NULL;
663                 return(status);
664             }
665 
666             /* Obtain generated ssrc */
667             status = nx_rtp_sender_session_ssrc_get(&(client_ptr -> rtp_session_video), &(transport_ptr -> rtp_ssrc));
668             if (status)
669             {
670 
671                 /* Reset the client pointer if error status happens */
672                 client_ptr -> rtsp_client_ptr = NX_NULL;
673                 return(status);
674             }
675 
676             /* Reset corresponding variables */
677             client_ptr -> rtp_session_video_timestamp = (ULONG)NX_RAND();
678 #ifdef DEMO_MULTICAST_ENABLED
679         }
680 #endif /* DEMO_MULTICAST_ENABLED */
681 
682         /* Increase the number of setup client. */
683         client_ptr -> rtp_session_video_client_count++;
684     }
685     else if (strstr((const char *)uri, DEMO_RTSP_AUDIO_FILE_NAME))
686     {
687         printf("Setup Audio (track 1)..\r\n");
688 
689 #ifdef DEMO_MULTICAST_ENABLED
690         if (client_ptr -> rtp_session_audio_client_count == 0)
691         {
692 #endif /* DEMO_MULTICAST_ENABLED */
693 
694             /* Setup rtp sender audio session */
695             status = nx_rtp_sender_session_create(&rtp_0, &(client_ptr -> rtp_session_audio), DEMO_RTP_PAYLOAD_TYPE_AUDIO,
696                                                   transport_ptr -> interface_index, &(transport_ptr -> client_ip_address),
697                                                   transport_ptr -> client_rtp_port, transport_ptr -> client_rtcp_port);
698             if (status)
699             {
700                 printf("Fail to create audio session\r\n");
701 
702                 /* Reset the client pointer if error status happens */
703                 client_ptr -> rtsp_client_ptr = NX_NULL;
704                 return(status);
705             }
706 
707             /* Obtain generated ssrc */
708             status = nx_rtp_sender_session_ssrc_get(&(client_ptr -> rtp_session_audio), &(transport_ptr -> rtp_ssrc));
709             if (status)
710             {
711 
712                 /* Reset the client pointer if error status happens */
713                 client_ptr -> rtsp_client_ptr = NX_NULL;
714                 return(status);
715             }
716 
717             /* Reset corresponding variables */
718             client_ptr -> rtp_session_audio_timestamp = (ULONG)NX_RAND();
719 
720 #if (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_PCM)
721             nx_rtp_sender_session_sample_factor_set(&(client_ptr -> rtp_session_audio), (DEMO_AUDIO_SAMPLE_SIZE / 8) * DEMO_AUDIO_CHANNEL_NUM);
722 #endif /* (DEMO_AUDIO_FORMAT == DEMO_AUDIO_FORMAT_PCM) */
723 #ifdef DEMO_MULTICAST_ENABLED
724         }
725 #endif /* DEMO_MULTICAST_ENABLED */
726 
727         /* Increase the number of setup client. */
728         client_ptr -> rtp_session_audio_client_count++;
729     }
730     else
731     {
732         printf("Invalid track ID!\r\n");
733         return(NX_NOT_SUCCESSFUL);
734     }
735 
736     return(NX_SUCCESS);
737 }
738 
rtsp_play_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length,UCHAR * range_ptr,UINT range_length)739 static UINT rtsp_play_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *range_ptr, UINT range_length)
740 {
741 UINT status;
742 UINT video_seq, audio_seq, video_rtptime, audio_rtptime;
743 SAMPLE_CLIENT *client_ptr;
744 #ifndef DEMO_MULTICAST_ENABLED
745 UINT i;
746 #endif
747 
748 
749     printf("RTSP request received: PLAY.\r\n");
750 
751 #ifndef DEMO_MULTICAST_ENABLED
752     /* Search and find the RTSP client. */
753     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
754     {
755         if (sample_client[i].rtsp_client_ptr == rtsp_client_ptr)
756         {
757             client_ptr = &sample_client[i];
758             break;
759         }
760     }
761     if (i == NX_RTSP_SERVER_MAX_CLIENTS)
762     {
763         printf("Fail to find rtsp client!\r\n");
764         return(NX_NOT_SUCCESSFUL);
765     }
766 #else
767     /* Directly use sample_client_multicast */
768     client_ptr = &sample_client_multicast;
769 #endif /* DEMO_MULTICAST_ENABLED */
770 
771     if (client_ptr -> rtp_session_video_client_count)
772     {
773 
774         /* Retrieve the sequence number through rtp sender functions */
775         nx_rtp_sender_session_sequence_number_get(&(client_ptr -> rtp_session_video), &video_seq);
776 
777         /* Assign recorded timestamps */
778         video_rtptime = client_ptr -> rtp_session_video_timestamp;
779 
780         /* Set rtp information into rtsp client */
781         status = nx_rtsp_server_rtp_info_set(rtsp_client_ptr, DEMO_RTSP_VIDEO_FILE_NAME, sizeof(DEMO_RTSP_VIDEO_FILE_NAME) - 1, video_seq, video_rtptime);
782         if (status)
783         {
784             return(status);
785         }
786     }
787 
788     if (client_ptr -> rtp_session_audio_client_count)
789     {
790 
791         /* Retrieve the sequence number through rtp sender functions */
792         nx_rtp_sender_session_sequence_number_get(&(client_ptr -> rtp_session_audio), &audio_seq);
793 
794         /* Assign recorded timestamps */
795         audio_rtptime = client_ptr -> rtp_session_audio_timestamp;
796 
797         /* Set rtp information into rtsp client */
798         status = nx_rtsp_server_rtp_info_set(rtsp_client_ptr, DEMO_RTSP_AUDIO_FILE_NAME, sizeof(DEMO_RTSP_AUDIO_FILE_NAME) - 1, audio_seq, audio_rtptime);
799         if (status)
800         {
801             return(status);
802         }
803     }
804 
805     /* Trigger the play event */
806     tx_event_flags_set(&demo_test_events, DEMO_PLAY_EVENT, TX_OR);
807 
808     return(NX_SUCCESS);
809 }
810 
rtsp_teardown_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length)811 static UINT rtsp_teardown_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length)
812 {
813 SAMPLE_CLIENT *client_ptr;
814 #ifndef DEMO_MULTICAST_ENABLED
815 UINT i;
816 
817 
818     printf("RTSP request received: TEARDOWN.\r\n");
819 
820     /* Find the RTSP client pointer.  */
821     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
822     {
823         if (sample_client[i].rtsp_client_ptr == rtsp_client_ptr)
824         {
825             client_ptr = &(sample_client[i]);
826             break;
827         }
828     }
829     if (i == NX_RTSP_SERVER_MAX_CLIENTS)
830     {
831         printf("Fail to find rtsp client!\r\n");
832         return(NX_NOT_SUCCESSFUL);
833     }
834 #else
835     /* Directly use sample_client_multicast */
836     client_ptr = &sample_client_multicast;
837 #endif /* DEMO_MULTICAST_ENABLED */
838 
839     /* Decrease session client count */
840     if (client_ptr -> rtp_session_video_client_count > 0)
841     {
842         client_ptr -> rtp_session_video_client_count--;
843 #ifdef DEMO_MULTICAST_ENABLED
844         if (client_ptr -> rtp_session_video_client_count == 0)
845 #endif
846         {
847             client_ptr -> rtsp_client_ptr = NX_NULL;
848             nx_rtp_sender_session_delete(&(client_ptr -> rtp_session_video));
849         }
850     }
851     if (client_ptr -> rtp_session_audio_client_count > 0)
852     {
853         client_ptr -> rtp_session_audio_client_count--;
854 #ifdef DEMO_MULTICAST_ENABLED
855         if (client_ptr -> rtp_session_audio_client_count == 0)
856 #endif
857         {
858             client_ptr -> rtsp_client_ptr = NX_NULL;
859             nx_rtp_sender_session_delete(&(client_ptr -> rtp_session_audio));
860         }
861     }
862 
863     /* Trigger the tear down event */
864     tx_event_flags_set(&demo_test_events, DEMO_TEARDOWN_EVENT, TX_OR);
865 
866     return(NX_SUCCESS);
867 }
868 
rtsp_pause_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length,UCHAR * range_ptr,UINT range_length)869 static UINT rtsp_pause_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *range_ptr, UINT range_length)
870 {
871     printf("RTSP request received: PAUSE.\r\n");
872 
873     return(NX_SUCCESS);
874 }
875 
rtsp_set_parameter_callback(NX_RTSP_CLIENT * rtsp_client_ptr,UCHAR * uri,UINT uri_length,UCHAR * parameter_ptr,ULONG parameter_length)876 static UINT rtsp_set_parameter_callback(NX_RTSP_CLIENT *rtsp_client_ptr, UCHAR *uri, UINT uri_length, UCHAR *parameter_ptr, ULONG parameter_length)
877 {
878     printf("RTSP request received: SET PARAMETER.\r\n");
879 
880     return(NX_SUCCESS);
881 }
882 
rtsp_disconnect_callback(NX_RTSP_CLIENT * rtsp_client_ptr)883 static UINT rtsp_disconnect_callback(NX_RTSP_CLIENT *rtsp_client_ptr)
884 {
885 
886     /* Trigger the tear down event */
887     tx_event_flags_set(&demo_test_events, DEMO_TEARDOWN_EVENT, TX_OR);
888 
889     return(NX_SUCCESS);
890 }
891 
test_rtcp_receiver_report_callback(NX_RTP_SESSION * session,NX_RTCP_RECEIVER_REPORT * report)892 static UINT test_rtcp_receiver_report_callback(NX_RTP_SESSION *session, NX_RTCP_RECEIVER_REPORT *report)
893 {
894 #ifndef DEMO_MULTICAST_ENABLED
895 UINT i;
896 
897     /* Search the rtsp client table and find which session it is*/
898     for (i = 0; i < NX_RTSP_SERVER_MAX_CLIENTS; i++)
899     {
900         if (session == &(sample_client[i].rtp_session_video))
901         {
902             break;
903         }
904         else if (session == &(sample_client[i].rtp_session_audio))
905         {
906             break;
907         }
908     }
909     if (i == NX_RTSP_SERVER_MAX_CLIENTS)
910     {
911 
912         /* Unkown session, return directly. */
913         return(NX_SUCCESS);
914     }
915 #endif /* DEMO_MULTICAST_ENABLED */
916 
917     /*
918         We can add user implementation code here..
919 
920         Note!: since this callback is invoked from the IP thread, the application should not block in this callback.
921 
922         Tip: in this callback, we can obtain and record below information:
923             1) report -> receiver_ssrc: the ssrc of the receiver who sends the rr report
924             2) report -> fraction_loss: the fraction lost of the receiver
925             3) report -> packet_loss: the cumulative number of packets lost of the receiver
926             4) report -> extended_max: the extended highest sequence number received of the receiver
927             5) report -> jitter: the inter-arrival jitter of the receiver
928             6) report -> last_sr: the last SR timestamp of the receiver
929             7) report -> delay: the delay since last SR timestamp of the receiver.
930     */
931 
932     /* Update the timeout of RTSP server since the RTCP message proves liveness.  */
933 #ifdef DEMO_MULTICAST_ENABLED
934     nx_rtsp_server_keepalive_update(sample_client_multicast.rtsp_client_ptr);
935 #else
936     nx_rtsp_server_keepalive_update(sample_client[i].rtsp_client_ptr);
937 #endif /* DEMO_MULTICAST_ENABLED */
938 
939     return(NX_SUCCESS);
940 }
941 
test_rtcp_sdes_callback(NX_RTCP_SDES_INFO * sdes_info)942 static UINT test_rtcp_sdes_callback(NX_RTCP_SDES_INFO *sdes_info)
943 {
944     /*
945         We can add user implementation code here..
946 
947         Note!: since this callback is invoked from the IP thread, the application should not block in this callback.
948 
949         Tip: in this callback, we can obtain and record below information:
950             1) sdes_info -> ssrc: the ssrc of the receiver who sends the sdes packet
951             2) sdes_info -> cname_length: the length of the cname field
952             3) sdes_info -> cname: the cname field
953     */
954 
955     return NX_SUCCESS;
956 }
957