MediaProcessors
live555_rtsp.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Rafael Antoniello
3  *
4  * This file is part of MediaProcessors.
5  *
6  * MediaProcessors is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * MediaProcessors is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with MediaProcessors. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
25 #include <mutex>
26 
27 extern "C" {
28 #include "live555_rtsp.h"
29 
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pthread.h>
34 
35 #include <libcjson/cJSON.h>
36 #include <libmediaprocsutils/uri_parser.h>
37 #include <libmediaprocsutils/log.h>
38 #include <libmediaprocsutils/stat_codes.h>
39 #include <libmediaprocsutils/check_utils.h>
40 #include <libmediaprocsutils/schedule.h>
41 #include <libmediaprocsutils/fair_lock.h>
42 #include <libmediaprocsutils/fifo.h>
43 #include <libmediaprocs/proc_if.h>
44 #include <libmediaprocs/procs.h>
45 #include <libmediaprocs/proc.h>
46 #include "muxers_settings.h"
47 #include "proc_muxer.h"
48 }
49 
50 #include <liveMedia/liveMedia.hh>
51 #include <BasicUsageEnvironment/BasicUsageEnvironment.hh>
52 #ifndef _MULTI_FRAMED_RTP_SINK_HH
53 #include "MultiFramedRTPSink.hh"
54 #endif
55 
56 using namespace std;
57 
58 /* **** Definitions **** */
59 
60 #define SERVER_TOUT 10
61 
62 #define FRAMED_SOURCE_FIFO_SLOTS 16
63 
64 #define SINK_BUFFER_SIZE 200000
65 
66 //#define ENABLE_DEBUG_LOGS
67 #ifdef ENABLE_DEBUG_LOGS
68  #define LOGD_CTX_INIT(CTX) LOG_CTX_INIT(CTX)
69  #define LOGD(FORMAT, ...) LOGV(FORMAT, ##__VA_ARGS__)
70 #else
71  #define LOGD_CTX_INIT(CTX)
72  #define LOGD(...)
73 #endif
74 
78 #define TAG_HAS(NEEDLE) (strstr(tag, NEEDLE)!= NULL)
79 
83 #define TAG_IS(TAG) (strcmp(tag, TAG)== 0)
84 
94  struct muxers_settings_mux_ctx_s muxers_settings_mux_ctx;
96 
100 typedef struct live555_rtsp_mux_ctx_s {
106  struct proc_muxer_mux_ctx_s proc_muxer_mux_ctx;
112  live555_rtsp_mux_settings_ctx;
119  TaskScheduler *taskScheduler;
123  UsageEnvironment *usageEnvironment;
127  RTSPServer *rtspServer;
135  ServerMediaSession *serverMediaSession;
140 
154  unsigned int rtp_timestamp_freq;
156 
160 class SimpleMediaSubsession; // Forward declaration
166  struct proc_ctx_s proc_ctx;
171  live555_rtsp_es_mux_settings_ctx;
186  TaskScheduler *taskScheduler;
191 
201  struct muxers_settings_dmux_ctx_s muxers_settings_dmux_ctx;
203 
207 class SimpleRTSPClient; // Forward declaration
208 typedef struct live555_rtsp_dmux_ctx_s {
213  struct proc_ctx_s proc_ctx;
220  live555_rtsp_dmux_settings_ctx;
227  TaskScheduler *taskScheduler;
231  UsageEnvironment *usageEnvironment;
237 
238 /* **** Prototypes **** */
239 
240 /* **** Multiplexer **** */
241 
242 static proc_ctx_t* live555_rtsp_mux_open(const proc_if_t *proc_if,
243  const char *settings_str, log_ctx_t *log_ctx, va_list arg);
244 static int live555_rtsp_mux_init_given_settings(
245  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx,
246  const muxers_settings_mux_ctx_t *muxers_settings_mux_ctx,
247  log_ctx_t *log_ctx);
248 static void live555_rtsp_mux_close(proc_ctx_t **ref_proc_ctx);
250  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx, log_ctx_t *log_ctx);
251 static int live555_rtsp_mux_process_frame(proc_ctx_t *proc_ctx,
252  fifo_ctx_t *iput_fifo_ctx, fifo_ctx_t *oput_fifo_ctx);
253 static int live555_rtsp_mux_rest_put(proc_ctx_t *proc_ctx, const char *str);
254 static int live555_rtsp_mux_opt(proc_ctx_t *proc_ctx, const char *tag,
255  va_list arg);
256 static int live555_rtsp_mux_rest_get(proc_ctx_t *proc_ctx,
257  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse);
258 static int live555_rtsp_mux_rest_get_es_array(procs_ctx_t *procs_ctx_es_muxers,
259  cJSON **ref_cjson_es_array, log_ctx_t *log_ctx);
260 
262  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx,
263  log_ctx_t *log_ctx);
265  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx,
266  log_ctx_t *log_ctx);
267 static void* taskScheduler_thr(void *t);
268 
269 static proc_ctx_t* live555_rtsp_es_mux_open(const proc_if_t *proc_if,
270  const char *settings_str, log_ctx_t *log_ctx, va_list arg);
271 static void live555_rtsp_es_mux_close(proc_ctx_t **ref_proc_ctx);
272 static int live555_rtsp_es_mux_process_frame(proc_ctx_t *proc_ctx,
273  fifo_ctx_t *iput_fifo_ctx, fifo_ctx_t *oput_fifo_ctx);
274 static int live555_rtsp_es_mux_rest_put(proc_ctx_t *proc_ctx, const char *str);
275 static int live555_rtsp_es_mux_rest_get(proc_ctx_t *proc_ctx,
276  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse);
277 
278 static int live555_rtsp_es_mux_settings_ctx_init(
280  live555_rtsp_es_mux_settings_ctx, log_ctx_t *log_ctx);
281 static void live555_rtsp_es_mux_settings_ctx_deinit(
283  live555_rtsp_es_mux_settings_ctx, log_ctx_t *log_ctx);
284 
288 class SimpleRTPSink2: public MultiFramedRTPSink {
289 public:
290  static SimpleRTPSink2* createNew(UsageEnvironment& env, Groupsock* RTPgs,
291  unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency,
292  char const* sdpMediaTypeString, char const* rtpPayloadFormatName,
293  unsigned numChannels= 1,
294  Boolean allowMultipleFramesPerPacket= True,
295  Boolean doNormalMBitRule= True);
296 
297 protected:
298  SimpleRTPSink2(UsageEnvironment& env, Groupsock* RTPgs,
299  unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency,
300  char const* sdpMediaTypeString, char const* rtpPayloadFormatName,
301  unsigned numChannels, Boolean allowMultipleFramesPerPacket,
302  Boolean doNormalMBitRule);
303  virtual ~SimpleRTPSink2();
304 
305 protected: // redefined virtual functions
306  virtual void doSpecialFrameHandling(unsigned fragmentationOffset,
307  unsigned char* frameStart,
308  unsigned numBytesInFrame,
309  struct timeval framePresentationTime,
310  unsigned numRemainingBytes);
311  virtual Boolean frameCanAppearAfterPacketStart(
312  unsigned char const* frameStart, unsigned numBytesInFrame) const;
313  virtual char const* sdpMediaType() const;
314 
315 private:
316  char const* fSDPMediaTypeString;
317  Boolean fAllowMultipleFramesPerPacket;
318  Boolean fSetMBitOnLastFrames, fSetMBitOnNextPacket;
319 };
320 
324 class SimpleFramedSource: public FramedSource
325 {
326 public:
327  static SimpleFramedSource* createNew(UsageEnvironment& env,
328  log_ctx_t *log_ctx);
333  void deliverFrame();
341  volatile EventTriggerId m_eventTriggerId;
342 
343 protected:
344  SimpleFramedSource(UsageEnvironment&, log_ctx_t*);
346 
347 private:
352  void doGetNextFrame();
356  static void deliverFrame0(void* clientData);
360  log_ctx_t *m_log_ctx;
361 };
362 
366 class SimpleMediaSubsession: public OnDemandServerMediaSubsession
367 {
368 public:
369  static SimpleMediaSubsession *createNew(UsageEnvironment &env,
370  const char *sdp_mimetype, portNumBits initialPortNum= 6970,
371  Boolean multiplexRTCPWithRTP= False);
372 
373  void deliverFrame(proc_frame_ctx_t **);
374 
375 protected:
376  SimpleMediaSubsession(UsageEnvironment &env, const char *sdp_mimetype,
377  portNumBits initialPortNum=6970,
378  Boolean multiplexRTCPWithRTP=False);
379 
380  virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
381  unsigned& estBitrate);
382  virtual void deleteStream(unsigned clientSessionId, void*& streamToken);
383  virtual void closeStreamSource(FramedSource* inputSource);
384  virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
385  unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource);
386 private:
387  std::mutex m_simpleFramedSource_mutex;
388  SimpleFramedSource *volatile m_simpleFramedSource;
389  const char *m_sdp_mimetype;
393  log_ctx_t *m_log_ctx;
394 };
395 
396 /* **** De-multiplexer **** */
397 
398 static proc_ctx_t* live555_rtsp_dmux_open(const proc_if_t *proc_if,
399  const char *settings_str, log_ctx_t *log_ctx, va_list arg);
400 static int live555_rtsp_dmux_init_given_settings(
401  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx,
402  const muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx,
403  log_ctx_t *log_ctx);
404 static void live555_rtsp_dmux_close(proc_ctx_t **ref_proc_ctx);
405 static void live555_rtsp_dmux_deinit_except_settings(
406  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx, log_ctx_t *log_ctx);
407 static int live555_rtsp_dmux_rest_get(proc_ctx_t *proc_ctx,
408  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse);
409 static int live555_rtsp_dmux_process_frame(proc_ctx_t *proc_ctx,
410  fifo_ctx_t* iput_fifo_ctx, fifo_ctx_t* oput_fifo_ctx);
411 static int live555_rtsp_dmux_rest_put(proc_ctx_t *proc_ctx, const char *str);
412 
415  live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx);
418  live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx);
419 
420 static void continueAfterDESCRIBE(RTSPClient *rtspClient, int resultCode,
421  char *resultString);
422 static void continueAfterSETUP(RTSPClient *rtspClient, int resultCode,
423  char *resultString);
424 static void continueAfterPLAY(RTSPClient *rtspClient, int resultCode,
425  char *resultString);
426 static void subsessionAfterPlaying(void * clientData);
427 static void subsessionByeHandler(void *clientData);
428 static void setupNextSubsession(RTSPClient* rtspClient);
429 static void shutdownStream(RTSPClient* rtspClient, int exitCode= 1);
430 
435 class SimpleClientMediaSubsession: public MediaSubsession
436 {
437 public:
438  SimpleClientMediaSubsession(MediaSession& parent);
439 protected:
440  virtual Boolean createSourceObjects(int useSpecialRTPoffset);
441 };
442 
449 class SimpleClientSession: public MediaSession
450 {
451 public:
452  static SimpleClientSession* createNew(UsageEnvironment& env,
453  char const* sdpDescription);
454 protected:
455  SimpleClientSession(UsageEnvironment& env);
456  virtual MediaSubsession* createNewMediaSubsession();
457 };
458 
464 public:
466  virtual ~StreamClientState();
467 
468 public:
469  MediaSubsessionIterator* iter;
470  SimpleClientSession* session;
471  MediaSubsession* subsession;
472  TaskToken streamTimerTask;
473  double duration;
474 };
475 
480 class SimpleRTSPClient: public RTSPClient {
481 public:
482  static SimpleRTSPClient* createNew(UsageEnvironment& env,
483  char const* rtspURL, volatile int *ref_flag_exit,
484  fifo_ctx_t *fifo_ctx, int verbosityLevel= 0,
485  char const* applicationName= NULL,
486  portNumBits tunnelOverHTTPPortNum= 0, log_ctx_t *log_ctx= NULL);
487 
488  StreamClientState streamClientState;
489  volatile int *m_ref_flag_exit;
490  log_ctx_t *m_log_ctx;
491  fifo_ctx_t *m_fifo_ctx;
492 protected:
493  SimpleRTSPClient(UsageEnvironment& env, char const* rtspURL,
494  volatile int *ref_flag_exit, fifo_ctx_t *fifo_ctx,
495  int verbosityLevel, char const* applicationName,
496  portNumBits tunnelOverHTTPPortNum, log_ctx_t *log_ctx= NULL);
497  virtual ~SimpleRTSPClient();
498 };
499 
504 class DummySink: public MediaSink {
505 public:
511  static DummySink* createNew(UsageEnvironment& env,
512  MediaSubsession& subsession, fifo_ctx_t *fifo_ctx,
513  char const* streamId= NULL, log_ctx_t *log_ctx= NULL);
514 
515 private:
516  DummySink(UsageEnvironment& env, MediaSubsession& subsession,
517  fifo_ctx_t *fifo_ctx, char const* streamId, log_ctx_t *log_ctx);
518  virtual ~DummySink();
519 
520  static void afterGettingFrame(void* clientData, unsigned frameSize,
521  unsigned numTruncatedBytes,
522  struct timeval presentationTime,
523  unsigned durationInMicroseconds);
524  void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
525  struct timeval presentationTime, unsigned durationInMicroseconds);
526  /* redefined virtual functions */
527  virtual Boolean continuePlaying();
528 
529 private:
530  u_int8_t* fReceiveBuffer;
531  MediaSubsession& fSubsession;
532  char* fStreamId;
533  log_ctx_t *m_log_ctx;
534  fifo_ctx_t *m_fifo_ctx;
535  proc_frame_ctx_t *m_proc_frame_ctx;
536  std::mutex m_dummySink_io_mutex;
537 };
538 
539 /* **** General **** */
540 
541 void live555_rtsp_reset_on_new_settings(proc_ctx_t *proc_ctx,
542  int flag_is_muxer, log_ctx_t *log_ctx);
543 void live555_rtsp_reset_on_new_settings_es_mux(proc_ctx_t *proc_ctx,
544  log_ctx_t *log_ctx);
545 void live555_rtsp_reset_on_new_settings_es_dmux(proc_ctx_t *proc_ctx,
546  log_ctx_t *log_ctx);
547 
548 /* **** Implementations **** */
549 
550 extern "C" {
552 {
553  "live555_rtsp_mux", "multiplexer", "application/octet-stream",
554  (uint64_t)0, // no generic processor features implemented
557  proc_send_frame_default1,
558  NULL, // no 'send-no-dup'
559  NULL, // no 'recv_frame'
560  NULL, // no specific unblock function extension
565  (void*(*)(const proc_frame_ctx_t*))proc_frame_ctx_dup,
566  (void(*)(void**))proc_frame_ctx_release,
567  (proc_frame_ctx_t*(*)(const void*))proc_frame_ctx_dup
568 };
569 
570 static const proc_if_t proc_if_live555_rtsp_es_mux=
571 {
572  "live555_rtsp_es_mux", "multiplexer", "application/octet-stream",
573  (uint64_t)0, // no generic processor features implemented
574  live555_rtsp_es_mux_open,
576  proc_send_frame_default1,
577  NULL, // no 'send-no-dup'
578  NULL, // no 'recv_frame'
579  NULL, // no specific unblock function extension
580  NULL, //live555_rtsp_es_mux_rest_put // used internally only (not in API)
583  NULL, //live555_rtsp_es_mux_opt
584  (void*(*)(const proc_frame_ctx_t*))proc_frame_ctx_dup,
585  (void(*)(void**))proc_frame_ctx_release,
586  (proc_frame_ctx_t*(*)(const void*))proc_frame_ctx_dup
587 };
588 
590 {
591  "live555_rtsp_dmux", "demultiplexer", "application/octet-stream",
592  (uint64_t)0, // no generic processor features implemented
593  live555_rtsp_dmux_open,
595  NULL, // no 'send_frame'
596  NULL, // no 'send-no-dup'
597  proc_recv_frame_default1,
598  NULL, // no specific unblock function extension
602  NULL, //live555_rtsp_dmux_opt,
603  (void*(*)(const proc_frame_ctx_t*))proc_frame_ctx_dup,
604  (void(*)(void**))proc_frame_ctx_release,
605  (proc_frame_ctx_t*(*)(const void*))proc_frame_ctx_dup
606 };
607 } //extern "C"
608 
614  const char *settings_str, log_ctx_t *log_ctx, va_list arg)
615 {
616  int ret_code, end_code= STAT_ERROR;
617  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL;
618  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx=
619  NULL; // Do not release
620  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx=
621  NULL; // Do not release
622  LOG_CTX_INIT(log_ctx);
623 
624  /* Check arguments */
625  CHECK_DO(proc_if!= NULL, return NULL);
626  CHECK_DO(settings_str!= NULL, return NULL);
627  // Note: 'log_ctx' is allowed to be NULL
628 
629  /* Allocate context structure */
630  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)calloc(1, sizeof(
632  CHECK_DO(live555_rtsp_mux_ctx!= NULL, goto end);
633 
634  /* Get settings structures */
635  live555_rtsp_mux_settings_ctx=
636  &live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx;
637  muxers_settings_mux_ctx=
638  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
639 
640  /* Initialize settings to defaults */
641  ret_code= live555_rtsp_mux_settings_ctx_init(live555_rtsp_mux_settings_ctx,
642  LOG_CTX_GET());
643  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
644 
645  /* Parse and put given settings */
646  ret_code= live555_rtsp_mux_rest_put((proc_ctx_t*)live555_rtsp_mux_ctx,
647  settings_str);
648  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
649 
650  /* **** Initialize the specific Live555 multiplexer resources ****
651  * Now that all the parameters are set, we proceed with Live555 specific's.
652  */
653  ret_code= live555_rtsp_mux_init_given_settings(live555_rtsp_mux_ctx,
654  (const muxers_settings_mux_ctx_t*)muxers_settings_mux_ctx,
655  LOG_CTX_GET());
656  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
657 
658  end_code= STAT_SUCCESS;
659 end:
660  if(end_code!= STAT_SUCCESS)
661  live555_rtsp_mux_close((proc_ctx_t**)&live555_rtsp_mux_ctx);
662  return (proc_ctx_t*)live555_rtsp_mux_ctx;
663 }
664 
665 static int live555_rtsp_mux_init_given_settings(
666  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx,
667  const muxers_settings_mux_ctx_t *muxers_settings_mux_ctx,
668  log_ctx_t *log_ctx)
669 {
670  char *stream_session_name;
671  int ret_code, end_code= STAT_ERROR;
672  int port= 8554;
673  LOG_CTX_INIT(log_ctx);
674 
675  /* Check arguments */
676  CHECK_DO(live555_rtsp_mux_ctx!= NULL, return STAT_ERROR);
677  CHECK_DO(muxers_settings_mux_ctx!= NULL, return STAT_ERROR);
678  // Note: 'log_ctx' is allowed to be NULL
679 
680  /* Initialize generic multiplexing common context structure */
681  ret_code= proc_muxer_mux_ctx_init(
682  (proc_muxer_mux_ctx_t*)live555_rtsp_mux_ctx, LOG_CTX_GET());
683  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
684 
685  /* Open Live555 scheduler */
686  live555_rtsp_mux_ctx->taskScheduler= BasicTaskScheduler::createNew();
687  CHECK_DO(live555_rtsp_mux_ctx->taskScheduler!= NULL, goto end);
688 
689  /* Set up Live555 usage environment.
690  * Unfortunate live555 implementation: we *must* initialize
691  * 'liveMediaPriv' and 'groupsockPriv' to NULL to be able to successfully
692  * delete -reclaim()- this class instance while releasing.
693  */
694  live555_rtsp_mux_ctx->usageEnvironment= BasicUsageEnvironment::createNew(
695  *live555_rtsp_mux_ctx->taskScheduler);
696  CHECK_DO(live555_rtsp_mux_ctx->usageEnvironment!= NULL, goto end);
697  live555_rtsp_mux_ctx->usageEnvironment->liveMediaPriv= NULL;
698  live555_rtsp_mux_ctx->usageEnvironment->groupsockPriv= NULL;
699 
700  /* Create the RTSP server */
701  port= muxers_settings_mux_ctx->rtsp_port;
702  live555_rtsp_mux_ctx->rtspServer= RTSPServer::createNew(
703  *live555_rtsp_mux_ctx->usageEnvironment, port, NULL, SERVER_TOUT);
704  if(live555_rtsp_mux_ctx->rtspServer== NULL) {
705  LOGE("Live555: %s\n",
706  live555_rtsp_mux_ctx->usageEnvironment->getResultMsg());
707  goto end;
708  }
709 
710  /* In run-time we will be able to set up each of the possible streams that
711  * can be served by the RTSP server. Each such stream is implemented using
712  * a 'ServerMediaSession' object, plus one or more 'ServerMediaSubsession'
713  * objects for each audio/video sub-stream.
714  * We initially create the 'ServerMediaSession' object. Sub-sessions will
715  * be created/destroyed dynamically.
716  */
717  stream_session_name= muxers_settings_mux_ctx->rtsp_streaming_session_name;
718  live555_rtsp_mux_ctx->serverMediaSession= ServerMediaSession::createNew(
719  *live555_rtsp_mux_ctx->usageEnvironment,
720  stream_session_name!= NULL? stream_session_name: "session",
721  "n/a", "n/a");
722  CHECK_DO(live555_rtsp_mux_ctx->serverMediaSession!= NULL, goto end);
723  live555_rtsp_mux_ctx->rtspServer->addServerMediaSession(
724  live555_rtsp_mux_ctx->serverMediaSession);
725 
726  /* Register ES-MUXER processor type */
727  ret_code= procs_module_opt("PROCS_REGISTER_TYPE",
728  &proc_if_live555_rtsp_es_mux);
729  CHECK_DO(ret_code== STAT_SUCCESS || ret_code== STAT_ECONFLICT, goto end);
730 
731  /* At last, launch scheduler thread */
732  ret_code= pthread_create(&live555_rtsp_mux_ctx->taskScheduler_thread, NULL,
733  taskScheduler_thr, live555_rtsp_mux_ctx);
734  CHECK_DO(ret_code== 0, goto end);
735 
736  end_code= STAT_SUCCESS;
737 end:
738  if(end_code!= STAT_SUCCESS)
739  live555_rtsp_mux_deinit_except_settings(live555_rtsp_mux_ctx,
740  LOG_CTX_GET());
741  return end_code;
742 }
743 
748 static void live555_rtsp_mux_close(proc_ctx_t **ref_proc_ctx)
749 {
750  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL;
751  LOG_CTX_INIT(NULL);
752  LOGD(">>%s\n", __FUNCTION__); //comment-me
753 
754  if(ref_proc_ctx== NULL)
755  return;
756 
757  if((live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)*ref_proc_ctx)!= NULL) {
758  LOG_CTX_SET(((proc_ctx_t*)live555_rtsp_mux_ctx)->log_ctx);
759 
760  live555_rtsp_mux_deinit_except_settings(live555_rtsp_mux_ctx,
761  LOG_CTX_GET());
762 
763  /* Release settings */
765  &live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx,
766  LOG_CTX_GET());
767 
768  /* Release context structure */
769  free(live555_rtsp_mux_ctx);
770  *ref_proc_ctx= NULL;
771  }
772  LOGD("<<%s\n", __FUNCTION__); //comment-me
773 }
774 
780  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx, log_ctx_t *log_ctx)
781 {
782  void *thread_end_code= NULL;
783  proc_muxer_mux_ctx_t *proc_muxer_mux_ctx= NULL; // Do not release
784  LOG_CTX_INIT(log_ctx);
785  LOGD(">>%s\n", __FUNCTION__); //comment-me
786 
787  /* Check arguments */
788  if(live555_rtsp_mux_ctx== NULL)
789  return;
790 
791  /* Get Multiplexer processing common context structure */
792  proc_muxer_mux_ctx= (proc_muxer_mux_ctx_t*)live555_rtsp_mux_ctx;
793 
794  /* Join Join ES-threads first
795  * - set flag to notify we are exiting processing;
796  * - unblock and close all running ES-processors;
797  * - join thread.
798  */
799  ((proc_ctx_t*)live555_rtsp_mux_ctx)->flag_exit= 1;
800  if(proc_muxer_mux_ctx!= NULL &&
801  proc_muxer_mux_ctx->procs_ctx_es_muxers!= NULL)
802  procs_close(&proc_muxer_mux_ctx->procs_ctx_es_muxers);
803  LOGD("Waiting thread to join... "); // comment-me
804  pthread_join(live555_rtsp_mux_ctx->taskScheduler_thread,
805  &thread_end_code);
806  if(thread_end_code!= NULL) {
807  ASSERT(*((int*)thread_end_code)== STAT_SUCCESS);
808  free(thread_end_code);
809  thread_end_code= NULL;
810  }
811  LOGD("joined O.K.\n"); // comment-me
812 
813  // '&live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx' preserved
814 
815  /* **** Release the specific Live555 multiplexer resources **** */
816 
817  /* Note about 'live555_rtsp_mux_ctx::serverMediaSession': we do not
818  * need to delete ServerMediaSession object before deleting a
819  * RTSPServer, because the RTSPServer destructor will automatically
820  * delete any ServerMediaSession (as ClientConnection and
821  * ClientSession) objects that it manages. Instead, we can just call
822  * 'Medium::close()' on your RTSPServer object.
823  */
824  if(live555_rtsp_mux_ctx->rtspServer!= NULL) {
825  Medium::close(live555_rtsp_mux_ctx->rtspServer);
826  live555_rtsp_mux_ctx->rtspServer= NULL;
827  }
828 
829  if(live555_rtsp_mux_ctx->usageEnvironment!= NULL) {
830  Boolean ret_boolean= live555_rtsp_mux_ctx->usageEnvironment->reclaim();
831  ASSERT(ret_boolean== True);
832  if(ret_boolean== True)
833  live555_rtsp_mux_ctx->usageEnvironment= NULL;
834  }
835 
836  if(live555_rtsp_mux_ctx->taskScheduler!= NULL) {
837  delete live555_rtsp_mux_ctx->taskScheduler;
838  live555_rtsp_mux_ctx->taskScheduler= NULL;
839  }
840 
841  /* De-initialize generic multiplexing common context structure.
842  * Implementation note: Do this after releasing 'rtspServer', as
843  * processors are referenced inside 'rtspServer' media sub-sessions
844  * related resources.
845  */
846  proc_muxer_mux_ctx_deinit(proc_muxer_mux_ctx, LOG_CTX_GET());
847 
848  // Reserved for future use: release other new variables here...
849 
850  LOGD("<<%s\n", __FUNCTION__); //comment-me
851 }
852 
858  fifo_ctx_t* iput_fifo_ctx, fifo_ctx_t* oput_fifo_ctx)
859 {
860  int ret_code, end_code= STAT_ERROR;
861  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL; // Do not release
862  proc_muxer_mux_ctx_t *proc_muxer_mux_ctx= NULL; // DO not release
863  procs_ctx_t *procs_ctx_es_muxers= NULL; // Do not release
864  proc_frame_ctx_t *proc_frame_ctx_iput= NULL;
865  size_t fifo_elem_size= 0;
866  LOG_CTX_INIT(NULL);
867 
868  /* Check arguments */
869  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
870  CHECK_DO(iput_fifo_ctx!= NULL, return STAT_ERROR);
871  CHECK_DO(oput_fifo_ctx!= NULL, return STAT_ERROR);
872 
873  LOG_CTX_SET(proc_ctx->log_ctx);
874 
875  /* Get multiplexer context */
876  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)proc_ctx;
877 
878  /* Get multiplexer processing common context structure */
879  proc_muxer_mux_ctx= (proc_muxer_mux_ctx_t*)live555_rtsp_mux_ctx;
880 
881  /* Get elementary streams MUXERS hanlder (PROCS module) */
882  procs_ctx_es_muxers= proc_muxer_mux_ctx->procs_ctx_es_muxers;
883  CHECK_DO(procs_ctx_es_muxers!= NULL, goto end);
884 
885  /* Get input packet from FIFO buffer */
886  ret_code= fifo_get(iput_fifo_ctx, (void**)&proc_frame_ctx_iput,
887  &fifo_elem_size);
888  CHECK_DO(ret_code== STAT_SUCCESS || ret_code== STAT_EAGAIN, goto end);
889  if(ret_code== STAT_EAGAIN) {
890  /* This means FIFO was unblocked, just go out with EOF status */
891  end_code= STAT_EOF;
892  goto end;
893  }
894 
895  /* Multiplex frame */
896  ret_code= procs_send_frame(procs_ctx_es_muxers, proc_frame_ctx_iput->es_id,
897  proc_frame_ctx_iput);
898  CHECK_DO(ret_code== STAT_SUCCESS || ret_code== STAT_EAGAIN, goto end);
899 
900  end_code= STAT_SUCCESS;
901 end:
902  if(proc_frame_ctx_iput!= NULL)
903  proc_frame_ctx_release(&proc_frame_ctx_iput);
904  return end_code;
905 }
906 
911 static int live555_rtsp_mux_opt(proc_ctx_t *proc_ctx, const char *tag,
912  va_list arg)
913 {
914 #define PROC_ID_STR_FMT "{\"elementary_stream_id\":%d}"
915  int ret_code, end_code= STAT_ERROR;
916  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL;
917  proc_muxer_mux_ctx_t *proc_muxer_mux_ctx= NULL;
918  procs_ctx_t *procs_ctx_es_muxers= NULL;
919  char *rest_str= NULL;
920  char ref_id_str[strlen(PROC_ID_STR_FMT)+ 64];
921  LOG_CTX_INIT(NULL);
922 
923  /* Check arguments */
924  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
925  CHECK_DO(tag!= NULL, return STAT_ERROR);
926 
927  /* Check that module instance critical section is locked */
928  ret_code= pthread_mutex_trylock(&proc_ctx->api_mutex);
929  CHECK_DO(ret_code== EBUSY, return STAT_ERROR);
930 
931  LOG_CTX_SET(proc_ctx->log_ctx);
932 
933  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)proc_ctx;
934  proc_muxer_mux_ctx= &live555_rtsp_mux_ctx->proc_muxer_mux_ctx;
935  procs_ctx_es_muxers= proc_muxer_mux_ctx->procs_ctx_es_muxers;
936 
937  if(TAG_IS("PROCS_ID_ES_MUX_REGISTER")) {
938  char *p;
939  int elementary_stream_id= -1;
940  const char *settings_str= va_arg(arg, const char*);
941  char **ref_rest_str= va_arg(arg, char**);
942  *ref_rest_str= NULL; // Value to return in case of error
943  end_code= procs_opt(procs_ctx_es_muxers, "PROCS_POST",
944  "live555_rtsp_es_mux", settings_str, &rest_str,
945  live555_rtsp_mux_ctx->usageEnvironment,
946  live555_rtsp_mux_ctx->serverMediaSession);
947  CHECK_DO(end_code== STAT_SUCCESS && rest_str!= NULL, goto end);
948 
949  /* Get processor identifier */
950  p= strstr(rest_str, "\"proc_id\":");
951  CHECK_DO(p!= NULL, goto end);
952  p+= strlen("\"proc_id\":");
953  elementary_stream_id= atoi(p);
954  CHECK_DO(elementary_stream_id>= 0, goto end);
955 
956  /* Prepare JSON string to be returned */
957  snprintf(ref_id_str, sizeof(ref_id_str), PROC_ID_STR_FMT,
958  elementary_stream_id);
959  *ref_rest_str= strdup(ref_id_str);
960  } else {
961  LOGE("Unknown option\n");
962  end_code= STAT_ENOTFOUND;
963  }
964 
965 end:
966  if(rest_str!= NULL)
967  free(rest_str);
968  return end_code;
969 #undef PROC_ID_STR_FMT
970 }
971 
976 static int live555_rtsp_mux_rest_put(proc_ctx_t *proc_ctx, const char *str)
977 {
978  int ret_code;
979  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL;
981  live555_rtsp_mux_settings_ctx= NULL;
982  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx= NULL;
983  LOG_CTX_INIT(NULL);
984 
985  /* Check arguments */
986  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
987  CHECK_DO(str!= NULL, return STAT_ERROR);
988 
989  LOG_CTX_SET(proc_ctx->log_ctx);
990 
991  /* Get multiplexer settings contexts */
992  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)proc_ctx;
993  live555_rtsp_mux_settings_ctx=
994  &live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx;
995  muxers_settings_mux_ctx=
996  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
997 
998  /* PUT generic multiplexer settings */
999  ret_code= muxers_settings_mux_ctx_restful_put(muxers_settings_mux_ctx, str,
1000  LOG_CTX_GET());
1001  if(ret_code!= STAT_SUCCESS)
1002  return ret_code;
1003 
1004 
1005  /* PUT specific multiplexer settings */
1006  // Reserved for future use
1007 
1008  /* Finally that we have new settings parsed, reset processor */
1009  live555_rtsp_reset_on_new_settings(proc_ctx, 1, LOG_CTX_GET());
1010 
1011  return STAT_SUCCESS;
1012 }
1013 
1019  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
1020 {
1021  int ret_code, end_code= STAT_ERROR;
1022  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL;
1023  procs_ctx_t *procs_ctx_es_muxers= NULL; // Do not release
1025  live555_rtsp_mux_settings_ctx= NULL;
1026  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx= NULL;
1027  cJSON *cjson_rest= NULL, *cjson_settings= NULL, *cjson_es_array= NULL;
1028  LOG_CTX_INIT(NULL);
1029 
1030  /* Check arguments */
1031  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
1032  CHECK_DO(rest_fmt< PROC_IF_REST_FMT_ENUM_MAX, return STAT_ERROR);
1033  CHECK_DO(ref_reponse!= NULL, return STAT_ERROR);
1034 
1035  LOG_CTX_SET(proc_ctx->log_ctx);
1036 
1037  *ref_reponse= NULL;
1038 
1039  /* Create cJSON tree root object */
1040  cjson_rest= cJSON_CreateObject();
1041  CHECK_DO(cjson_rest!= NULL, goto end);
1042 
1043  /* JSON string to be returned:
1044  * {
1045  * "settings":
1046  * {
1047  * ...
1048  * },
1049  * elementary_streams:
1050  * [
1051  * {...},
1052  * ...
1053  * ]
1054  * ... // reserved for future use
1055  * }
1056  */
1057 
1058  /* Get multiplexer settings contexts */
1059  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)proc_ctx;
1060  live555_rtsp_mux_settings_ctx=
1061  &live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx;
1062  muxers_settings_mux_ctx=
1063  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
1064 
1065  /* GET generic multiplexer settings */
1066  ret_code= muxers_settings_mux_ctx_restful_get(muxers_settings_mux_ctx,
1067  &cjson_settings, LOG_CTX_GET());
1068  CHECK_DO(ret_code== STAT_SUCCESS && cjson_settings!= NULL, goto end);
1069 
1070  /* GET specific multiplexer settings */
1071  // Reserved for future use: attach to 'cjson_settings' (should be != NULL)
1072 
1073  /* Attach settings object to REST response */
1074  cJSON_AddItemToObject(cjson_rest, "settings", cjson_settings);
1075  cjson_settings= NULL; // Attached; avoid double referencing
1076 
1077  /* **** Attach data to REST response **** */
1078 
1079  /* Get ES-processors array REST and attach */
1080  procs_ctx_es_muxers= ((proc_muxer_mux_ctx_t*)
1081  live555_rtsp_mux_ctx)->procs_ctx_es_muxers;
1082  CHECK_DO(procs_ctx_es_muxers!= NULL, goto end);
1083  ret_code= live555_rtsp_mux_rest_get_es_array(procs_ctx_es_muxers,
1084  &cjson_es_array, LOG_CTX_GET());
1085  CHECK_DO(ret_code== STAT_SUCCESS && cjson_es_array!= NULL, goto end);
1086  cJSON_AddItemToObject(cjson_rest, "elementary_streams", cjson_es_array);
1087  cjson_es_array= NULL; // Attached; avoid double referencing
1088 
1089  // Reserved for future use
1090  /* Example:
1091  * cjson_aux= cJSON_CreateNumber((double)live555_rtsp_mux_ctx->var1);
1092  * CHECK_DO(cjson_aux!= NULL, goto end);
1093  * cJSON_AddItemToObject(cjson_rest, "var1_name", cjson_aux);
1094  */
1095 
1096  /* Format response to be returned */
1097  switch(rest_fmt) {
1098  case PROC_IF_REST_FMT_CHAR:
1099  /* Print cJSON structure data to char string */
1100  *ref_reponse= (void*)CJSON_PRINT(cjson_rest);
1101  CHECK_DO(*ref_reponse!= NULL && strlen((char*)*ref_reponse)> 0,
1102  goto end);
1103  break;
1105  *ref_reponse= (void*)cjson_rest;
1106  cjson_rest= NULL; // Avoid double referencing
1107  break;
1108  default:
1109  LOGE("Unknown format requested for processor REST\n");
1110  goto end;
1111  }
1112 
1113  end_code= STAT_SUCCESS;
1114 end:
1115  if(cjson_rest!= NULL)
1116  cJSON_Delete(cjson_rest);
1117  if(cjson_settings!= NULL)
1118  cJSON_Delete(cjson_settings);
1119  if(cjson_es_array!= NULL)
1120  cJSON_Delete(cjson_es_array);
1121  return end_code;
1122 }
1123 
1124 static int live555_rtsp_mux_rest_get_es_array(procs_ctx_t *procs_ctx_es_muxers,
1125  cJSON **ref_cjson_es_array, log_ctx_t *log_ctx)
1126 {
1127  int i, ret_code, procs_num= 0, end_code= STAT_ERROR;
1128  cJSON *cjson_es_array= NULL, *cjson_procs_rest= NULL,
1129  *cjson_procs_es_rest= NULL, *cjson_procs_es_rest_settings= NULL;
1130  cJSON *cjson_procs= NULL, *cjson_aux= NULL; // Do not release
1131  char *rest_str_aux= NULL, *es_rest_str_aux= NULL;
1132  LOG_CTX_INIT(log_ctx);
1133 
1134  /* Check arguments */
1135  CHECK_DO(procs_ctx_es_muxers!= NULL, return STAT_ERROR);
1136  CHECK_DO(ref_cjson_es_array!= NULL, return STAT_ERROR);
1137 
1138  *ref_cjson_es_array= NULL;
1139 
1140  /* Create ES-processors array REST and attach*/
1141  cjson_es_array= cJSON_CreateArray();
1142  CHECK_DO(cjson_es_array!= NULL, goto end);
1143 
1144  /* JSON string to be returned:
1145  * [
1146  * {...}, // ES-object JSON
1147  * ...
1148  * ]
1149  */
1150 
1151  ret_code= procs_opt(procs_ctx_es_muxers, "PROCS_GET", &rest_str_aux, NULL);
1152  CHECK_DO(ret_code== STAT_SUCCESS && rest_str_aux!= NULL, goto end);
1153 
1154  /* Parse to cJSON structure */
1155  cjson_procs_rest= cJSON_Parse(rest_str_aux);
1156  CHECK_DO(cjson_procs_rest!= NULL, goto end);
1157 
1158  /* Get ES-processors array */
1159  cjson_procs= cJSON_GetObjectItem(cjson_procs_rest, "procs");
1160  CHECK_DO(cjson_procs!= NULL, goto end);
1161  procs_num= cJSON_GetArraySize(cjson_procs);
1162  for(i= 0; i< procs_num; i++) {
1163  int elem_stream_id;
1164  cJSON *cjson_proc= cJSON_GetArrayItem(cjson_procs, i);
1165  CHECK_DO(cjson_proc!= NULL, continue);
1166 
1167  cjson_aux= cJSON_GetObjectItem(cjson_proc, "proc_id");
1168  CHECK_DO(cjson_aux!= NULL, continue);
1169  elem_stream_id= (int)cjson_aux->valuedouble;
1170 
1171  /* Get ES-processor REST */
1172  if(es_rest_str_aux!= NULL) {
1173  free(es_rest_str_aux);
1174  es_rest_str_aux= NULL;
1175  }
1176  ret_code= procs_opt(procs_ctx_es_muxers, "PROCS_ID_GET",
1177  elem_stream_id, &es_rest_str_aux);
1178  CHECK_DO(ret_code== STAT_SUCCESS && es_rest_str_aux!= NULL, continue);
1179 
1180  /* Parse ES-processor response to cJSON structure */
1181  if(cjson_procs_es_rest!= NULL) {
1182  cJSON_Delete(cjson_procs_es_rest);
1183  cjson_procs_es_rest= NULL;
1184  }
1185  cjson_procs_es_rest= cJSON_Parse(es_rest_str_aux);
1186  CHECK_DO(cjson_procs_es_rest!= NULL, continue);
1187 
1188  /* Attach elementary stream Id. (== xxx) */
1189  cjson_aux= cJSON_CreateNumber((double)elem_stream_id);
1190  CHECK_DO(cjson_aux!= NULL, continue);
1191  cJSON_AddItemToObject(cjson_procs_es_rest, "elementary_stream_id",
1192  cjson_aux);
1193 
1194  /* Detach settings from elementary stream REST */
1195  if(cjson_procs_es_rest_settings!= NULL) {
1196  cJSON_Delete(cjson_procs_es_rest_settings);
1197  cjson_procs_es_rest_settings= NULL;
1198  }
1199  cjson_procs_es_rest_settings= cJSON_DetachItemFromObject(
1200  cjson_procs_es_rest, "settings");
1201 
1202  /* Attach elementary stream data to array */
1203  cJSON_AddItemToArray(cjson_es_array, cjson_procs_es_rest);
1204  cjson_procs_es_rest= NULL; // Attached; avoid double referencing
1205  }
1206 
1207  *ref_cjson_es_array= cjson_es_array;
1208  cjson_es_array= NULL; // Avoid double referencing
1209  end_code= STAT_SUCCESS;
1210 end:
1211  if(cjson_es_array!= NULL)
1212  cJSON_Delete(cjson_es_array);
1213  if(rest_str_aux!= NULL)
1214  free(rest_str_aux);
1215  if(cjson_procs_rest!= NULL)
1216  cJSON_Delete(cjson_procs_rest);
1217  if(es_rest_str_aux!= NULL)
1218  free(es_rest_str_aux);
1219  if(cjson_procs_es_rest!= NULL)
1220  cJSON_Delete(cjson_procs_es_rest);
1221  if(cjson_procs_es_rest_settings!= NULL)
1222  cJSON_Delete(cjson_procs_es_rest_settings);
1223  return end_code;
1224 }
1225 
1234  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx,
1235  log_ctx_t *log_ctx)
1236 {
1237  int ret_code;
1238  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx= NULL;
1239  LOG_CTX_INIT(log_ctx);
1240 
1241  /* Check arguments */
1242  CHECK_DO(live555_rtsp_mux_settings_ctx!= NULL, return STAT_ERROR);
1243 
1244  muxers_settings_mux_ctx=
1245  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
1246 
1247  /* Initialize generic multiplexer settings */
1248  ret_code= muxers_settings_mux_ctx_init(muxers_settings_mux_ctx);
1249  if(ret_code!= STAT_SUCCESS)
1250  return ret_code;
1251 
1252  /* Initialize specific multiplexer settings */
1253  // Reserved for future use
1254 
1255  return STAT_SUCCESS;
1256 }
1257 
1265  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx,
1266  log_ctx_t *log_ctx)
1267 {
1268  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx= NULL;
1269  LOG_CTX_INIT(log_ctx);
1270 
1271  /* Check arguments */
1272  CHECK_DO(live555_rtsp_mux_settings_ctx!= NULL, return);
1273 
1274  muxers_settings_mux_ctx=
1275  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
1276 
1277  /* Release (heap-allocated) generic multiplexer settings */
1278  muxers_settings_mux_ctx_deinit(muxers_settings_mux_ctx);
1279 
1280  /* Release specific multiplexer settings */
1281  // Reserved for future use
1282 }
1283 
1284 static void* taskScheduler_thr(void *t)
1285 {
1286  char volatile *watchVariable;
1287  live555_rtsp_mux_ctx_t* live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)t;
1288  int *ref_end_code= NULL;
1289  UsageEnvironment *usageEnvironment= NULL;
1290  LOG_CTX_INIT(NULL);
1291 
1292  /* Allocate return context; initialize to a default 'ERROR' value */
1293  ref_end_code= (int*)malloc(sizeof(int));
1294  CHECK_DO(ref_end_code!= NULL, return NULL);
1295  *ref_end_code= STAT_ERROR;
1296 
1297  /* Check arguments */
1298  CHECK_DO(live555_rtsp_mux_ctx!= NULL, return (void*)ref_end_code);
1299 
1300  LOG_CTX_SET(((proc_ctx_t*)live555_rtsp_mux_ctx)->log_ctx);
1301 
1302  /* Get Live555's usage environment */
1303  usageEnvironment= live555_rtsp_mux_ctx->usageEnvironment;
1304  CHECK_DO(live555_rtsp_mux_ctx!= NULL, return (void*)ref_end_code);
1305 
1306  /* Run the scheduler until "exit flag" is set */
1307  watchVariable= (char volatile*)
1308  &((proc_ctx_t*)live555_rtsp_mux_ctx)->flag_exit;
1309  usageEnvironment->taskScheduler().doEventLoop(watchVariable);
1310 
1311  *ref_end_code= STAT_SUCCESS;
1312  return (void*)ref_end_code;
1313 }
1314 
1315 /* **** Elementary stream instance related implementation **** */
1316 
1317 static proc_ctx_t* live555_rtsp_es_mux_open(const proc_if_t *proc_if,
1318  const char *settings_str, log_ctx_t *log_ctx, va_list arg)
1319 {
1320  int ret_code, end_code= STAT_ERROR;
1321  live555_rtsp_es_mux_ctx_t *live555_rtsp_es_mux_ctx= NULL;
1323  live555_rtsp_es_mux_settings_ctx= NULL; // Do not release
1324  UsageEnvironment *usageEnvironment= NULL; // Do not release
1325  ServerMediaSession *serverMediaSession= NULL; // Do not release
1326  LOG_CTX_INIT(log_ctx);
1327 
1328  /* Check arguments */
1329  CHECK_DO(proc_if!= NULL, return NULL);
1330  CHECK_DO(settings_str!= NULL, return NULL);
1331  // Note: 'log_ctx' is allowed to be NULL
1332 
1333  /* Allocate context structure */
1334  live555_rtsp_es_mux_ctx= (live555_rtsp_es_mux_ctx_t*)calloc(1, sizeof(
1336  CHECK_DO(live555_rtsp_es_mux_ctx!= NULL, goto end);
1337 
1338  /* Get settings structure */
1339  live555_rtsp_es_mux_settings_ctx=
1340  &live555_rtsp_es_mux_ctx->live555_rtsp_es_mux_settings_ctx;
1341 
1342  /* Initialize settings to defaults */
1343  ret_code= live555_rtsp_es_mux_settings_ctx_init(
1344  live555_rtsp_es_mux_settings_ctx, LOG_CTX_GET());
1345  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
1346 
1347  /* Parse and put given settings */
1349  live555_rtsp_es_mux_ctx, settings_str);
1350  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
1351 
1352  /* **** Initialize specific context structure members **** */
1353 
1354  live555_rtsp_es_mux_ctx->log_ctx= LOG_CTX_GET();
1355 
1356  usageEnvironment= va_arg(arg, UsageEnvironment*);
1357  CHECK_DO(usageEnvironment!= NULL, goto end);
1358 
1359  serverMediaSession= va_arg(arg, ServerMediaSession*);
1360  CHECK_DO(serverMediaSession!= NULL, goto end);
1361 
1362  live555_rtsp_es_mux_ctx->taskScheduler=
1363  &(usageEnvironment->taskScheduler());
1364  CHECK_DO(live555_rtsp_es_mux_ctx->taskScheduler!= NULL, goto end);
1365 
1366  live555_rtsp_es_mux_ctx->simpleMediaSubsession=
1367  SimpleMediaSubsession::createNew(*usageEnvironment,
1368  live555_rtsp_es_mux_settings_ctx->sdp_mimetype);
1369  CHECK_DO(live555_rtsp_es_mux_ctx->simpleMediaSubsession!= NULL, goto end);
1370 
1371  ret_code= serverMediaSession->addSubsession(
1372  live555_rtsp_es_mux_ctx->simpleMediaSubsession);
1373  CHECK_DO(ret_code== True, goto end);
1374 
1375  end_code= STAT_SUCCESS;
1376  end:
1377  if(end_code!= STAT_SUCCESS)
1378  live555_rtsp_es_mux_close((proc_ctx_t**)&live555_rtsp_es_mux_ctx);
1379  return (proc_ctx_t*)live555_rtsp_es_mux_ctx;
1380 }
1381 
1386 static void live555_rtsp_es_mux_close(proc_ctx_t **ref_proc_ctx)
1387 {
1388  live555_rtsp_es_mux_ctx_t *live555_rtsp_es_mux_ctx= NULL;
1389  LOG_CTX_INIT(NULL);
1390  LOGD(">>%s\n", __FUNCTION__); //comment-me
1391 
1392  if(ref_proc_ctx== NULL)
1393  return;
1394 
1395  if((live555_rtsp_es_mux_ctx= (live555_rtsp_es_mux_ctx_t*)*ref_proc_ctx)!=
1396  NULL) {
1397  LOG_CTX_SET(((proc_ctx_t*)live555_rtsp_es_mux_ctx)->log_ctx);
1398 
1399  /* Release settings */
1400  live555_rtsp_es_mux_settings_ctx_deinit(
1401  &live555_rtsp_es_mux_ctx->live555_rtsp_es_mux_settings_ctx,
1402  LOG_CTX_GET());
1403 
1404  // Reserved for future use: release other new variables here...
1405 
1406  /* Release context structure */
1407  free(live555_rtsp_es_mux_ctx);
1408  *ref_proc_ctx= NULL;
1409  }
1410  LOGD("<<%s\n", __FUNCTION__); //comment-me
1411 }
1412 
1418  fifo_ctx_t* iput_fifo_ctx, fifo_ctx_t* oput_fifo_ctx)
1419 {
1420  int ret_code, end_code= STAT_ERROR;
1421  live555_rtsp_es_mux_ctx_t *live555_rtsp_es_mux_ctx= NULL; //Do not release
1422  proc_frame_ctx_t *proc_frame_ctx= NULL;
1423  size_t fifo_elem_size= 0;
1424  SimpleMediaSubsession *simpleMediaSubsession= NULL; //Do not release
1425  LOG_CTX_INIT(NULL);
1426 
1427  /* Check arguments */
1428  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
1429  CHECK_DO(iput_fifo_ctx!= NULL, return STAT_ERROR);
1430  CHECK_DO(oput_fifo_ctx!= NULL, return STAT_ERROR);
1431 
1432  LOG_CTX_SET(proc_ctx->log_ctx);
1433 
1434  /* Get multiplexer context */
1435  live555_rtsp_es_mux_ctx= (live555_rtsp_es_mux_ctx_t*)proc_ctx;
1436 
1437  /* Get input packet from FIFO buffer */
1438  ret_code= fifo_get(iput_fifo_ctx, (void**)&proc_frame_ctx, &fifo_elem_size);
1439  CHECK_DO(ret_code== STAT_SUCCESS || ret_code== STAT_EAGAIN, goto end);
1440  if(ret_code== STAT_EAGAIN) {
1441  /* This means FIFO was unblocked, just go out with EOF status */
1442  end_code= STAT_EOF;
1443  goto end;
1444  }
1445 
1446  /* Deliver frame to Live555's "framed source" */
1447  simpleMediaSubsession= (SimpleMediaSubsession*)
1448  live555_rtsp_es_mux_ctx->simpleMediaSubsession;
1449  CHECK_DO(simpleMediaSubsession!= NULL, goto end);
1450  simpleMediaSubsession->deliverFrame(&proc_frame_ctx);
1451 
1452  end_code= STAT_SUCCESS;
1453 end:
1454  /* If 'deliverFrame()' method did not consume the frame (frame pointer
1455  * was not set to NULL), we must release frame and schedule to avoid
1456  * CPU-consuming closed loops.
1457  */
1458  if(proc_frame_ctx!= NULL) {
1459  proc_frame_ctx_release(&proc_frame_ctx);
1460  schedule();
1461  }
1462  return end_code;
1463 }
1464 
1469 static int live555_rtsp_es_mux_rest_put(proc_ctx_t *proc_ctx, const char *str)
1470 {
1471  int flag_is_query, end_code= STAT_ERROR;
1472  live555_rtsp_es_mux_ctx_t *live555_rtsp_es_mux_ctx= NULL;
1474  live555_rtsp_es_mux_settings_ctx= NULL;
1475  char *sdp_mimetype_str= NULL, *rtp_timestamp_freq_str= NULL,
1476  *bit_rate_estimated_str= NULL;
1477  cJSON *cjson_rest= NULL, *cjson_aux= NULL;
1478  LOG_CTX_INIT(NULL);
1479 
1480  /* Check arguments */
1481  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
1482  CHECK_DO(str!= NULL, return STAT_ERROR);
1483 
1484  LOG_CTX_SET(proc_ctx->log_ctx);
1485 
1486  /* Get FFmpeg video encoder settings contexts */
1487  live555_rtsp_es_mux_ctx= (live555_rtsp_es_mux_ctx_t*)proc_ctx;
1488  live555_rtsp_es_mux_settings_ctx=
1489  &live555_rtsp_es_mux_ctx->live555_rtsp_es_mux_settings_ctx;
1490 
1491  /* **** PUT specific m2v video encoder settings **** */
1492 
1493  /* Guess string representation format (JSON-REST or Query) */
1494  //LOGD("'%s'\n", str); //comment-me
1495  flag_is_query= (str[0]=='{' && str[strlen(str)-1]=='}')? 0: 1;
1496 
1497  /* **** Parse RESTful string to get settings parameters **** */
1498 
1499  if(flag_is_query== 1) {
1500 
1501  /* 'sdp_mimetype' */
1502  sdp_mimetype_str= uri_parser_query_str_get_value("sdp_mimetype", str);
1503  if(sdp_mimetype_str!= NULL) {
1504  char *sdp_mimetype;
1505  CHECK_DO(strlen(sdp_mimetype_str)> 0,
1506  end_code= STAT_EINVAL; goto end);
1507 
1508  /* Allocate new session name */
1509  sdp_mimetype= strdup(sdp_mimetype_str);
1510  CHECK_DO(sdp_mimetype!= NULL, goto end);
1511 
1512  /* Release old session name and set new one */
1513  if(live555_rtsp_es_mux_settings_ctx->sdp_mimetype!= NULL)
1514  free(live555_rtsp_es_mux_settings_ctx->sdp_mimetype);
1515  live555_rtsp_es_mux_settings_ctx->sdp_mimetype= sdp_mimetype;
1516  }
1517 
1518  /* 'rtp_timestamp_freq' */
1519  rtp_timestamp_freq_str= uri_parser_query_str_get_value(
1520  "rtp_timestamp_freq", str);
1521  if(rtp_timestamp_freq_str!= NULL)
1522  live555_rtsp_es_mux_settings_ctx->rtp_timestamp_freq=
1523  atoll(rtp_timestamp_freq_str);
1524  } else {
1525 
1526  /* In the case string format is JSON-REST, parse to cJSON structure */
1527  cjson_rest= cJSON_Parse(str);
1528  CHECK_DO(cjson_rest!= NULL, goto end);
1529 
1530  /* 'sdp_mimetype' */
1531  cjson_aux= cJSON_GetObjectItem(cjson_rest, "sdp_mimetype");
1532  if(cjson_aux!= NULL) {
1533  char *sdp_mimetype;
1534  CHECK_DO(strlen(cjson_aux->valuestring)> 0,
1535  end_code= STAT_EINVAL; goto end);
1536 
1537  /* Allocate new session name */
1538  sdp_mimetype= strdup(cjson_aux->valuestring);
1539  CHECK_DO(sdp_mimetype!= NULL, goto end);
1540 
1541  /* Release old session name and set new one */
1542  if(live555_rtsp_es_mux_settings_ctx->sdp_mimetype!= NULL)
1543  free(live555_rtsp_es_mux_settings_ctx->sdp_mimetype);
1544  live555_rtsp_es_mux_settings_ctx->sdp_mimetype= sdp_mimetype;
1545  }
1546 
1547  /* 'rtp_timestamp_freq' */
1548  cjson_aux= cJSON_GetObjectItem(cjson_rest, "rtp_timestamp_freq");
1549  if(cjson_aux!= NULL)
1550  live555_rtsp_es_mux_settings_ctx->rtp_timestamp_freq=
1551  cjson_aux->valuedouble;
1552  }
1553 
1554  /* Finally that we have new settings parsed, reset MUXER */
1555  // Reserved for future use
1556 
1557  end_code= STAT_SUCCESS;
1558 end:
1559  if(sdp_mimetype_str!= NULL)
1560  free(sdp_mimetype_str);
1561  if(rtp_timestamp_freq_str!= NULL)
1562  free(rtp_timestamp_freq_str);
1563  if(bit_rate_estimated_str!= NULL)
1564  free(bit_rate_estimated_str);
1565  if(cjson_rest!= NULL)
1566  cJSON_Delete(cjson_rest);
1567  return end_code;
1568 }
1569 
1575  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
1576 {
1577  int end_code= STAT_ERROR;
1578  live555_rtsp_es_mux_ctx_t *live555_rtsp_es_mux_ctx= NULL;
1580  live555_rtsp_es_mux_settings_ctx= NULL;
1581  cJSON *cjson_rest= NULL/*, *cjson_settings= NULL // Not used*/;
1582  cJSON *cjson_aux= NULL; // Do not release
1583  LOG_CTX_INIT(NULL);
1584 
1585  /* Check arguments */
1586  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
1587  CHECK_DO(rest_fmt< PROC_IF_REST_FMT_ENUM_MAX, return STAT_ERROR);
1588  CHECK_DO(ref_reponse!= NULL, return STAT_ERROR);
1589 
1590  LOG_CTX_SET(proc_ctx->log_ctx);
1591 
1592  *ref_reponse= NULL;
1593 
1594  /* Create cJSON tree root object */
1595  cjson_rest= cJSON_CreateObject();
1596  CHECK_DO(cjson_rest!= NULL, goto end);
1597 
1598  /* JSON string to be returned:
1599  * {
1600  * // "settings":{}, //RAL: Do not expose in current implementation!
1601  * "sdp_mimetype":string,
1602  * "rtp_timestamp_freq":number
1603  * ... // Reserved for future use
1604  * }
1605  */
1606 
1607  /* Get FFmpeg video encoder settings contexts */
1608  live555_rtsp_es_mux_ctx= (live555_rtsp_es_mux_ctx_t*)proc_ctx;
1609  live555_rtsp_es_mux_settings_ctx=
1610  &live555_rtsp_es_mux_ctx->live555_rtsp_es_mux_settings_ctx;
1611 
1612  /* **** GET specific ES-MUXER settings **** */
1613 
1614  /* Create cJSON settings object */ // Not used
1615  //cjson_settings= cJSON_CreateObject();
1616  //CHECK_DO(cjson_settings!= NULL, goto end);
1617 
1618  /* Attach settings object to REST response */ // Not used
1619  //cJSON_AddItemToObject(cjson_rest, "settings", cjson_settings);
1620  //cjson_settings= NULL; // Attached; avoid double referencing
1621 
1622  /* **** Attach data to REST response **** */
1623 
1624  /* 'sdp_mimetype' */
1625  cjson_aux= cJSON_CreateString(
1626  live555_rtsp_es_mux_settings_ctx->sdp_mimetype);
1627  CHECK_DO(cjson_aux!= NULL, goto end);
1628  cJSON_AddItemToObject(cjson_rest, "sdp_mimetype", cjson_aux);
1629 
1630  /* 'rtp_timestamp_freq' */
1631  cjson_aux= cJSON_CreateNumber((double)
1632  live555_rtsp_es_mux_settings_ctx->rtp_timestamp_freq);
1633  CHECK_DO(cjson_aux!= NULL, goto end);
1634  cJSON_AddItemToObject(cjson_rest, "rtp_timestamp_freq", cjson_aux);
1635 
1636  // Reserved for future use
1637  /* Example:
1638  * cjson_aux= cJSON_CreateNumber((double)live555_rtsp_es_mux_ctx->var1);
1639  * CHECK_DO(cjson_aux!= NULL, goto end);
1640  * cJSON_AddItemToObject(cjson_rest, "var1_name", cjson_aux);
1641  */
1642 
1643  // Reserved for future use: set other data values here...
1644 
1645  /* Format response to be returned */
1646  switch(rest_fmt) {
1647  case PROC_IF_REST_FMT_CHAR:
1648  /* Print cJSON structure data to char string */
1649  *ref_reponse= (void*)CJSON_PRINT(cjson_rest);
1650  CHECK_DO(*ref_reponse!= NULL && strlen((char*)*ref_reponse)> 0,
1651  goto end);
1652  break;
1654  *ref_reponse= (void*)cjson_rest;
1655  cjson_rest= NULL; // Avoid double referencing
1656  break;
1657  default:
1658  LOGE("Unknown format requested for processor REST\n");
1659  goto end;
1660  }
1661 
1662  end_code= STAT_SUCCESS;
1663 end:
1664  //if(cjson_settings!= NULL) // Not used
1665  // cJSON_Delete(cjson_settings);
1666  if(cjson_rest!= NULL)
1667  cJSON_Delete(cjson_rest);
1668  return end_code;
1669 }
1670 
1671 static int live555_rtsp_es_mux_settings_ctx_init(
1673  live555_rtsp_es_mux_settings_ctx, log_ctx_t *log_ctx)
1674 {
1675  LOG_CTX_INIT(log_ctx);
1676 
1677  /* Check arguments */
1678  CHECK_DO(live555_rtsp_es_mux_settings_ctx!= NULL, return STAT_ERROR);
1679 
1680  live555_rtsp_es_mux_settings_ctx->sdp_mimetype= strdup("n/a");
1681  CHECK_DO(live555_rtsp_es_mux_settings_ctx->sdp_mimetype!= NULL,
1682  return STAT_ERROR);
1683  live555_rtsp_es_mux_settings_ctx->rtp_timestamp_freq= 9000;
1684 
1685  return STAT_SUCCESS;
1686 }
1687 
1688 static void live555_rtsp_es_mux_settings_ctx_deinit(
1690  live555_rtsp_es_mux_settings_ctx, log_ctx_t *log_ctx)
1691 {
1692  LOG_CTX_INIT(log_ctx);
1693 
1694  /* Check arguments */
1695  CHECK_DO(live555_rtsp_es_mux_settings_ctx!= NULL, return);
1696 
1697  /* Release ES-MUXER specific settings */
1698  if(live555_rtsp_es_mux_settings_ctx->sdp_mimetype!= NULL) {
1699  free(live555_rtsp_es_mux_settings_ctx->sdp_mimetype);
1700  live555_rtsp_es_mux_settings_ctx->sdp_mimetype= NULL;
1701  }
1702 }
1703 
1704 /* **** So-called "framed-sink class implementation **** */
1705 
1706 SimpleRTPSink2::SimpleRTPSink2(UsageEnvironment& env, Groupsock* RTPgs,
1707  unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency,
1708  char const* sdpMediaTypeString, char const* rtpPayloadFormatName,
1709  unsigned numChannels, Boolean allowMultipleFramesPerPacket,
1710  Boolean doNormalMBitRule):
1711  MultiFramedRTPSink(env, RTPgs, rtpPayloadFormat,
1712  rtpTimestampFrequency, rtpPayloadFormatName,
1713  numChannels),
1714  fAllowMultipleFramesPerPacket(allowMultipleFramesPerPacket),
1715  fSetMBitOnNextPacket(False)
1716 {
1717  fSDPMediaTypeString= strDup(
1718  sdpMediaTypeString== NULL? "unknown": sdpMediaTypeString);
1719  fSetMBitOnLastFrames= doNormalMBitRule
1720  /*&& strcmp(fSDPMediaTypeString, "audio")!= 0*/;
1721 }
1722 
1723 SimpleRTPSink2::~SimpleRTPSink2()
1724 {
1725  delete[] (char*)fSDPMediaTypeString;
1726 }
1727 
1728 SimpleRTPSink2* SimpleRTPSink2::createNew(
1729  UsageEnvironment& env, Groupsock* RTPgs,
1730  unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency,
1731  char const* sdpMediaTypeString, char const* rtpPayloadFormatName,
1732  unsigned numChannels, Boolean allowMultipleFramesPerPacket,
1733  Boolean doNormalMBitRule)
1734 {
1735  return new SimpleRTPSink2(env, RTPgs, rtpPayloadFormat,
1736  rtpTimestampFrequency, sdpMediaTypeString, rtpPayloadFormatName,
1737  numChannels, allowMultipleFramesPerPacket, doNormalMBitRule);
1738 }
1739 
1740 void SimpleRTPSink2::doSpecialFrameHandling(unsigned fragmentationOffset,
1741  unsigned char* frameStart,
1742  unsigned numBytesInFrame,
1743  struct timeval framePresentationTime,
1744  unsigned numRemainingBytes) {
1745  if(numRemainingBytes== 0) {
1746  // This packet contains the last (or only) fragment of the frame.
1747  // Set the RTP 'M' ('marker') bit, if appropriate:
1748  if(fSetMBitOnLastFrames)
1749  setMarkerBit();
1750  }
1751  if(fSetMBitOnNextPacket) {
1752  //An external object asked for the 'M' bit to be set on the next packet:
1753  setMarkerBit();
1754  fSetMBitOnNextPacket = False;
1755  }
1756 
1757  // Important: Also call our base class's doSpecialFrameHandling(),
1758  // to set the packet's timestamp:
1759  MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset,
1760  frameStart, numBytesInFrame, framePresentationTime,
1761  numRemainingBytes);
1762 }
1763 
1764 Boolean SimpleRTPSink2::frameCanAppearAfterPacketStart(
1765  unsigned char const* /*frameStart*/, unsigned /*numBytesInFrame*/)
1766 const
1767 {
1768  return fAllowMultipleFramesPerPacket;
1769 }
1770 
1771 char const* SimpleRTPSink2::sdpMediaType() const
1772 {
1773  return fSDPMediaTypeString;
1774 }
1775 
1776 /* **** So-called "framed-source" class implementation **** */
1777 
1778 SimpleFramedSource *SimpleFramedSource::createNew(UsageEnvironment& env,
1779  log_ctx_t *log_ctx)
1780 {
1781  return new SimpleFramedSource(env, log_ctx);
1782 }
1783 
1784 SimpleFramedSource::SimpleFramedSource(UsageEnvironment& env,
1785  log_ctx_t *log_ctx):
1786  FramedSource(env),
1787  m_log_ctx(log_ctx)
1788 {
1789  fifo_elem_alloc_fxn_t fifo_elem_alloc_fxn= {0};
1790  LOG_CTX_INIT(m_log_ctx);
1791  LOGD(">>::SimpleFramedSource\n"); //comment-me
1792 
1793  /* Initialize input FIFO buffer as *NON-BLOCKING* */
1794  fifo_elem_alloc_fxn.elem_ctx_dup=
1795  (fifo_elem_ctx_dup_fxn_t*)proc_frame_ctx_dup;
1796  fifo_elem_alloc_fxn.elem_ctx_release=
1797  (fifo_elem_ctx_release_fxn_t*)proc_frame_ctx_release;
1798  m_fifo_ctx= fifo_open(FRAMED_SOURCE_FIFO_SLOTS, 0/*unlimited chunk size*/,
1799  FIFO_O_NONBLOCK, &fifo_elem_alloc_fxn);
1800  ASSERT(m_fifo_ctx!= NULL);
1801 
1802  /* We arrange here for our "deliverFrame" member function to be called
1803  * whenever the next frame of data becomes available from the device.
1804  */
1805  m_eventTriggerId= envir().taskScheduler().createEventTrigger(deliverFrame0);
1806 
1807  LOGD("<<::SimpleFramedSource\n"); //comment-me
1808 }
1809 
1810 SimpleFramedSource::~SimpleFramedSource()
1811 {
1812  LOGD_CTX_INIT(m_log_ctx);
1813  LOGD(">>::~SimpleFramedSource\n"); //comment-me
1814 
1815  /* Release input and output FIFO's */
1816  fifo_close(&m_fifo_ctx);
1817 
1818  /* Reclaim our 'event trigger' */
1819  envir().taskScheduler().deleteEventTrigger(m_eventTriggerId);
1820  m_eventTriggerId= 0;
1821 
1822  LOGD("<<::~SimpleFramedSource\n"); //comment-me
1823 }
1824 
1825 void SimpleFramedSource::doGetNextFrame()
1826 {
1827  LOGD_CTX_INIT(m_log_ctx);
1828  LOGD(">>SimpleFramedSource::doGetNextFrame\n"); //comment-me
1829 
1830  /*//Reserved for future use
1831  * Note: If, for some reason, the source device stops being readable
1832  * (e.g., it gets closed), then you do the following:
1833  */
1834  if(0 /* the source stops being readable */) {
1835  handleClosure();
1836  return;
1837  }
1838 
1839  /* Directly deliver the next frame of data if is immediately available */
1840  if(m_fifo_ctx!= NULL && fifo_get_buffer_level(m_fifo_ctx)> 0)
1841  deliverFrame();
1842 
1843 
1844  LOGD("<<SimpleFramedSource::doGetNextFrame\n"); //comment-me
1845 }
1846 
1847 void SimpleFramedSource::deliverFrame0(void *simpleFramedSource_opaque)
1848 {
1849  LOGD_CTX_INIT(NULL);
1850  LOGD(">>%s\n", __FUNCTION__); //comment-me
1851  ((SimpleFramedSource*)simpleFramedSource_opaque)->deliverFrame();
1852  LOGD("<<%s\n", __FUNCTION__); //comment-me
1853 }
1854 
1880 {
1881  uint8_t *newFrame= NULL;
1882  int ret_code, newFrameSize= 0;
1883  proc_frame_ctx_t *proc_frame_ctx_show= NULL; //Do not release but modify
1884  size_t fifo_elem_size= 0;
1885  LOG_CTX_INIT(m_log_ctx);
1886  LOGD(">>%s\n", __FUNCTION__); //comment-me
1887 
1888  if(!isCurrentlyAwaitingData()) {
1889  LOGD("-!isCurrentlyAwaitingData()-"); //comment-me
1890  goto end; // we're not ready for the data yet
1891  }
1892 
1893  /* Show (but not consume yet) next packet from FIFO buffer.
1894  * The packet, if not fully consumed, will be modified.
1895  * The 'ret_code' should always be 'STAT_SUCCESS' as this method should
1896  * only be called if there is data available. Also, note that this FIFO is
1897  * *NOT* blocking.
1898  */
1899  ret_code= fifo_show(m_fifo_ctx, (void**)&proc_frame_ctx_show,
1900  &fifo_elem_size);
1901  CHECK_DO(ret_code== STAT_SUCCESS && proc_frame_ctx_show!= NULL, goto end);
1902 
1903  /* Get input frame pointer and size */
1904  newFrame= (uint8_t*)proc_frame_ctx_show->p_data[0];
1905  newFrameSize= proc_frame_ctx_show->width[0];
1906  if(newFrameSize> (int)fMaxSize) {
1907  LOGW("Input frame fragmented (Elementary Stream Id.: %d\n)",
1908  proc_frame_ctx_show->es_id);
1909  fFrameSize= fMaxSize;
1910  fNumTruncatedBytes= newFrameSize- fMaxSize;
1911  /* Update frame pointer and size for next call to deliverFrame() */
1912  proc_frame_ctx_show->p_data[0]= (const uint8_t*)(newFrame+ fMaxSize);
1913  proc_frame_ctx_show->width[0]-= fMaxSize;
1914  } else {
1915  fFrameSize= newFrameSize;
1916  fNumTruncatedBytes= 0;
1917  }
1918  gettimeofday(&fPresentationTime, NULL); //TODO
1919 
1920  /* Copy frame (or segment) to output buffer */
1921  memmove(fTo, newFrame, fFrameSize);
1922 
1923  /* After delivering the data, inform the reader that it is now available */
1924  FramedSource::afterGetting(this);
1925 
1926  /* Consume packet from FIFO if fully used (not truncated) */
1927  if(fNumTruncatedBytes== 0) {
1928  proc_frame_ctx_t *proc_frame_ctx= NULL;
1929  ret_code= fifo_get(m_fifo_ctx, (void**)&proc_frame_ctx,
1930  &fifo_elem_size);
1931  ASSERT(ret_code== STAT_SUCCESS);
1932  proc_frame_ctx_release(&proc_frame_ctx);
1933  }
1934 
1935 end:
1936  LOGD("<<%s\n", __FUNCTION__); //comment-me
1937  return;
1938 }
1939 
1940 /* **** So-called "media sub-session" class implementation **** */
1941 
1942 SimpleMediaSubsession * SimpleMediaSubsession::createNew(UsageEnvironment &env,
1943  const char *sdp_mimetype, portNumBits initialPortNum,
1944  Boolean multiplexRTCPWithRTP)
1945 {
1946  return new SimpleMediaSubsession(env, sdp_mimetype, initialPortNum,
1947  multiplexRTCPWithRTP);
1948 }
1949 
1950 SimpleMediaSubsession::SimpleMediaSubsession(UsageEnvironment &env,
1951  const char *sdp_mimetype, portNumBits initialPortNum,
1952  Boolean multiplexRTCPWithRTP):
1953  OnDemandServerMediaSubsession(env, True/*reuseFirstSource*/,
1954  initialPortNum, multiplexRTCPWithRTP),
1955  m_simpleFramedSource(NULL),
1956  m_log_ctx(NULL)
1957 {
1958  LOGD_CTX_INIT(m_log_ctx);
1959  LOGD(">>::SimpleMediaSubsession\n"); //comment-me
1960 
1961  /* Check members initialization */
1962  if(sdp_mimetype!= NULL && strlen(sdp_mimetype)> 0)
1963  m_sdp_mimetype= sdp_mimetype;
1964  else
1965  m_sdp_mimetype= (const char*)"n/a";
1966 
1967  LOGD("<<::SimpleMediaSubsession\n"); //comment-me
1968 }
1969 
1970 void SimpleMediaSubsession::deliverFrame(proc_frame_ctx_t **ref_proc_frame_ctx)
1971 {
1972  LOG_CTX_INIT(m_log_ctx);
1973 
1974  /* Check arguments */
1975  CHECK_DO(ref_proc_frame_ctx!= NULL && *ref_proc_frame_ctx!= NULL, return);
1976 
1977  m_simpleFramedSource_mutex.lock();
1978 
1979  if(m_simpleFramedSource!= NULL) {
1980  int ret_code;
1981 
1982  /* Pass input frame reference to framed-source FIFO */
1983  ret_code= fifo_put(m_simpleFramedSource->m_fifo_ctx,
1984  (void**)ref_proc_frame_ctx, sizeof(void*));
1985  if(ret_code== STAT_ENOMEM)
1986  LOGW("MUXER buffer overflow: throughput may be exceeding "
1987  "processing capacity?\n");
1988  else
1989  ASSERT(*ref_proc_frame_ctx== NULL);
1990 
1991  /* Notify scheduler that we have a new frame!. Note that
1992  * 'm_simpleFramedSource' handler will be available only if a RTSP
1993  * session is established with a RTSP client.
1994  * If handler is available, we just trigger the corresponding
1995  * framed-source event; framed-source will internally read the FIFO
1996  * buffer and consume the input frame. If handler is not available
1997  * (namely, we have a NULL handler reference), we should consume the
1998  * input frame to avoid buffer overflowing (the calling function
1999  * consumes it).
2000  */
2001  envir().taskScheduler().triggerEvent(
2002  m_simpleFramedSource->m_eventTriggerId, m_simpleFramedSource);
2003  }
2004 
2005  m_simpleFramedSource_mutex.unlock();
2006  return;
2007 }
2008 
2009 /*
2010  * This method is called internally by the parent class
2011  * OnDemandServerMediaSubsession.
2012  */
2013 FramedSource* SimpleMediaSubsession::createNewStreamSource(
2014  unsigned clientSessionId, unsigned &estBitrate)
2015 {
2016  FramedSource *framedSource= NULL;
2017  LOG_CTX_INIT(m_log_ctx);
2018 
2019  LOGD(">> SimpleMediaSubsession::createNewStreamSource\n"); //comment-me
2020 
2021  estBitrate= 3000; /* Kbps */
2022  OutPacketBuffer::increaseMaxSizeTo(SINK_BUFFER_SIZE);
2023 
2024  /* Instantiate (and initialize) simple framed source */
2025  framedSource= SimpleFramedSource::createNew(envir(), LOG_CTX_GET());
2026  m_simpleFramedSource_mutex.lock();
2027  m_simpleFramedSource= (SimpleFramedSource*)framedSource;
2028  m_simpleFramedSource_mutex.unlock();
2029 
2030  // Reserved for future use: here instantiate so-called "discrete framer"
2031 
2032  LOGD("<< SimpleMediaSubsession::createNewStreamSource\n"); //comment-me
2033  return framedSource;
2034 }
2035 
2036 void SimpleMediaSubsession::deleteStream(unsigned clientSessionId,
2037  void*& streamToken)
2038 {
2039  LOGD_CTX_INIT(m_log_ctx);
2040 
2041  LOGD(">> SimpleMediaSubsession::deleteStream\n"); //comment-me
2042  m_simpleFramedSource_mutex.lock();
2043  m_simpleFramedSource= NULL;
2044  m_simpleFramedSource_mutex.unlock();
2045  OnDemandServerMediaSubsession::deleteStream(clientSessionId, streamToken);
2046  LOGD("<< SimpleMediaSubsession::deleteStream\n"); //comment-me
2047 }
2048 
2049 void SimpleMediaSubsession::closeStreamSource(FramedSource* inputSource)
2050 {
2051  LOGD_CTX_INIT(m_log_ctx);
2052  LOGD(">> SimpleMediaSubsession::closeStreamSource\n"); //comment-me
2053  m_simpleFramedSource_mutex.lock();
2054  m_simpleFramedSource= NULL;
2055  m_simpleFramedSource_mutex.unlock();
2056  OnDemandServerMediaSubsession::closeStreamSource(inputSource);
2057  LOGD("<< SimpleMediaSubsession::closeStreamSource\n"); //comment-me
2058 }
2059 
2060 RTPSink* SimpleMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,
2061  unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource)
2062 {
2063  char *sdp_p; // Do not release
2064  RTPSink *rtpSink= NULL;
2065  char *type_str= NULL, *subtype_str= NULL;
2066  LOG_CTX_INIT(m_log_ctx);
2067  LOGD(">>SimpleMediaSubsession::createNewRTPSink\n"); //comment-me
2068 
2069  /* Sanity checks */
2070  CHECK_DO(m_sdp_mimetype!= NULL, goto end);
2071 
2072  /* Extract MIME type and sub-type */
2073  sdp_p= strchr((char*)m_sdp_mimetype, '/');
2074  if(sdp_p!= NULL && strlen(m_sdp_mimetype)> 0)
2075  type_str= strndup(m_sdp_mimetype, sdp_p- m_sdp_mimetype);
2076  else
2077  type_str= strdup("n/a");
2078  if(sdp_p!= NULL && strlen(sdp_p+ 1)> 0)
2079  subtype_str= strdup(sdp_p+ 1);
2080  else
2081  subtype_str= strdup("n/a");
2082 
2083  /* Select specific RTP-Sink */
2084  // Reserved for future; e.g.:
2085  //if(strcmp(sdp_mimetype, "video/LHE")== 0) {
2086  // "function pointer"= myRTPSink::createNew;
2087  //}
2088 
2089  /* Create Sink */
2090  rtpSink= SimpleRTPSink2::createNew(envir(), rtpGroupsock,
2091  rtpPayloadTypeIfDynamic, 90000, type_str, subtype_str,
2092  1,
2093  False/*allowMultipleFramesPerPacket*/, True /*doNormalMBitRule*/);
2094 
2095 end:
2096  if(type_str!= NULL)
2097  free(type_str);
2098  if(subtype_str!= NULL)
2099  free(subtype_str);
2100  LOGD("<<SimpleMediaSubsession::createNewRTPSink\n"); //comment-me
2101  return rtpSink;
2102 }
2103 
2104 /* **** De-multiplexer **** */
2105 
2111  const char *settings_str, log_ctx_t *log_ctx, va_list arg)
2112 {
2113  int ret_code, end_code= STAT_ERROR;
2114  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL;
2115  volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx=
2116  NULL; // Do not release (alias)
2117  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx=
2118  NULL; // Do not release (alias)
2119  LOG_CTX_INIT(log_ctx);
2120 
2121  /* Check arguments */
2122  CHECK_DO(proc_if!= NULL, return NULL);
2123  CHECK_DO(settings_str!= NULL, return NULL);
2124  // Note: 'log_ctx' is allowed to be NULL
2125 
2126  /* Allocate context structure */
2127  live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)calloc(1, sizeof(
2129  CHECK_DO(live555_rtsp_dmux_ctx!= NULL, goto end);
2130 
2131  /* Get settings structures */
2132  live555_rtsp_dmux_settings_ctx=
2133  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx;
2134  muxers_settings_dmux_ctx=
2135  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2136 
2137  /* Initialize settings to defaults */
2139  live555_rtsp_dmux_settings_ctx, LOG_CTX_GET());
2140  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
2141 
2142  /* Parse and put given settings */
2143  ret_code= live555_rtsp_dmux_rest_put((proc_ctx_t*)live555_rtsp_dmux_ctx,
2144  settings_str);
2145  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
2146 
2147  /* **** Initialize the specific Live555 de-multiplexer resources ****
2148  * Now that all the parameters are set, we proceed with Live555 specific's.
2149  */
2150  ret_code= live555_rtsp_dmux_init_given_settings(live555_rtsp_dmux_ctx,
2151  (const muxers_settings_dmux_ctx_t*)muxers_settings_dmux_ctx,
2152  LOG_CTX_GET());
2153  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
2154 
2155  end_code= STAT_SUCCESS;
2156 end:
2157  if(end_code!= STAT_SUCCESS)
2158  live555_rtsp_dmux_close((proc_ctx_t**)&live555_rtsp_dmux_ctx);
2159  return (proc_ctx_t*)live555_rtsp_dmux_ctx;
2160 }
2161 
2162 static int live555_rtsp_dmux_init_given_settings(
2163  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx,
2164  const muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx,
2165  log_ctx_t *log_ctx)
2166 {
2167  int end_code= STAT_ERROR;
2168  LOG_CTX_INIT(log_ctx);
2169 
2170  /* Check arguments */
2171  CHECK_DO(live555_rtsp_dmux_ctx!= NULL, return STAT_ERROR);
2172  CHECK_DO(muxers_settings_dmux_ctx!= NULL, return STAT_ERROR);
2173  // Note: 'log_ctx' is allowed to be NULL
2174 
2175  /* Open Live555 scheduler */
2176  live555_rtsp_dmux_ctx->taskScheduler= BasicTaskScheduler::createNew();
2177  CHECK_DO(live555_rtsp_dmux_ctx->taskScheduler!= NULL, goto end);
2178 
2179  /* Set up Live555 usage environment. */
2180  live555_rtsp_dmux_ctx->usageEnvironment= BasicUsageEnvironment::createNew(
2181  *live555_rtsp_dmux_ctx->taskScheduler);
2182  CHECK_DO(live555_rtsp_dmux_ctx->usageEnvironment!= NULL, goto end);
2183  live555_rtsp_dmux_ctx->usageEnvironment->liveMediaPriv= NULL;
2184  live555_rtsp_dmux_ctx->usageEnvironment->groupsockPriv= NULL;
2185 
2186  end_code= STAT_SUCCESS;
2187 end:
2188  if(end_code!= STAT_SUCCESS)
2189  live555_rtsp_dmux_deinit_except_settings(live555_rtsp_dmux_ctx,
2190  LOG_CTX_GET());
2191  return end_code;
2192 }
2193 
2198 static void live555_rtsp_dmux_close(proc_ctx_t **ref_proc_ctx)
2199 {
2200  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL;
2201  LOG_CTX_INIT(NULL);
2202  LOGD(">> %s\n", __FUNCTION__); //comment-me
2203 
2204  if(ref_proc_ctx== NULL)
2205  return;
2206 
2207  if((live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)*ref_proc_ctx)!=
2208  NULL) {
2209  LOG_CTX_SET(((proc_ctx_t*)live555_rtsp_dmux_ctx)->log_ctx);
2210 
2211  /* Implementation note: 'live555_rtsp_dmux_process_frame()' is
2212  * exited first (and previously,
2213  * '((proc_ctx_t*)live555_rtsp_dmux_ctx)->flag_exit' is set to 1
2214  * accordingly.
2215  */
2216 
2217  /* Release settings */
2219  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx,
2220  LOG_CTX_GET());
2221 
2222  /* **** Release the specific Live555 de-multiplexer resources **** */
2223 
2224  live555_rtsp_dmux_deinit_except_settings(live555_rtsp_dmux_ctx,
2225  LOG_CTX_GET());
2226 
2227  // Reserved for future use: release other new variables here...
2228  /* Release context structure */
2229  free(live555_rtsp_dmux_ctx);
2230  *ref_proc_ctx= NULL;
2231  }
2232  LOGD("<< %s\n", __FUNCTION__); //comment-me
2233 }
2234 
2235 static void live555_rtsp_dmux_deinit_except_settings(
2236  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx, log_ctx_t *log_ctx)
2237 {
2238  LOG_CTX_INIT(log_ctx);
2239 
2240  if(live555_rtsp_dmux_ctx== NULL)
2241  return;
2242 
2243  if(live555_rtsp_dmux_ctx->usageEnvironment!= NULL) {
2244  Boolean ret_boolean= live555_rtsp_dmux_ctx->usageEnvironment->reclaim();
2245  ASSERT(ret_boolean== True);
2246  if(ret_boolean== True)
2247  live555_rtsp_dmux_ctx->usageEnvironment= NULL;
2248  }
2249 
2250  if(live555_rtsp_dmux_ctx->taskScheduler!= NULL) {
2251  delete live555_rtsp_dmux_ctx->taskScheduler;
2252  live555_rtsp_dmux_ctx->taskScheduler= NULL;
2253  }
2254 }
2255 
2261  const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
2262 {
2263  int end_code= STAT_ERROR;
2264  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL;
2265  volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx=
2266  NULL;
2267  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx= NULL;
2268  SimpleRTSPClient *simpleRTSPClient= NULL;
2269  MediaSession* session= NULL;
2270  cJSON *cjson_rest= NULL, *cjson_settings= NULL, *cjson_es_array= NULL,
2271  *cjson_es= NULL;
2272  cJSON *cjson_aux= NULL; // Do not release
2273  char sdp_mimetype_buf[512];
2274  LOG_CTX_INIT(NULL);
2275 
2276  /* Check arguments */
2277  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
2278  CHECK_DO(rest_fmt< PROC_IF_REST_FMT_ENUM_MAX, return STAT_ERROR);
2279  CHECK_DO(ref_reponse!= NULL, return STAT_ERROR);
2280 
2281  LOG_CTX_SET(proc_ctx->log_ctx);
2282 
2283  *ref_reponse= NULL;
2284 
2285  /* Create cJSON tree root object */
2286  cjson_rest= cJSON_CreateObject();
2287  CHECK_DO(cjson_rest!= NULL, goto end);
2288 
2289  /* JSON string to be returned:
2290  * {
2291  * "settings":
2292  * {
2293  * "rtsp_url":string
2294  * },
2295  * elementary_streams:
2296  * [
2297  * {
2298  * "sdp_mimetype":string,
2299  * "port":number,
2300  * "elementary_stream_id":number
2301  * },
2302  * ...
2303  * ]
2304  * ... // Reserved for future use
2305  * }
2306  */
2307 
2308  /* Get FFmpeg video encoder settings contexts */
2309  live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)proc_ctx;
2310  live555_rtsp_dmux_settings_ctx=
2311  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx;
2312  muxers_settings_dmux_ctx=
2313  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2314 
2315  /* **** GET specific ES-MUXER settings **** */
2316 
2317  /* Create cJSON settings object */
2318  cjson_settings= cJSON_CreateObject();
2319  CHECK_DO(cjson_settings!= NULL, goto end);
2320 
2321  /* 'rtsp_url' */
2322  cjson_aux= cJSON_CreateString(muxers_settings_dmux_ctx->rtsp_url);
2323  CHECK_DO(cjson_aux!= NULL, goto end);
2324  cJSON_AddItemToObject(cjson_settings, "rtsp_url", cjson_aux);
2325 
2326  /* Attach settings object to REST response */
2327  cJSON_AddItemToObject(cjson_rest, "settings", cjson_settings);
2328  cjson_settings= NULL; // Attached; avoid double referencing
2329 
2330  /* **** Attach data to REST response **** */
2331 
2332  /* Create ES-processors array REST and attach*/
2333  cjson_es_array= cJSON_CreateArray();
2334  CHECK_DO(cjson_es_array!= NULL, goto end);
2335 
2336  simpleRTSPClient= live555_rtsp_dmux_ctx->simpleRTSPClient;
2337  CHECK_DO(simpleRTSPClient!= NULL, goto end);
2338 
2339  session= simpleRTSPClient->streamClientState.session;
2340  if(session!= NULL) {
2341  MediaSubsession *subsession= NULL;
2342  MediaSubsessionIterator iter(*session);
2343  while((subsession= iter.next())!= NULL && proc_ctx->flag_exit== 0) {
2344 
2345  /* Create ES-processor cJSON */
2346  if(cjson_es!= NULL) {
2347  cJSON_Delete(cjson_es);
2348  cjson_es= NULL;
2349  }
2350  cjson_es= cJSON_CreateObject();
2351  CHECK_DO(cjson_es!= NULL, goto end);
2352 
2353  /* 'sdp_mimetype' */
2354  memset(sdp_mimetype_buf, 0, sizeof(sdp_mimetype_buf));
2355  snprintf(sdp_mimetype_buf, sizeof(sdp_mimetype_buf), "%s/%s",
2356  subsession->mediumName(), subsession->codecName());
2357  cjson_aux= cJSON_CreateString(sdp_mimetype_buf);
2358  CHECK_DO(cjson_aux!= NULL, goto end);
2359  cJSON_AddItemToObject(cjson_es, "sdp_mimetype", cjson_aux);
2360 
2361  /* 'port' */
2362  cjson_aux= cJSON_CreateNumber((double)subsession->clientPortNum());
2363  CHECK_DO(cjson_aux!= NULL, goto end);
2364  cJSON_AddItemToObject(cjson_es, "port", cjson_aux);
2365 
2366  /* 'elementary_stream_id' (we use port number as unique Id.) */
2367  cjson_aux= cJSON_CreateNumber((double)subsession->clientPortNum());
2368  CHECK_DO(cjson_aux!= NULL, goto end);
2369  cJSON_AddItemToObject(cjson_es, "elementary_stream_id", cjson_aux);
2370 
2371  /* Attach elementary stream data to array */
2372  cJSON_AddItemToArray(cjson_es_array, cjson_es);
2373  cjson_es= NULL; // Attached; avoid double referencing
2374  }
2375  }
2376 
2377  /* Attach elementary stream data array to REST response */
2378  cJSON_AddItemToObject(cjson_rest, "elementary_streams", cjson_es_array);
2379  cjson_es_array= NULL; // Attached; avoid double referencing
2380 
2381  // Reserved for future use
2382  /* Example:
2383  * cjson_aux= cJSON_CreateNumber((double)live555_rtsp_dmux_ctx->var1);
2384  * CHECK_DO(cjson_aux!= NULL, goto end);
2385  * cJSON_AddItemToObject(cjson_rest, "var1_name", cjson_aux);
2386  */
2387 
2388  // Reserved for future use: set other data values here...
2389 
2390  /* Format response to be returned */
2391  switch(rest_fmt) {
2392  case PROC_IF_REST_FMT_CHAR:
2393  /* Print cJSON structure data to char string */
2394  *ref_reponse= (void*)CJSON_PRINT(cjson_rest);
2395  CHECK_DO(*ref_reponse!= NULL && strlen((char*)*ref_reponse)> 0,
2396  goto end);
2397  break;
2399  *ref_reponse= (void*)cjson_rest;
2400  cjson_rest= NULL; // Avoid double referencing
2401  break;
2402  default:
2403  LOGE("Unknown format requested for processor REST\n");
2404  goto end;
2405  }
2406 
2407  end_code= STAT_SUCCESS;
2408 end:
2409  if(cjson_settings!= NULL)
2410  cJSON_Delete(cjson_settings);
2411  if(cjson_rest!= NULL)
2412  cJSON_Delete(cjson_rest);
2413  if(cjson_es_array!= NULL)
2414  cJSON_Delete(cjson_es_array);
2415  if(cjson_es!= NULL)
2416  cJSON_Delete(cjson_es);
2417  return end_code;
2418 }
2419 
2425  fifo_ctx_t* iput_fifo_ctx, fifo_ctx_t* oput_fifo_ctx)
2426 {
2427  char *rtsp_url;
2428  char volatile *watchVariable;
2429  int ret_code, end_code= STAT_ERROR;
2430  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL; // Do not release
2431  volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx=
2432  NULL; // Do not release (alias)
2433  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx=
2434  NULL; // Do not release (alias)
2435  UsageEnvironment *usageEnvironment= NULL; // Do not release
2436  LOG_CTX_INIT(NULL);
2437 
2438  /* Check arguments */
2439  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
2440  CHECK_DO(iput_fifo_ctx!= NULL, return STAT_ERROR);
2441  CHECK_DO(oput_fifo_ctx!= NULL, return STAT_ERROR);
2442 
2443  LOG_CTX_SET(proc_ctx->log_ctx);
2444 
2445  /* Get multiplexer context */
2446  live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)proc_ctx;
2447 
2448  /* Get Live555's usage environment */
2449  usageEnvironment= live555_rtsp_dmux_ctx->usageEnvironment;
2450  CHECK_DO(usageEnvironment!= NULL, goto end);
2451 
2452  /* Get settings structures */
2453  live555_rtsp_dmux_settings_ctx=
2454  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx;
2455  muxers_settings_dmux_ctx=
2456  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2457 
2458  /* Create a unique "RTSPClient" for the stream that we wish to
2459  * receive ("rtsp://" URL).
2460  */
2461  rtsp_url= muxers_settings_dmux_ctx->rtsp_url;
2462  if(rtsp_url== NULL) {
2463  LOGE("A valid RTSP URL must be provided\n");
2464  goto end;
2465  }
2466  live555_rtsp_dmux_ctx->simpleRTSPClient= SimpleRTSPClient::createNew(
2467  *live555_rtsp_dmux_ctx->usageEnvironment, rtsp_url,
2468  &((proc_ctx_t*)live555_rtsp_dmux_ctx)->flag_exit,
2469  ((proc_ctx_t*)live555_rtsp_dmux_ctx)->fifo_ctx_array[PROC_OPUT],
2470  0/*No-verbose*/, "n/a"/*application-name*/, 0, LOG_CTX_GET());
2471  if(live555_rtsp_dmux_ctx->simpleRTSPClient== NULL) {
2472  LOGE("Failed to create a RTSP client for URL %s: %s\n", rtsp_url,
2473  live555_rtsp_dmux_ctx->usageEnvironment->getResultMsg());
2474  goto end;
2475  }
2476 
2477  /* Send a RTSP "DESCRIBE" command to get a SDP description for the stream.
2478  * Note that this command -like all RTSP commands- is sent asynchronously;
2479  * we do not block waiting for a response, instead, the following function
2480  * call returns immediately, and we handle the RTSP response later, from
2481  * within the event loop 'doEventLoop()'.
2482  *
2483  */
2484  ret_code= live555_rtsp_dmux_ctx->simpleRTSPClient->sendDescribeCommand(
2485  continueAfterDESCRIBE);
2486  if(ret_code== 0) {
2487  LOGE("Failed to send DESCRIBE to RTSP client for URL %s: %s\n",
2488  rtsp_url,
2489  live555_rtsp_dmux_ctx->usageEnvironment->getResultMsg());
2490  goto end;
2491  }
2492 
2493  /* Implementation note: In the case of the LIVE555's de-multiplexer
2494  * implementation, we use 'live555_rtsp_dmux_process_frame()' just to
2495  * execute the task scheduler event loop. We do not read nor write to
2496  * input or output FIFOs directly. This is performed synchronously using
2497  * the task scheduler registered events.
2498  */
2499 
2500  /* Run the scheduler until "exit flag" is set */
2501  watchVariable= (char volatile*)
2502  &((proc_ctx_t*)live555_rtsp_dmux_ctx)->flag_exit;
2503  usageEnvironment->taskScheduler().doEventLoop(watchVariable);
2504 
2505  end_code= STAT_SUCCESS;
2506 end:
2507  if(live555_rtsp_dmux_ctx->simpleRTSPClient!= NULL)
2508  shutdownStream(live555_rtsp_dmux_ctx->simpleRTSPClient);
2509  return end_code;
2510 }
2511 
2516 static int live555_rtsp_dmux_rest_put(proc_ctx_t *proc_ctx, const char *str)
2517 {
2518  int ret_code;
2519  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL;
2521  live555_rtsp_dmux_settings_ctx= NULL;
2522  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx= NULL;
2523  LOG_CTX_INIT(NULL);
2524 
2525  /* Check arguments */
2526  CHECK_DO(proc_ctx!= NULL, return STAT_ERROR);
2527  CHECK_DO(str!= NULL, return STAT_ERROR);
2528 
2529  LOG_CTX_SET(proc_ctx->log_ctx);
2530 
2531  /* Get de-multiplexer settings contexts */
2532  live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)proc_ctx;
2533  live555_rtsp_dmux_settings_ctx=
2534  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx;
2535  muxers_settings_dmux_ctx=
2536  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2537 
2538  /* PUT generic de-multiplexer settings */
2539  ret_code= muxers_settings_dmux_ctx_restful_put(muxers_settings_dmux_ctx,
2540  str, LOG_CTX_GET());
2541  if(ret_code!= STAT_SUCCESS)
2542  return ret_code;
2543 
2544 
2545  /* PUT specific de-multiplexer settings */
2546  // Reserved for future use
2547 
2548  /* Finally that we have new settings parsed, reset processor */
2549  live555_rtsp_reset_on_new_settings(proc_ctx, 0, LOG_CTX_GET());
2550 
2551  return STAT_SUCCESS;
2552 }
2553 
2563  live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx)
2564 {
2565  int ret_code;
2566  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx= NULL;
2567  LOG_CTX_INIT(log_ctx);
2568 
2569  /* Check arguments */
2570  CHECK_DO(live555_rtsp_dmux_settings_ctx!= NULL, return STAT_ERROR);
2571 
2572  muxers_settings_dmux_ctx=
2573  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2574 
2575  /* Initialize generic de-multiplexer settings */
2576  ret_code= muxers_settings_dmux_ctx_init(muxers_settings_dmux_ctx);
2577  if(ret_code!= STAT_SUCCESS)
2578  return ret_code;
2579 
2580  /* Initialize specific de-multiplexer settings */
2581  // Reserved for future use
2582 
2583  return STAT_SUCCESS;
2584 }
2585 
2594  live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx)
2595 {
2596  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx= NULL;
2597  LOG_CTX_INIT(log_ctx);
2598 
2599  /* Check arguments */
2600  CHECK_DO(live555_rtsp_dmux_settings_ctx!= NULL, return);
2601 
2602  muxers_settings_dmux_ctx=
2603  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
2604 
2605  /* Release (heap-allocated) generic de-multiplexer settings */
2606  muxers_settings_dmux_ctx_deinit(muxers_settings_dmux_ctx);
2607 
2608  /* Release specific de-multiplexer settings */
2609  // Reserved for future use
2610 }
2611 
2612 static void continueAfterDESCRIBE(RTSPClient *rtspClient, int resultCode,
2613  char *resultString)
2614 {
2615  int end_code= STAT_ERROR;
2616  UsageEnvironment *usageEnvironment= NULL; // Alias
2617  StreamClientState *streamClientState= NULL; // Alias
2618  LOG_CTX_INIT(NULL);
2619 
2620  /* Check arguments */
2621  CHECK_DO(rtspClient!= NULL, goto end);
2622  usageEnvironment= &rtspClient->envir();
2623  streamClientState= &((SimpleRTSPClient*)rtspClient)->streamClientState;
2624  if(resultCode!= 0) {
2625  LOGE("[URL: '%s'] Failed to get a SDP description: \n",
2626  rtspClient->url(), resultString);
2627  goto end;
2628  }
2629 
2630  LOG_CTX_SET(((SimpleRTSPClient*)rtspClient)->m_log_ctx);
2631 
2632  /* Inform we got a SDP description.
2633  * Create a media session object from this SDP description
2634  */
2635  LOGW("Got a SDP description: %s\n", resultString);
2636  streamClientState->session = SimpleClientSession::createNew(
2637  *usageEnvironment, resultString);
2638  if(streamClientState->session== NULL) {
2639  LOGE("[URL: '%s'] Failed to create a MediaSession object from the SDP "
2640  "description: %s\n", rtspClient->url(),
2641  usageEnvironment->getResultMsg());
2642  goto end;
2643  } else if(!streamClientState->session->hasSubsessions()) {
2644  LOGE("[URL: '%s'] This session has no media subsessions (i.e. no 'm=' "
2645  "lines)\n", rtspClient->url());
2646  goto end;
2647  }
2648 
2649  /* Create and set up our data source objects for the session.
2650  * We do this by iterating over the session's 'subsessions', calling
2651  * "MediaSubsession::initiate()", and then sending a RTSP "SETUP" command,
2652  * on each one (Each 'subsession' will have its own data source).
2653  */
2654  streamClientState->iter= new MediaSubsessionIterator(
2655  *streamClientState->session);
2656  setupNextSubsession(rtspClient);
2657 
2658  end_code= STAT_SUCCESS;
2659 end:
2660  if(end_code!= STAT_SUCCESS)
2661  shutdownStream(rtspClient); // unrecoverable error occurred
2662  if(resultString!= NULL)
2663  delete[] resultString;
2664  return;
2665 }
2666 
2670 static void setupNextSubsession(RTSPClient *rtspClient)
2671 {
2672  UsageEnvironment *usageEnvironment= NULL; // Alias
2673  StreamClientState *streamClientState= NULL; // Alias
2674  MediaSubsession *subsession= NULL; // Alias
2675  MediaSession *session= NULL; // Alias
2676  char extra_port_str[8]= {0};
2677  LOG_CTX_INIT(NULL);
2678 
2679  /* Check arguments */
2680  CHECK_DO(rtspClient!= NULL, return);
2681 
2682  usageEnvironment= &rtspClient->envir();
2683  streamClientState= &((SimpleRTSPClient*)rtspClient)->streamClientState;
2684 
2685  streamClientState->subsession= subsession= streamClientState->iter->next();
2686  if(subsession!= NULL) {
2687  unsigned short port;
2688 
2689  /* If we can not initialize sub-session, go to the next one */
2690  if(!subsession->initiate(0)) {
2691  LOGE("[URL: '%s'] Failed to initiate the sub-session '%s/%s': %s\n",
2692  rtspClient->url(), subsession->mediumName(),
2693  subsession->codecName(), usageEnvironment->getResultMsg());
2694  setupNextSubsession(rtspClient);
2695  return;
2696  }
2697 
2698  port= subsession->clientPortNum();
2699  snprintf(extra_port_str, sizeof(extra_port_str), ", %d", port+ 1);
2700  LOGW("[URL: '%s'] Initiated the sub-session '%s/%s' (client port[s] "
2701  "%d%s)\n", rtspClient->url(), subsession->mediumName(),
2702  subsession->codecName(), port,
2703  !subsession->rtcpIsMuxed()? extra_port_str: "");
2704 
2705  /* Continue setting up this sub-session by sending a RTSP "SETUP"
2706  * command.
2707  */
2708  rtspClient->sendSetupCommand(*subsession, continueAfterSETUP, False,
2709  False/*use TCP= false*/);
2710  return;
2711  }
2712 
2713  /* We've finished setting up all of the subsessions. Now, send a RTSP
2714  * "PLAY" command to start the streaming.
2715  */
2716  if((session= streamClientState->session)!= NULL) {
2717  char* absStartTime_str= session->absStartTime();
2718  if(absStartTime_str!= NULL) {
2719  /* Special case: the stream is indexed by 'absolute' time, so
2720  * send an appropriate "PLAY" command.
2721  */
2722  rtspClient->sendPlayCommand(*session, continueAfterPLAY,
2723  absStartTime_str, session->absEndTime());
2724  } else {
2725  streamClientState->duration= session->playEndTime()-
2726  session->playStartTime();
2727  rtspClient->sendPlayCommand(*session, continueAfterPLAY);
2728  }
2729  }
2730  return;
2731 }
2732 
2733 static void continueAfterSETUP(RTSPClient *rtspClient, int resultCode,
2734  char *resultString)
2735 {
2736  unsigned short port;
2737  UsageEnvironment *usageEnvironment= NULL; // Alias
2738  StreamClientState *streamClientState= NULL; // Alias
2739  MediaSubsession *subsession= NULL; // Alias
2740  RTCPInstance *rtcpInstance= NULL; // Alias
2741  char extra_port_str[8]= {0};
2742  LOG_CTX_INIT(NULL);
2743 
2744  /* Check arguments */
2745  CHECK_DO(rtspClient!= NULL, goto end);
2746  usageEnvironment= &rtspClient->envir();
2747  streamClientState= &((SimpleRTSPClient*)rtspClient)->streamClientState;
2748  subsession= streamClientState->subsession;
2749  CHECK_DO(subsession!= NULL, goto end);
2750  if(resultCode!= 0) {
2751  LOGE("[URL: '%s'] Failed to set up the sub-session '%s/%s': %s\n",
2752  rtspClient->url(), subsession->mediumName(),
2753  subsession->codecName(), resultString);
2754  goto end;
2755  }
2756 
2757  port= subsession->clientPortNum();
2758  snprintf(extra_port_str, sizeof(extra_port_str), ", %d", port+ 1);
2759  LOGW("[URL: '%s'] Set up the sub-session '%s/%s' (client port[s] %d%s)\n",
2760  rtspClient->url(), subsession->mediumName(),
2761  subsession->codecName(), port,
2762  !subsession->rtcpIsMuxed()? extra_port_str: "");
2763 
2764  /* Having successfully setup the sub-session, create a data sink for it,
2765  * and call "startPlaying()" on it (This will prepare the data sink to
2766  * receive data; the actual flow of data from the client won't start
2767  * happening until later, after we've sent a RTSP "PLAY" command).
2768  */
2769  subsession->sink= DummySink::createNew(*usageEnvironment, *subsession,
2770  ((SimpleRTSPClient*)rtspClient)->m_fifo_ctx, rtspClient->url(),
2771  LOG_CTX_GET());
2772  CHECK_DO(subsession->sink!= NULL, goto end);
2773  // hack to let sub-session handler functions get the "RTSPClient" from
2774  // the sub-session
2775  subsession->miscPtr= rtspClient;
2776  subsession->sink->startPlaying(*(subsession->readSource()),
2777  subsessionAfterPlaying, subsession);
2778 
2779  /* Set handler call if a RTCP "BYE" arrives for this sub-session */
2780  if((rtcpInstance= subsession->rtcpInstance())!= NULL)
2781  rtcpInstance->setByeHandler(subsessionByeHandler, subsession);
2782 
2783 end:
2784  setupNextSubsession(rtspClient); // Set up the next sub-session, if any.
2785  if(resultString!= NULL)
2786  delete[] resultString;
2787  return;
2788 }
2789 
2790 static void continueAfterPLAY(RTSPClient *rtspClient, int resultCode,
2791  char *resultString)
2792 {
2793  int end_code= STAT_ERROR;
2794  LOG_CTX_INIT(NULL);
2795 
2796  /* Check arguments */
2797  CHECK_DO(rtspClient!= NULL, goto end);
2798  if(resultCode!= 0) {
2799  LOGE("[URL: '%s'] Failed to start playing session: %s\n",
2800  rtspClient->url(), resultString);
2801  goto end;
2802  }
2803 
2804  LOGW("[URL: '%s'] Started playing session...\n", rtspClient->url());
2805 
2806  end_code= STAT_SUCCESS;
2807 end:
2808  if(end_code!= STAT_SUCCESS)
2809  shutdownStream(rtspClient);
2810  if(resultString!= NULL)
2811  delete[] resultString;
2812  return;
2813 }
2814 
2818 static void subsessionAfterPlaying(void *clientData)
2819 {
2820  MediaSubsession *subsession= NULL;
2821  RTSPClient *rtspClient= NULL;
2822  LOG_CTX_INIT(NULL);
2823 
2824  /* Check arguments */
2825  CHECK_DO(clientData!= NULL, return);
2826 
2827  subsession= (MediaSubsession*)clientData;
2828  rtspClient= (RTSPClient*)(subsession->miscPtr);
2829 
2830  /* Begin by closing this subsession's stream */
2831  Medium::close(subsession->sink);
2832  subsession->sink= NULL;
2833 
2834  /* Check whether *all* sub-sessions' streams have now been closed */
2835  MediaSession& session= subsession->parentSession();
2836  MediaSubsessionIterator iter(session);
2837  while((subsession= iter.next())!= NULL) {
2838  if(subsession->sink!= NULL) return; // this sub-session is still active
2839  }
2840 
2841  /* All sub-sessions' streams have now been closed, so shutdown the client */
2842  shutdownStream(rtspClient);
2843 }
2844 
2848 static void subsessionByeHandler(void *clientData)
2849 {
2850  MediaSubsession *subsession= NULL;
2851  RTSPClient *rtspClient= NULL;
2852  LOG_CTX_INIT(NULL);
2853 
2854  /* Check arguments */
2855  CHECK_DO(clientData!= NULL, return);
2856 
2857  subsession= (MediaSubsession*)clientData;
2858  rtspClient= (RTSPClient*)(subsession->miscPtr);
2859 
2860  LOGW("[URL: '%s'] Received RTCP 'BYE' on sub-session '%s/%s'\n",
2861  rtspClient->url(), subsession->mediumName(),
2862  subsession->codecName());
2863 
2864  /* Now act as if the subsession had closed */
2865  subsessionAfterPlaying(subsession);
2866 }
2867 
2871 static void shutdownStream(RTSPClient *rtspClient, int exitCode)
2872 {
2873  StreamClientState *streamClientState= NULL; // Alias
2874  MediaSession *session= NULL;
2875  LOG_CTX_INIT(NULL);
2876 
2877  /* Check arguments */
2878  CHECK_DO(rtspClient!= NULL, return);
2879 
2880  streamClientState= &((SimpleRTSPClient*)rtspClient)->streamClientState;
2881 
2882  /* First, check whether any subsessions have still to be closed */
2883  if((session= streamClientState->session)!= NULL) {
2884  Boolean someSubsessionsWereActive= False;
2885  MediaSubsessionIterator iter(*session);
2886  MediaSubsession* subsession;
2887 
2888  while((subsession= iter.next())!= NULL) {
2889  if(subsession->sink!= NULL) {
2890  RTCPInstance* rtcpInstance;
2891  Medium::close(subsession->sink);
2892  subsession->sink= NULL;
2893 
2894  /* If server sends a RTCP "BYE" while handling "TEARDOWN" */
2895  if((rtcpInstance= subsession->rtcpInstance())!= NULL)
2896  rtcpInstance->setByeHandler(NULL, NULL);
2897  someSubsessionsWereActive= True;
2898  }
2899  }
2900 
2901  /* Send RTSP "TEARDOWN" command to tell server to shutdown the stream.
2902  * Don't bother handling the response to the "TEARDOWN".
2903  */
2904  if(someSubsessionsWereActive)
2905  rtspClient->sendTeardownCommand(*session, NULL);
2906  }
2907 
2908  /* Close the stream.
2909  * Note that this will also cause this stream's "StreamClientState"
2910  * structure to get reclaimed.
2911  */
2912  LOGW("[URL: '%s'] Closing the stream.\n", rtspClient->url());
2913  if(rtspClient->url()!= NULL)
2914  Medium::close(rtspClient);
2915 }
2916 
2917 SimpleRTSPClient* SimpleRTSPClient::createNew(UsageEnvironment& env,
2918  char const* rtspURL, volatile int *ref_flag_exit,
2919  fifo_ctx_t *fifo_ctx, int verbosityLevel,
2920  char const* applicationName,
2921  portNumBits tunnelOverHTTPPortNum, log_ctx_t *log_ctx)
2922 {
2923  return new SimpleRTSPClient(env, rtspURL, ref_flag_exit, fifo_ctx,
2924  verbosityLevel, applicationName, tunnelOverHTTPPortNum, log_ctx);
2925 }
2926 
2927 SimpleRTSPClient::SimpleRTSPClient(UsageEnvironment& env, char const* rtspURL,
2928  volatile int *ref_flag_exit, fifo_ctx_t *fifo_ctx, int verbosityLevel,
2929  char const* applicationName, portNumBits tunnelOverHTTPPortNum,
2930  log_ctx_t *log_ctx):
2931  RTSPClient(env,rtspURL, verbosityLevel, applicationName,
2932  tunnelOverHTTPPortNum, -1),
2933  m_ref_flag_exit(ref_flag_exit),
2934  m_log_ctx(log_ctx),
2935  m_fifo_ctx(fifo_ctx)
2936 {
2937  LOG_CTX_INIT(m_log_ctx);
2938  ASSERT(fifo_ctx!= NULL);
2939 }
2940 
2941 SimpleRTSPClient::~SimpleRTSPClient()
2942 {}
2943 
2944 SimpleClientMediaSubsession::SimpleClientMediaSubsession(MediaSession& parent):
2945  MediaSubsession(parent)
2946 {
2947 }
2948 
2949 Boolean SimpleClientMediaSubsession::createSourceObjects(
2950  int useSpecialRTPoffset)
2951 {
2952  Boolean doNormalMBitRule= False; // default behavior
2953  char mimeType[strlen(mediumName())+ strlen(codecName())+ 2];
2954  snprintf(mimeType, sizeof(mimeType), "%s/%s", mediumName(), codecName());
2955 
2956  fReadSource= fRTPSource= SimpleRTPSource::createNew(env(), fRTPSocket,
2957  fRTPPayloadFormat, fRTPTimestampFrequency, mimeType,
2958  (unsigned)useSpecialRTPoffset, doNormalMBitRule);
2959  return True;
2960 }
2961 
2962 SimpleClientSession* SimpleClientSession::createNew(UsageEnvironment& env,
2963  char const* sdpDescription)
2964 {
2965  SimpleClientSession* newSession = new SimpleClientSession(env);
2966  if (newSession != NULL) {
2967  if (!newSession->initializeWithSDP(sdpDescription)) {
2968  delete newSession;
2969  return NULL;
2970  }
2971  }
2972  return newSession;
2973 }
2974 
2975 SimpleClientSession::SimpleClientSession(UsageEnvironment& env):
2976  MediaSession(env)
2977 {
2978 }
2979 
2980 MediaSubsession* SimpleClientSession::createNewMediaSubsession()
2981 {
2982  return new SimpleClientMediaSubsession(*this);
2983 }
2984 
2985 StreamClientState::StreamClientState(): iter(NULL), session(NULL),
2986  subsession(NULL), streamTimerTask(NULL), duration(0.0)
2987 {}
2988 
2989 StreamClientState::~StreamClientState()
2990 {
2991  delete iter;
2992  if(session!= NULL) {
2993  /* Delete "session" and un-schedule "streamTimerTask" if applicable */
2994  session->envir().taskScheduler().unscheduleDelayedTask(streamTimerTask);
2995  Medium::close(session);
2996  }
2997 }
2998 
2999 DummySink* DummySink::createNew(UsageEnvironment& env,
3000  MediaSubsession& subsession, fifo_ctx_t *fifo_ctx,
3001  char const* streamId, log_ctx_t *log_ctx)
3002 {
3003  return new DummySink(env, subsession, fifo_ctx, streamId, log_ctx);
3004 }
3005 
3006 DummySink::DummySink(UsageEnvironment& env, MediaSubsession& subsession,
3007  fifo_ctx_t *fifo_ctx, char const* streamId, log_ctx_t *log_ctx):
3008  MediaSink(env),
3009  fSubsession(subsession),
3010  m_log_ctx(log_ctx),
3011  m_fifo_ctx(fifo_ctx),
3012  m_proc_frame_ctx(NULL)
3013 {
3014  LOG_CTX_INIT(m_log_ctx);
3015  fStreamId= strDup(streamId);
3016  fReceiveBuffer= new u_int8_t[SINK_BUFFER_SIZE];
3017  ASSERT(m_fifo_ctx!= NULL);
3018 }
3019 
3020 DummySink::~DummySink() {
3021  LOGD_CTX_INIT(m_log_ctx); LOGD(">>%s\n", __FUNCTION__); //comment-me
3022  m_dummySink_io_mutex.lock();
3023  if(fReceiveBuffer!= NULL)
3024  delete[] fReceiveBuffer;
3025  if(fStreamId!= NULL)
3026  delete[] fStreamId;
3027  proc_frame_ctx_release(&m_proc_frame_ctx);
3028  m_dummySink_io_mutex.unlock();
3029  LOGD("<<%s\n", __FUNCTION__); //comment-me
3030 }
3031 
3032 void DummySink::afterGettingFrame(void* clientData, unsigned frameSize,
3033  unsigned numTruncatedBytes, struct timeval presentationTime,
3034  unsigned durationInMicroseconds)
3035 {
3036  DummySink* sink= (DummySink*)clientData;
3037  LOG_CTX_INIT(NULL);
3038 
3039  /* Check arguments */
3040  CHECK_DO(sink!= NULL, return);
3041 
3042  sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime,
3043  durationInMicroseconds);
3044 }
3045 
3046 void DummySink::afterGettingFrame(unsigned frameSize,
3047  unsigned numTruncatedBytes, struct timeval presentationTime,
3048  unsigned /*durationInMicroseconds*/)
3049 {
3050  register size_t accumu_size, new_size, new_size_alig;
3051  int ret_code, m_bit= -1;
3052  RTPSource *rtpsrc= NULL;
3053  uint8_t *data= NULL;
3054  LOG_CTX_INIT(m_log_ctx);
3055  LOGD(">>%s (frameSize: %d; numTruncatedBytes: %d)\n", __FUNCTION__,
3056  (int)frameSize, (int)numTruncatedBytes); //comment-me
3057 
3058  /* Check arguments */
3059  if(frameSize== 0)
3060  goto end;
3061 
3062  /* Get marker bit */
3063  rtpsrc= fSubsession.rtpSource();
3064  if(rtpsrc!= NULL)
3065  m_bit= rtpsrc->curPacketMarkerBit();
3066 
3067  LOGD("%s/%s\n", fSubsession.mediumName(),
3068  fSubsession.codecName()); //comment-me
3069 
3070  /* Allocate de-multiplexer output frame if applicable */
3071  if(m_proc_frame_ctx== NULL) {
3072  m_proc_frame_ctx= proc_frame_ctx_allocate();
3073  CHECK_DO(m_proc_frame_ctx!= NULL, goto end);
3074  }
3075 
3076  /* Complete frame if M bit is set; push frame into output FIFO.
3077  * Otherwise, accumulate frame fragment data.
3078  */
3079  accumu_size= m_proc_frame_ctx->width[0];
3080  new_size= accumu_size+ frameSize;
3081  if(m_bit== 1) {
3082  new_size_alig= EXTEND_SIZE_TO_MULTIPLE(new_size, CTX_S_BASE_ALIGN);
3083  data= (uint8_t*)aligned_alloc(CTX_S_BASE_ALIGN, new_size_alig);
3084  CHECK_DO(data!= NULL, goto end);
3085  if(accumu_size> 0 && m_proc_frame_ctx->data!= NULL)
3086  memcpy(data, m_proc_frame_ctx->data, accumu_size);
3087  memcpy(&data[accumu_size], fReceiveBuffer, frameSize);
3088  if(m_proc_frame_ctx->data!= NULL)
3089  free(m_proc_frame_ctx->data);
3090  m_proc_frame_ctx->data= data;
3091  m_proc_frame_ctx->p_data[0]= data;
3092  data= NULL; // Avoid double referencing
3093  m_proc_frame_ctx->linesize[0]= new_size_alig;
3094  m_proc_frame_ctx->width[0]= new_size;
3095  m_proc_frame_ctx->height[0]= 1; // "1D" data
3096  m_proc_frame_ctx->proc_sample_fmt= PROC_IF_FMT_UNDEF;
3097  m_proc_frame_ctx->pts= 0; //FIXME!!
3098  // We use port as the Id. as is an unique number for each elementary
3099  // stream (unless, for example, we send a transport layer as MPEG2-TS,
3100  // but it is also valid -elementary stream de-multiplexing will occur
3101  // at the MPEG2-TS layer in that case, and the layer provides the
3102  // means for de-multiplexing).
3103  m_proc_frame_ctx->es_id= fSubsession.clientPortNum();
3104 
3105  /* Write frame to input FIFO */
3106  ret_code= fifo_put(m_fifo_ctx, (void**)&m_proc_frame_ctx,
3107  sizeof(void*));
3108  if(ret_code== STAT_ENOMEM) {
3109  /* This FIFO was unblocked, probably we are exiting processing */
3110  proc_frame_ctx_release(&m_proc_frame_ctx);
3111  goto end;
3112  }
3113  ASSERT(ret_code== STAT_SUCCESS && m_proc_frame_ctx== NULL);
3114  } else {
3115  data= (uint8_t*)realloc(m_proc_frame_ctx->data, new_size);
3116  CHECK_DO(data!= NULL, goto end);
3117  memcpy(&data[accumu_size], fReceiveBuffer, frameSize);
3118  m_proc_frame_ctx->data= data;
3119  data= NULL; // Avoid double referencing
3120  m_proc_frame_ctx->width[0]= new_size;
3121  }
3122 
3123 end:
3124  if(data!= NULL)
3125  free(data);
3126  /* Then continue, to request the next frame of data */
3127  continuePlaying();
3128  LOGD("<<%s\n", __FUNCTION__); //comment-me
3129  return;
3130 }
3131 
3132 Boolean DummySink::continuePlaying()
3133 {
3134  if(fSource== NULL)
3135  return False; // sanity check (should not happen)
3136 
3137  /* Request the next frame of data from our input source.
3138  * "afterGettingFrame()" will get called later, when it arrives.
3139  */
3140  fSource->getNextFrame(fReceiveBuffer, SINK_BUFFER_SIZE, afterGettingFrame,
3141  this, onSourceClosure, this);
3142  return True;
3143 }
3144 
3145 void live555_rtsp_reset_on_new_settings(proc_ctx_t *proc_ctx,
3146  int flag_is_muxer, log_ctx_t *log_ctx)
3147 {
3148  int ret_code, flag_io_locked= 0, flag_thr_joined= 0;
3149  void *thread_end_code= NULL;
3150  LOG_CTX_INIT(log_ctx);
3151 
3152  /* Check arguments */
3153  CHECK_DO(proc_ctx!= NULL, return);
3154 
3155  /* If processor interface was not set yet, it means this function is being
3156  * call in processor opening phase, so it must be skipped.
3157  */
3158  if(proc_ctx->proc_if== NULL)
3159  return;
3160 
3161  /* Firstly, stop processing thread:
3162  * - Signal processing to end;
3163  * - Unlock i/o FIFOs;
3164  * - Lock i/o critical section (to make FIFOs unreachable);
3165  * - Join the thread.
3166  * IMPORTANT: *do not* set a jump here (return or goto)
3167  */
3168  proc_ctx->flag_exit= 1;
3169  fifo_set_blocking_mode(proc_ctx->fifo_ctx_array[PROC_IPUT], 0);
3170  fifo_set_blocking_mode(proc_ctx->fifo_ctx_array[PROC_OPUT], 0);
3171  fair_lock(proc_ctx->fair_lock_io_array[PROC_IPUT]);
3172  fair_lock(proc_ctx->fair_lock_io_array[PROC_OPUT]);
3173  flag_io_locked= 1;
3174  //LOGV("Waiting thread to join... "); // comment-me
3175  pthread_join(proc_ctx->proc_thread, &thread_end_code);
3176  if(thread_end_code!= NULL) {
3177  ASSERT(*((int*)thread_end_code)== STAT_SUCCESS);
3178  free(thread_end_code);
3179  thread_end_code= NULL;
3180  }
3181  //LOGV("joined O.K.\n"); // comment-me
3182  flag_thr_joined= 1;
3183 
3184  /* Empty i/o FIFOs */
3185  fifo_empty(proc_ctx->fifo_ctx_array[PROC_IPUT]);
3186  fifo_empty(proc_ctx->fifo_ctx_array[PROC_OPUT]);
3187 
3188  /* Reset processor resources */
3189  if(flag_is_muxer!= 0) {
3190  live555_rtsp_reset_on_new_settings_es_mux(proc_ctx, LOG_CTX_GET());
3191  } else {
3192  live555_rtsp_reset_on_new_settings_es_dmux(proc_ctx, LOG_CTX_GET());
3193  }
3194 
3195 end:
3196  /* Restore FIFOs blocking mode if applicable */
3197  fifo_set_blocking_mode(proc_ctx->fifo_ctx_array[PROC_IPUT], 1);
3198  fifo_set_blocking_mode(proc_ctx->fifo_ctx_array[PROC_OPUT], 1);
3199 
3200  /* Re-launch PROC thread if applicable */
3201  if(flag_thr_joined!= 0) {
3202  proc_ctx->flag_exit= 0;
3203  ret_code= pthread_create(&proc_ctx->proc_thread, NULL,
3204  (void*(*)(void*))proc_ctx->start_routine, proc_ctx);
3205  CHECK_DO(ret_code== 0, goto end);
3206  }
3207 
3208  /* Unlock i/o critical sections if applicable */
3209  if(flag_io_locked!= 0) {
3210  fair_unlock(proc_ctx->fair_lock_io_array[PROC_IPUT]);
3211  fair_unlock(proc_ctx->fair_lock_io_array[PROC_OPUT]);
3212  }
3213  return;
3214 }
3215 
3216 void live555_rtsp_reset_on_new_settings_es_mux(proc_ctx_t *proc_ctx,
3217  log_ctx_t *log_ctx)
3218 {
3219  char *sdp_mimetype;
3220  int i, ret_code, procs_num= 0;
3221  live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx= NULL; // Do not release
3222  volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx=
3223  NULL; // Do not release
3224  volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx=
3225  NULL; // Do not release
3226  cJSON *cjson_es_array= NULL, *cjson_aux= NULL;
3227  char *rest_str= NULL;
3228  LOG_CTX_INIT(log_ctx);
3229 
3230  /* Check arguments */
3231  CHECK_DO(proc_ctx!= NULL, return);
3232 
3233  live555_rtsp_mux_ctx= (live555_rtsp_mux_ctx_t*)proc_ctx;
3234 
3235  /* Get settings structures */
3236  live555_rtsp_mux_settings_ctx=
3237  &live555_rtsp_mux_ctx->live555_rtsp_mux_settings_ctx;
3238  muxers_settings_mux_ctx=
3239  &live555_rtsp_mux_settings_ctx->muxers_settings_mux_ctx;
3240 
3241  /* Get ES-processors array REST (will need to register ES's again) */
3242  ret_code= live555_rtsp_mux_rest_get_es_array(
3243  ((proc_muxer_mux_ctx_t*)live555_rtsp_mux_ctx)->procs_ctx_es_muxers,
3244  &cjson_es_array, LOG_CTX_GET());
3245  CHECK_DO(ret_code== STAT_SUCCESS && cjson_es_array!= NULL, goto end);
3246 
3247  /* Release RTSP multiplexer at the exception of its settings context
3248  * structure.
3249  */
3250  live555_rtsp_mux_deinit_except_settings(live555_rtsp_mux_ctx,
3251  LOG_CTX_GET());
3252 
3253  /* Re-initialize the specific Live555 multiplexer resources */
3254  ret_code= live555_rtsp_mux_init_given_settings(live555_rtsp_mux_ctx,
3255  (const muxers_settings_mux_ctx_t*)muxers_settings_mux_ctx,
3256  LOG_CTX_GET());
3257  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
3258 
3259  /* Register ES's again */
3260  procs_num= cJSON_GetArraySize(cjson_es_array);
3261  for(i= 0; i< procs_num; i++) {
3262  char settings_str[128]= {0};
3263  cJSON *cjson_proc= cJSON_GetArrayItem(cjson_es_array, i);
3264  CHECK_DO(cjson_proc!= NULL, continue);
3265 
3266  cjson_aux= cJSON_GetObjectItem(cjson_proc, "sdp_mimetype");
3267  CHECK_DO(cjson_aux!= NULL, continue);
3268  sdp_mimetype= cjson_aux->valuestring;
3269 
3270  /* Register ES */
3271  if(rest_str!= NULL) {
3272  free(rest_str);
3273  rest_str= NULL;
3274  }
3275  snprintf(settings_str, sizeof(settings_str), "sdp_mimetype=%s",
3276  sdp_mimetype);
3277  ret_code= procs_opt(
3278  ((proc_muxer_mux_ctx_t*)live555_rtsp_mux_ctx)->
3279  procs_ctx_es_muxers, "PROCS_POST",
3280  "live555_rtsp_es_mux", settings_str, &rest_str,
3281  live555_rtsp_mux_ctx->usageEnvironment,
3282  live555_rtsp_mux_ctx->serverMediaSession);
3283  CHECK_DO(ret_code== STAT_SUCCESS && rest_str!= NULL, continue);
3284  }
3285 
3286 end:
3287  if(cjson_es_array!= NULL)
3288  cJSON_Delete(cjson_es_array);
3289  if(rest_str!= NULL)
3290  free(rest_str);
3291  return;
3292 }
3293 
3294 void live555_rtsp_reset_on_new_settings_es_dmux(proc_ctx_t *proc_ctx,
3295  log_ctx_t *log_ctx)
3296 {
3297  int ret_code;
3298  live555_rtsp_dmux_ctx_t *live555_rtsp_dmux_ctx= NULL; // Do not release
3299  volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx=
3300  NULL; // Do not release
3301  volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx=
3302  NULL; // Do not release
3303  LOG_CTX_INIT(log_ctx);
3304 
3305  /* Check arguments */
3306  CHECK_DO(proc_ctx!= NULL, return);
3307 
3308  live555_rtsp_dmux_ctx= (live555_rtsp_dmux_ctx_t*)proc_ctx;
3309 
3310  /* Get settings structures */
3311  live555_rtsp_dmux_settings_ctx=
3312  &live555_rtsp_dmux_ctx->live555_rtsp_dmux_settings_ctx;
3313  muxers_settings_dmux_ctx=
3314  &live555_rtsp_dmux_settings_ctx->muxers_settings_dmux_ctx;
3315 
3316  /* Release RTSP de-multiplexer at the exception of its settings context
3317  * structure.
3318  */
3319  live555_rtsp_dmux_deinit_except_settings(live555_rtsp_dmux_ctx,
3320  LOG_CTX_GET());
3321 
3322  /* Re-initialize the specific Live555 multiplexer resources */
3323  ret_code= live555_rtsp_dmux_init_given_settings(live555_rtsp_dmux_ctx,
3324  (const muxers_settings_dmux_ctx_t*)muxers_settings_dmux_ctx,
3325  LOG_CTX_GET());
3326  ASSERT(ret_code== STAT_SUCCESS);
3327 
3328  return;
3329 }
static int live555_rtsp_dmux_rest_get(proc_ctx_t *proc_ctx, const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
static int live555_rtsp_dmux_rest_put(proc_ctx_t *proc_ctx, const char *str)
void fifo_close(fifo_ctx_t **ref_fifo_ctx)
Definition: fifo.c:327
struct live555_rtsp_es_mux_settings_ctx_s live555_rtsp_es_mux_settings_ctx_t
int fifo_get(fifo_ctx_t *fifo_ctx, void **ref_elem, size_t *ref_elem_size)
Definition: fifo.c:366
static void shutdownStream(RTSPClient *rtspClient, int exitCode=1)
#define CJSON_PRINT(CJSON_PTR)
Definition: proc.h:70
static int live555_rtsp_dmux_settings_ctx_init(volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx)
int muxers_settings_mux_ctx_init(volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx)
#define TAG_IS(TAG)
struct live555_rtsp_mux_settings_ctx_s live555_rtsp_mux_settings_ctx_t
UsageEnvironment * usageEnvironment
size_t width[PROC_FRAME_NUM_DATA_POINTERS]
Definition: proc_if.h:113
struct muxers_settings_dmux_ctx_s muxers_settings_dmux_ctx
int muxers_settings_dmux_ctx_restful_put(volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx, const char *str, log_ctx_t *log_ctx)
TaskScheduler * taskScheduler
static int live555_rtsp_mux_settings_ctx_init(volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx, log_ctx_t *log_ctx)
void proc_frame_ctx_release(proc_frame_ctx_t **ref_proc_frame_ctx)
Definition: proc_if.c:125
#define EXTEND_SIZE_TO_MULTIPLE(SIZE, MULTIPLE)
Definition: mem_utils.h:52
Multiplexers and de-multiplexers generic settings.
ssize_t fifo_get_buffer_level(fifo_ctx_t *fifo_ctx)
Definition: fifo.c:385
#define CTX_S_BASE_ALIGN
Definition: mem_utils.h:47
struct live555_rtsp_mux_ctx_s live555_rtsp_mux_ctx_t
struct muxers_settings_mux_ctx_s muxers_settings_mux_ctx
UsageEnvironment * usageEnvironment
void fifo_set_blocking_mode(fifo_ctx_t *fifo_ctx, int do_block)
Definition: fifo.c:332
Generic processor module context (see type proc_ctx_t) extension for multiplexers and de-multiplexers...
int procs_opt(procs_ctx_t *procs_ctx, const char *tag,...)
Definition: procs.c:474
static proc_ctx_t * live555_rtsp_dmux_open(const proc_if_t *proc_if, const char *settings_str, log_ctx_t *log_ctx, va_list arg)
pthread_t proc_thread
Definition: proc.h:173
int fifo_put(fifo_ctx_t *fifo_ctx, void **ref_elem, size_t elem_size)
Definition: fifo.c:361
procs_ctx_t * procs_ctx_es_muxers
Definition: proc_muxer.h:49
int procs_module_opt(const char *tag,...)
Definition: procs.c:294
static void subsessionByeHandler(void *clientData)
void fifo_empty(fifo_ctx_t *fifo_ctx)
Definition: fifo.c:456
int fifo_show(fifo_ctx_t *fifo_ctx, void **ref_elem, size_t *ref_elem_size)
Definition: fifo.c:379
static int live555_rtsp_es_mux_rest_get(proc_ctx_t *proc_ctx, const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
volatile EventTriggerId m_eventTriggerId
void proc_muxer_mux_ctx_deinit(proc_muxer_mux_ctx_t *proc_muxer_mux_ctx, log_ctx_t *log_ctx)
Definition: proc_muxer.c:70
const proc_if_t proc_if_live555_rtsp_mux
pthread_mutex_t api_mutex
Definition: proc.h:99
const void *(* start_routine)(void *)
Definition: proc.h:181
static DummySink * createNew(UsageEnvironment &env, MediaSubsession &subsession, fifo_ctx_t *fifo_ctx, char const *streamId=NULL, log_ctx_t *log_ctx=NULL)
#define CHECK_DO(COND, ACTION)
Definition: check_utils.h:57
Character string response.
Definition: proc_if.h:158
volatile int flag_exit
Definition: proc.h:169
int procs_send_frame(procs_ctx_t *procs_ctx, int proc_id, const proc_frame_ctx_t *proc_frame_ctx)
Definition: procs.c:504
fifo_ctx_t * fifo_open(size_t slots_max, size_t chunk_size_max, uint32_t flags, const fifo_elem_alloc_fxn_t *fifo_elem_alloc_fxn)
Definition: fifo.c:195
int muxers_settings_dmux_ctx_init(volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx)
proc_frame_ctx_t * proc_frame_ctx_allocate()
Definition: proc_if.c:47
enum proc_if_rest_fmt_enum proc_if_rest_fmt_t
const proc_if_t * proc_if
Definition: proc.h:89
fifo_ctx_t * fifo_ctx_array[PROC_IO_NUM]
Definition: proc.h:107
SimpleRTSPClient * simpleRTSPClient
volatile struct live555_rtsp_mux_settings_ctx_s live555_rtsp_mux_settings_ctx
static int live555_rtsp_es_mux_process_frame(proc_ctx_t *proc_ctx, fifo_ctx_t *iput_fifo_ctx, fifo_ctx_t *oput_fifo_ctx)
TaskScheduler * taskScheduler
cJSON structure response
Definition: proc_if.h:159
static int live555_rtsp_mux_opt(proc_ctx_t *proc_ctx, const char *tag, va_list arg)
static int live555_rtsp_mux_rest_get(proc_ctx_t *proc_ctx, const proc_if_rest_fmt_t rest_fmt, void **ref_reponse)
Live555 based RTSP multiplexer and de-multiplexer wrappers.
ServerMediaSession * serverMediaSession
static void live555_rtsp_dmux_close(proc_ctx_t **ref_proc_ctx)
static int live555_rtsp_es_mux_rest_put(proc_ctx_t *proc_ctx, const char *str)
static void setupNextSubsession(RTSPClient *rtspClient)
fifo_ctx_t * m_fifo_ctx
volatile struct live555_rtsp_dmux_settings_ctx_s live555_rtsp_dmux_settings_ctx
const proc_if_t proc_if_live555_rtsp_dmux
static int live555_rtsp_mux_rest_put(proc_ctx_t *proc_ctx, const char *str)
Undefined format.
Definition: proc_if.h:54
static void subsessionAfterPlaying(void *clientData)
#define FIFO_O_NONBLOCK
Definition: fifo.h:50
proc_frame_ctx_t * proc_frame_ctx_dup(const proc_frame_ctx_t *proc_frame_ctx_arg)
Definition: proc_if.c:52
int muxers_settings_mux_ctx_restful_get(volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx, cJSON **ref_cjson_rest, log_ctx_t *log_ctx)
#define ASSERT(COND)
Definition: check_utils.h:51
TaskScheduler * taskScheduler
static void live555_rtsp_mux_settings_ctx_deinit(volatile live555_rtsp_mux_settings_ctx_t *live555_rtsp_mux_settings_ctx, log_ctx_t *log_ctx)
volatile struct live555_rtsp_es_mux_settings_ctx_s live555_rtsp_es_mux_settings_ctx
void procs_close(procs_ctx_t **ref_procs_ctx)
Definition: procs.c:417
struct proc_muxer_mux_ctx_s proc_muxer_mux_ctx
static void live555_rtsp_mux_close(proc_ctx_t **ref_proc_ctx)
Definition: log.c:102
static void live555_rtsp_mux_deinit_except_settings(live555_rtsp_mux_ctx_t *live555_rtsp_mux_ctx, log_ctx_t *log_ctx)
static void live555_rtsp_dmux_settings_ctx_deinit(volatile live555_rtsp_dmux_settings_ctx_t *live555_rtsp_dmux_settings_ctx, log_ctx_t *log_ctx)
static int live555_rtsp_dmux_process_frame(proc_ctx_t *proc_ctx, fifo_ctx_t *iput_fifo_ctx, fifo_ctx_t *oput_fifo_ctx)
const uint8_t * p_data[PROC_FRAME_NUM_DATA_POINTERS]
Definition: proc_if.h:94
static proc_ctx_t * live555_rtsp_mux_open(const proc_if_t *proc_if, const char *settings_str, log_ctx_t *log_ctx, va_list arg)
fair_lock_t * fair_lock_io_array[PROC_IO_NUM]
Definition: proc.h:111
int proc_muxer_mux_ctx_init(proc_muxer_mux_ctx_t *proc_muxer_mux_ctx, log_ctx_t *log_ctx)
Definition: proc_muxer.c:50
void muxers_settings_mux_ctx_deinit(volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx)
SimpleMediaSubsession * simpleMediaSubsession
log_ctx_t * log_ctx
Definition: proc.h:103
void muxers_settings_dmux_ctx_deinit(volatile muxers_settings_dmux_ctx_t *muxers_settings_dmux_ctx)
static int live555_rtsp_mux_process_frame(proc_ctx_t *proc_ctx, fifo_ctx_t *iput_fifo_ctx, fifo_ctx_t *oput_fifo_ctx)
static void live555_rtsp_es_mux_close(proc_ctx_t **ref_proc_ctx)
struct live555_rtsp_dmux_settings_ctx_s live555_rtsp_dmux_settings_ctx_t
int muxers_settings_mux_ctx_restful_put(volatile muxers_settings_mux_ctx_t *muxers_settings_mux_ctx, const char *str, log_ctx_t *log_ctx)