From 90db5a903269064e731b8adb0af0297f88243dac Mon Sep 17 00:00:00 2001 From: Seven Du Date: Wed, 16 Dec 2020 22:55:12 +0800 Subject: [PATCH] [mod_loopback] Add video support to null endpoint * [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 | 8 +- src/mod/endpoints/mod_loopback/mod_loopback.c | 141 +++++++++++++++++- tests/unit/switch_ivr_originate.c | 22 +++ 3 files changed, 166 insertions(+), 5 deletions(-) diff --git a/src/include/test/switch_test.h b/src/include/test/switch_test.h index 3413884145..936c709bb1 100644 --- a/src/include/test/switch_test.h +++ b/src/include/test/switch_test.h @@ -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 */ diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index 6fa0d4fbd4..456936562a 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -25,6 +25,7 @@ * * Anthony Minessale II * Emmanuel Schmidbauer + * Seven Du * * * 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) diff --git a/tests/unit/switch_ivr_originate.c b/tests/unit/switch_ivr_originate.c index b6ffe7cf51..4cf9695275 100644 --- a/tests/unit/switch_ivr_originate.c +++ b/tests/unit/switch_ivr_originate.c @@ -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;