]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[mod_loopback] Add video support to null endpoint
authorSeven Du <seven@signalwire.com>
Wed, 16 Dec 2020 14:55:12 +0000 (22:55 +0800)
committerAndrey Volk <andywolk@gmail.com>
Sat, 23 Oct 2021 19:00:38 +0000 (22:00 +0300)
* [mod_loopback] add video support to null channel

* [core test] add video session support

* [core] add video channel test case

src/include/test/switch_test.h
src/mod/endpoints/mod_loopback/mod_loopback.c
tests/unit/switch_ivr_originate.c

index 3413884145d5029c5929a5dab570a725e3ebd194..936c709bb136378332ecfbe02863a13a9275e73b 100644 (file)
@@ -484,9 +484,10 @@ static switch_status_t fst_init_core_and_modload(const char *confdir, const char
  *
  * @param name the name of this test
  * @param rate the rate of the channel
+ * @param video_codec the rate of the channel
  */
 
-#define FST_SESSION_BEGIN_RATE(name, rate) \
+#define FST_SESSION_BEGIN_RATE_VIDEO(name, rate, video_codec) \
        FCT_TEST_BGN(name) \
        { \
                if (fst_core) { \
@@ -513,7 +514,7 @@ static switch_status_t fst_init_core_and_modload(const char *confdir, const char
                fst_requires(switch_event_create_plain(&fst_originate_vars, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS); \
                switch_event_add_header_string(fst_originate_vars, SWITCH_STACK_BOTTOM, "origination_caller_id_number", "+15551112222"); \
                switch_event_add_header(fst_originate_vars, SWITCH_STACK_BOTTOM, "rate", "%d", rate); \
-               if (switch_ivr_originate(NULL, &fst_session, &fst_cause, "null/+15553334444", 2, NULL, NULL, NULL, NULL, fst_originate_vars, SOF_NONE, NULL, NULL) == SWITCH_STATUS_SUCCESS && fst_session) { \
+               if (switch_ivr_originate(NULL, &fst_session, &fst_cause, "{null_video_codec=" video_codec "}null/+15553334444", 2, NULL, NULL, NULL, NULL, fst_originate_vars, SOF_NONE, NULL, NULL) == SWITCH_STATUS_SUCCESS && fst_session) { \
                        switch_memory_pool_t *fst_session_pool = switch_core_session_get_pool(fst_session); \
                        switch_channel_t *fst_channel = switch_core_session_get_channel(fst_session); \
                        switch_channel_set_state(fst_channel, CS_SOFT_EXECUTE); \
@@ -525,10 +526,11 @@ static switch_status_t fst_init_core_and_modload(const char *confdir, const char
 
 /**
  * Define a session test in a test suite.  This can be used to test IVR functions.
- * See FST_SESSION_BEGIN_RATE
+ * See FST_SESSION_BEGIN_RATE_VIDEO
  */
 
 #define FST_SESSION_BEGIN(name) FST_SESSION_BEGIN_RATE(name, 8000)
+#define FST_SESSION_BEGIN_RATE(name, rate) FST_SESSION_BEGIN_RATE_VIDEO(name, rate, "")
 
 /* BODY OF TEST CASE HERE */
 
index 6fa0d4fbd48593c3c178ecf2a05230adad9a084d..456936562a23e0e2e0a525c92c09456cc52a766c 100644 (file)
@@ -25,6 +25,7 @@
  *
  * Anthony Minessale II <anthm@freeswitch.org>
  * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
+ * Seven Du <dujinfang@gmail.com>
  *
  *
  * mod_loopback.c -- Loopback Endpoint Module
@@ -1302,6 +1303,9 @@ struct null_private_object {
        switch_codec_t read_codec;
        switch_codec_t write_codec;
        switch_timer_t timer;
+       switch_codec_t video_read_codec;
+       switch_codec_t video_write_codec;
+       switch_timer_t video_timer;
        switch_caller_profile_t *caller_profile;
        switch_frame_t read_frame;
        int16_t *null_buf;
@@ -1312,6 +1316,12 @@ struct null_private_object {
        int enable_auto_answer;
        /* auto_answer_delay (0 ms by default) */
        int auto_answer_delay;
+       char *video_codec_name;
+       switch_frame_t video_read_frame;
+       uint8_t video_data[SWITCH_RECOMMENDED_BUFFER_SIZE];
+       switch_image_t *img;
+       switch_media_handle_t *media_handle;
+       switch_core_media_params_t mparams;
 };
 
 typedef struct null_private_object null_private_t;
@@ -1324,9 +1334,31 @@ static switch_call_cause_t null_channel_outgoing_channel(switch_core_session_t *
                                                                                                        switch_call_cause_t *cancel_cause);
 static switch_status_t null_channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
 static switch_status_t null_channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t null_channel_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t null_channel_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
 static switch_status_t null_channel_kill_channel(switch_core_session_t *session, int sig);
 
-
+static void set_mparams(null_private_t *tech_pvt)
+{
+       switch_core_media_params_t *mparams = &tech_pvt->mparams;
+
+       mparams->inbound_codec_string = "L16";
+       mparams->outbound_codec_string = "L16";
+       mparams->timer_name = "soft";
+       mparams->extsipip = "10.0.0.1";
+       mparams->extrtpip = "10.0.0.2";
+       mparams->local_network = "127.0.0.1";
+       mparams->sipip = "127.0.0.1";
+       mparams->rtpip = "127.0.0.1";
+       mparams->jb_msec = "60";
+       mparams->rtcp_audio_interval_msec = "5000";
+       mparams->rtcp_video_interval_msec = "5000";
+       mparams->sdp_username = "FreeSWITCH";
+       mparams->cng_pt = 13;
+       mparams->rtp_timeout_sec = 300;
+       mparams->rtp_hold_timeout_sec = 3600;
+       mparams->external_video_source = 1;
+}
 
 static switch_status_t null_tech_init(null_private_t *tech_pvt, switch_core_session_t *session)
 {
@@ -1364,6 +1396,43 @@ static switch_status_t null_tech_init(null_private_t *tech_pvt, switch_core_sess
        switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
        switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
 
+       if (!zstr(tech_pvt->video_codec_name)) {
+               status = switch_core_codec_init(&tech_pvt->video_read_codec,
+                                               tech_pvt->video_codec_name,
+                                               NULL,
+                                               NULL,
+                                               90000, 0, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session));
+
+               if (status != SWITCH_STATUS_SUCCESS || !tech_pvt->video_read_codec.implementation || !switch_core_codec_ready(&tech_pvt->video_read_codec)) {
+                       goto end;
+               }
+
+               status = switch_core_codec_init(&tech_pvt->video_write_codec,
+                                               tech_pvt->video_codec_name,
+                                               NULL,
+                                               NULL,
+                                               90000, 0, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session));
+
+
+               if (status != SWITCH_STATUS_SUCCESS) {
+                       switch_core_codec_destroy(&tech_pvt->video_read_codec);
+                       goto end;
+               }
+
+               switch_channel_set_flag(switch_core_session_get_channel(session), CF_VIDEO);
+               switch_core_session_set_video_read_codec(session, &tech_pvt->read_codec);
+               switch_core_session_set_video_write_codec(session, &tech_pvt->write_codec);
+               switch_core_timer_init(&tech_pvt->video_timer, "soft", 100, 900, switch_core_session_get_pool(session));
+               set_mparams(tech_pvt);
+               switch_media_handle_create(&tech_pvt->media_handle, session, &tech_pvt->mparams);
+               // switch_core_media_prepare_codecs(session, SWITCH_TRUE);
+               // switch_core_media_check_video_codecs(session);
+               // switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0);
+               // switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 0);
+               // switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, "127.0.0.1", 2000, NULL, 0);
+               // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", mparams.local_sdp_str);
+       }
+
        read_impl = tech_pvt->read_codec.implementation;
 
        switch_core_timer_init(&tech_pvt->timer, "soft",
@@ -1419,8 +1488,20 @@ static switch_status_t null_channel_on_destroy(switch_core_session_t *session)
                if (switch_core_codec_ready(&tech_pvt->write_codec)) {
                        switch_core_codec_destroy(&tech_pvt->write_codec);
                }
+
+               if (switch_core_codec_ready(&tech_pvt->video_read_codec)) {
+                       switch_core_codec_destroy(&tech_pvt->video_read_codec);
+               }
+
+               if (switch_core_codec_ready(&tech_pvt->video_write_codec)) {
+                       switch_core_codec_destroy(&tech_pvt->video_write_codec);
+               }
+
+               switch_img_free(&tech_pvt->img);
        }
 
+       switch_media_handle_destroy(session);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1558,6 +1639,50 @@ static switch_status_t null_channel_write_frame(switch_core_session_t *session,
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t null_channel_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+       switch_channel_t *channel = NULL;
+       null_private_t *tech_pvt = NULL;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       channel = switch_core_session_get_channel(session);
+       switch_assert(channel != NULL);
+
+       tech_pvt = switch_core_session_get_private(session);
+       switch_assert(tech_pvt != NULL);
+
+       *frame = NULL;
+
+       if (!switch_channel_ready(channel)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_core_timer_next(&tech_pvt->video_timer);
+
+       tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec;
+       tech_pvt->video_read_frame.datalen = 0;
+       tech_pvt->video_read_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
+       tech_pvt->video_read_frame.samples = 0;
+       tech_pvt->video_read_frame.data = tech_pvt->video_data;
+       if (!tech_pvt->img) {
+               tech_pvt->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, 1280, 720, 0);
+       }
+       tech_pvt->video_read_frame.img = tech_pvt->img;
+       *frame = &tech_pvt->video_read_frame;
+
+       if (*frame) {
+               status = SWITCH_STATUS_SUCCESS;
+       } else {
+               status = SWITCH_STATUS_FALSE;
+       }
+
+       return status;
+}
+static switch_status_t null_channel_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t null_channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
 {
        switch_channel_t *channel;
@@ -1638,6 +1763,7 @@ static switch_call_cause_t null_channel_outgoing_channel(switch_core_session_t *
 
                if ((tech_pvt = (null_private_t *) switch_core_session_alloc(*new_session, sizeof(null_private_t))) != 0) {
                        const char *rate_ = switch_event_get_header(var_event, "rate");
+                       const char *video_codec = switch_event_get_header(var_event, "null_video_codec");
                        int rate = 0;
 
                        if (rate_) {
@@ -1649,9 +1775,12 @@ static switch_call_cause_t null_channel_outgoing_channel(switch_core_session_t *
                        }
 
                        tech_pvt->rate = rate;
-
                        tech_pvt->pre_answer = switch_true(pre_answer);
 
+                       if (video_codec) {
+                               tech_pvt->video_codec_name = switch_core_session_strdup(*new_session, video_codec);
+                       }
+
                        if (!enable_auto_answer) {
                                /* if not set - enabled by default */
                                tech_pvt->enable_auto_answer = SWITCH_TRUE;
@@ -1733,7 +1862,15 @@ static switch_io_routines_t null_channel_io_routines = {
        /*.write_frame */ null_channel_write_frame,
        /*.kill_channel */ null_channel_kill_channel,
        /*.send_dtmf */ null_channel_send_dtmf,
-       /*.receive_message */ null_channel_receive_message
+       /*.receive_message */ null_channel_receive_message,
+       /*.receive_event */ NULL,
+       /*.state_change */ NULL,
+       /*.read_video_frame */ null_channel_read_video_frame,
+       /*.write_video_frame */ null_channel_write_video_frame,
+       /*.read_text_frame */ NULL,
+       /*.write_text_frame */ NULL,
+       /*.state_run*/ NULL,
+       /*.get_jb*/ NULL
 };
 
 switch_status_t load_loopback_configuration(switch_bool_t reload)
index b6ffe7cf513ecea202ace2602a8b26ba1eb83156..4cf969527523bc8446a38c8f2a31b8ca47801542 100644 (file)
@@ -763,6 +763,28 @@ FST_CORE_BEGIN("./conf")
                }
                FST_TEST_END()
 
+               FST_TEST_BEGIN(originate_test_video)
+               {
+                       switch_core_session_t *session = NULL;
+                       switch_channel_t *channel = NULL;
+                       switch_status_t status;
+                       switch_call_cause_t cause;
+
+                       status = switch_ivr_originate(NULL, &session, &cause, "{null_video_codec=VP8}null/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+                       fst_requires(session);
+                       fst_check(status == SWITCH_STATUS_SUCCESS);
+
+                       channel = switch_core_session_get_channel(session);
+                       fst_requires(channel);
+                       fst_check(switch_channel_test_flag(channel, CF_VIDEO));
+                       switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                       fst_check(!switch_channel_ready(channel));
+
+                       switch_core_session_rwunlock(session);
+                       switch_sleep(1000000);
+               }
+               FST_TEST_END()
+
                FST_TEST_BEGIN(enterprise_originate_test_group_confirm_two_handles)
                {
                        switch_core_session_t *session = NULL;