modest core framework for video stuff

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4977 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale
2007-04-19 21:40:50 +00:00
parent bdaab6dbbd
commit a1725ad334
18 changed files with 1128 additions and 77 deletions
+2
View File
@@ -0,0 +1,2 @@
BASE=../../../..
include /usr/src/freeswitch.trunk/build/modmake.rules
+154
View File
@@ -0,0 +1,154 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* mod_h26x.c -- H26X Signed Linear Codec
*
*/
#include <switch.h>
static const char modname[] = "mod_h26x";
static switch_status_t switch_h26x_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
int encoding, decoding;
encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
if (!(encoding || decoding)) {
return SWITCH_STATUS_FALSE;
} else {
return SWITCH_STATUS_SUCCESS;
}
}
static switch_status_t switch_h26x_encode(switch_codec_t *codec,
switch_codec_t *other_codec,
void *decoded_data,
uint32_t decoded_data_len,
uint32_t decoded_rate, void *encoded_data, uint32_t * encoded_data_len, uint32_t * encoded_rate,
unsigned int *flag)
{
return SWITCH_STATUS_FALSE;
}
static switch_status_t switch_h26x_decode(switch_codec_t *codec,
switch_codec_t *other_codec,
void *encoded_data,
uint32_t encoded_data_len,
uint32_t encoded_rate, void *decoded_data, uint32_t * decoded_data_len, uint32_t * decoded_rate,
unsigned int *flag)
{
return SWITCH_STATUS_FALSE;
}
static switch_status_t switch_h26x_destroy(switch_codec_t *codec)
{
return SWITCH_STATUS_SUCCESS;
}
static const switch_codec_implementation_t h264_90000_implementation = {
/*.codec_type */ SWITCH_CODEC_TYPE_VIDEO,
/*.ianacode */ 99,
/*.iananame */ "H264",
/*.fmtp */ NULL,
/*.samples_per_second = */ 90000,
/*.bits_per_second = */ 0,
/*.microseconds_per_frame = */ 0,
/*.samples_per_frame = */ 0,
/*.bytes_per_frame = */ 0,
/*.encoded_bytes_per_frame = */ 0,
/*.number_of_channels = */ 1,
/*.pref_frames_per_packet = */ 1,
/*.max_frames_per_packet = */ 1,
/*.init = */ switch_h26x_init,
/*.encode = */ switch_h26x_encode,
/*.decode = */ switch_h26x_decode,
/*.destroy = */ switch_h26x_destroy
/*.next = */
};
static const switch_codec_implementation_t h263_90000_implementation = {
/*.codec_type */ SWITCH_CODEC_TYPE_VIDEO,
/*.ianacode */ 34,
/*.iananame */ "H263",
/*.fmtp */ NULL,
/*.samples_per_second = */ 90000,
/*.bits_per_second = */ 0,
/*.microseconds_per_frame = */ 0,
/*.samples_per_frame = */ 0,
/*.bytes_per_frame = */ 0,
/*.encoded_bytes_per_frame = */ 0,
/*.number_of_channels = */ 1,
/*.pref_frames_per_packet = */ 1,
/*.max_frames_per_packet = */ 1,
/*.init = */ switch_h26x_init,
/*.encode = */ switch_h26x_encode,
/*.decode = */ switch_h26x_decode,
/*.destroy = */ switch_h26x_destroy,
/*.next = */&h264_90000_implementation
};
static const switch_codec_interface_t h26x_codec_interface = {
/*.interface_name */ "h26x video (passthru)",
/*.implementations */ &h263_90000_implementation
};
static switch_loadable_module_interface_t h26x_module_interface = {
/*.module_name */ modname,
/*.endpoint_interface */ NULL,
/*.timer_interface */ NULL,
/*.dialplan_interface */ NULL,
/*.codec_interface */ &h26x_codec_interface,
/*.application_interface */ NULL,
/*.api_interface */ NULL,
};
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
{
/* connect my internal structure to the blank pointer passed to me */
*module_interface = &h26x_module_interface;
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/
+211
View File
@@ -0,0 +1,211 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="mod_h26x"
ProjectGUID="{5844AFE1-AA3E-4BDB-A9EF-119AEF19DF88}"
RootNamespace="mod_h26x"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\..\libs\libresample\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\libresample\win&quot;;..\..\..\..\w32\vsnet\$(OutDir)"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/mod_h26x.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\..\libs\libresample\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\libresample\win&quot;;..\..\..\..\w32\vsnet\$(OutDir)"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/mod_h26x.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\mod_h26x.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+118 -26
View File
@@ -58,6 +58,8 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
switch_memory_pool_t **pool);
static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id);
static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id);
static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id);
static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id);
static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig);
@@ -321,12 +323,117 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
}
static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id)
{
private_object_t *tech_pvt = NULL;
switch_channel_t *channel = NULL;
int payload = 0;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
tech_pvt = (private_object_t *) switch_core_session_get_private(session);
assert(tech_pvt != NULL);
if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
return SWITCH_STATUS_FALSE;
}
while (!(tech_pvt->video_read_codec.implementation && switch_rtp_ready(tech_pvt->video_rtp_session))) {
if (switch_channel_ready(channel)) {
switch_yield(10000);
} else {
return SWITCH_STATUS_GENERR;
}
}
tech_pvt->video_read_frame.datalen = 0;
if (switch_test_flag(tech_pvt, TFLAG_IO)) {
switch_status_t status;
if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
return SWITCH_STATUS_GENERR;
}
assert(tech_pvt->rtp_session != NULL);
tech_pvt->video_read_frame.datalen = 0;
while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->video_read_frame.datalen == 0) {
tech_pvt->video_read_frame.flags = SFF_NONE;
status = switch_rtp_zerocopy_read_frame(tech_pvt->video_rtp_session, &tech_pvt->video_read_frame);
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
return SWITCH_STATUS_FALSE;
}
payload = tech_pvt->video_read_frame.payload;
if (tech_pvt->video_read_frame.datalen > 0) {
break;
}
}
}
if (tech_pvt->video_read_frame.datalen == 0) {
*frame = NULL;
return SWITCH_STATUS_GENERR;
}
*frame = &tech_pvt->video_read_frame;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id)
{
private_object_t *tech_pvt;
switch_channel_t *channel = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
tech_pvt = (private_object_t *) switch_core_session_get_private(session);
assert(tech_pvt != NULL);
while (!(tech_pvt->video_read_codec.implementation && switch_rtp_ready(tech_pvt->video_rtp_session))) {
if (switch_channel_ready(channel)) {
switch_yield(10000);
} else {
return SWITCH_STATUS_GENERR;
}
}
if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
return SWITCH_STATUS_FALSE;
}
if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
return SWITCH_STATUS_GENERR;
}
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
return SWITCH_STATUS_SUCCESS;
}
if (!switch_test_flag(frame, SFF_CNG)) {
switch_rtp_write_frame(tech_pvt->video_rtp_session, frame, 0);
}
return status;
}
static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id)
{
private_object_t *tech_pvt = NULL;
switch_channel_t *channel = NULL;
int payload = 0;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
@@ -349,16 +456,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
tech_pvt->read_frame.datalen = 0;
switch_set_flag_locked(tech_pvt, TFLAG_READING);
#if 0
if (tech_pvt->last_read) {
elapsed = (unsigned int) ((switch_time_now() - tech_pvt->last_read) / 1000);
if (elapsed > 60000) {
return SWITCH_STATUS_TIMEOUT;
}
}
#endif
if (switch_test_flag(tech_pvt, TFLAG_IO)) {
switch_status_t status;
@@ -382,20 +479,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
payload = tech_pvt->read_frame.payload;
#if 0
elapsed = (unsigned int) ((switch_time_now() - started) / 1000);
if (timeout > -1) {
if (elapsed >= (unsigned int) timeout) {
return SWITCH_STATUS_BREAK;
}
}
elapsed = (unsigned int) ((switch_time_now() - last_act) / 1000);
if (elapsed >= hard_timeout) {
return SWITCH_STATUS_BREAK;
}
#endif
if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
char dtmf[128];
switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
@@ -508,6 +591,9 @@ static switch_status_t sofia_kill_channel(switch_core_session_t *session, int si
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK);
}
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_BREAK);
}
break;
case SWITCH_SIG_KILL:
default:
@@ -517,6 +603,9 @@ static switch_status_t sofia_kill_channel(switch_core_session_t *session, int si
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_kill_socket(tech_pvt->rtp_session);
}
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_kill_socket(tech_pvt->video_rtp_session);
}
break;
}
@@ -774,7 +863,10 @@ static const switch_io_routines_t sofia_io_routines = {
/*.waitfor_read */ sofia_waitfor_write,
/*.send_dtmf */ sofia_send_dtmf,
/*.receive_message */ sofia_receive_message,
/*.receive_event */ sofia_receive_event
/*.receive_event */ sofia_receive_event,
/*.state_change*/ NULL,
/*.read_video_frame*/ sofia_read_video_frame,
/*.write_video_frame*/ sofia_write_video_frame
};
static const switch_state_handler_table_t sofia_event_handlers = {
+21 -2
View File
@@ -137,7 +137,9 @@ typedef enum {
TFLAG_BUGGY_2833 = (1 << 21),
TFLAG_SIP_HOLD = (1 << 22),
TFLAG_INB_NOMEDIA = (1 << 23),
TFLAG_LATE_NEGOTIATION = (1 << 24)
TFLAG_LATE_NEGOTIATION = (1 << 24),
TFLAG_SDP = (1 << 25),
TFLAG_VIDEO = (1 << 26)
} TFLAGS;
struct mod_sofia_globals {
@@ -310,7 +312,23 @@ struct private_object {
nua_handle_t *nh;
nua_handle_t *nh2;
sip_contact_t *contact;
int hangup_status;
/** VIDEO **/
switch_frame_t video_read_frame;
switch_codec_t video_read_codec;
switch_codec_t video_write_codec;
switch_rtp_t *video_rtp_session;
switch_port_t adv_sdp_video_port;
switch_port_t local_sdp_video_port;
char *video_rm_encoding;
switch_payload_t video_pt;
unsigned long video_rm_rate;
uint32_t video_codec_ms;
char *remote_sdp_video_ip;
switch_port_t remote_sdp_video_port;
char *video_rm_fmtp;
switch_payload_t video_agreed_pt;
char *video_fmtp_out;
uint32_t video_count;
};
struct callback_t {
@@ -428,3 +446,4 @@ switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile,
switch_core_db_callback_func_t callback,
void *pdata);
char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len);
void sofia_glue_check_video_codecs(private_object_t *tech_pvt);
+5 -11
View File
@@ -924,14 +924,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
nua_ack(nh, TAG_END());
break;
case nua_callstate_received:
if (session && switch_core_session_running(session)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-Entering Call State Received!\n");
goto done;
}
if (channel) {
if (r_sdp) {
if (tech_pvt && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
switch_set_flag_locked(tech_pvt, TFLAG_READY);
@@ -1015,7 +1009,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
break;
case nua_callstate_completed:
if (tech_pvt && r_sdp) {
if (r_sdp) {
if (r_sdp) { // && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
goto done;
} else {
@@ -1078,10 +1072,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
goto done;
}
if (!r_sdp) {
if (!r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
}
if (r_sdp) {
if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
switch_set_flag_locked(tech_pvt, TFLAG_ANS);
switch_channel_mark_answered(channel);
+335 -16
View File
@@ -34,6 +34,8 @@
*/
#include "mod_sofia.h"
switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt);
switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force);
void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force)
{
@@ -41,6 +43,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
switch_time_t now = switch_time_now();
int ptime = 0;
int rate = 0;
uint32_t v_port;
if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
return;
@@ -56,6 +59,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
port = tech_pvt->proxy_sdp_audio_port;
}
}
if (!sr) {
sr = "sendrecv";
}
@@ -63,7 +68,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
snprintf(buf, sizeof(buf),
"v=0\n"
"o=FreeSWITCH %d%" SWITCH_TIME_T_FMT " %d%" SWITCH_TIME_T_FMT " IN IP4 %s\n"
"s=FreeSWITCH\n" "c=IN IP4 %s\n" "t=0 0\n" "a=%s\n" "m=audio %d RTP/AVP", port, now, port, now, ip, ip, sr, port);
"s=FreeSWITCH\n"
"c=IN IP4 %s\n" "t=0 0\n"
"a=%s\n"
"m=audio %d RTP/AVP", port, now, port, now, ip, ip, sr, port);
if (tech_pvt->rm_encoding) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
@@ -72,6 +80,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
if (!ptime) {
ptime = imp->microseconds_per_frame / 1000;
@@ -105,6 +117,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
uint32_t rfc_3551_sucks = imp->samples_per_second;
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
if (!rate) {
rate = imp->samples_per_second;
}
@@ -136,6 +152,65 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t por
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
}
if (switch_test_flag(tech_pvt, TFLAG_VIDEO)) {
sofia_glue_tech_choose_video_port(tech_pvt);
if ((v_port = tech_pvt->adv_sdp_video_port)) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=video %d RTP/AVP", v_port);
sofia_glue_tech_set_video_codec(tech_pvt, 0);
/*****************************/
if (tech_pvt->video_rm_encoding) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->video_pt);
} else if (tech_pvt->num_codecs) {
int i;
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
if (!ptime) {
ptime = imp->microseconds_per_frame / 1000;
}
}
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
if (tech_pvt->rm_encoding) {
rate = tech_pvt->video_rm_rate;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->video_pt, tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate);
if (tech_pvt->video_fmtp_out) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->video_pt, tech_pvt->video_fmtp_out);
}
} else if (tech_pvt->num_codecs) {
int i;
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
if (!rate) {
rate = imp->samples_per_second;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, imp->samples_per_second);
if (imp->fmtp) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
}
}
}
}
}
/*****************************/
tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf);
}
@@ -146,11 +221,11 @@ void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt)
char *ocodec = NULL;
if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
return;
goto end;
}
if (tech_pvt->num_codecs) {
return;
goto end;
}
assert(tech_pvt->session != NULL);
@@ -192,6 +267,26 @@ void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt)
sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
}
end:
sofia_glue_check_video_codecs(tech_pvt);
}
void sofia_glue_check_video_codecs(private_object_t *tech_pvt)
{
if (tech_pvt->num_codecs && !switch_test_flag(tech_pvt, TFLAG_VIDEO)) {
int i;
for (i = 0; i < tech_pvt->num_codecs; i++) {
if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) {
tech_pvt->video_count++;
}
}
if (tech_pvt->video_count) {
switch_set_flag_locked(tech_pvt, TFLAG_VIDEO);
}
}
}
@@ -297,6 +392,42 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt)
return SWITCH_STATUS_SUCCESS;
}
switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt)
{
char *ip = tech_pvt->profile->rtpip;
switch_channel_t *channel;
switch_port_t sdp_port;
char tmp[50];
channel = switch_core_session_get_channel(tech_pvt->session);
if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_video_port) {
return SWITCH_STATUS_SUCCESS;
}
tech_pvt->local_sdp_video_port = switch_rtp_request_port();
sdp_port = tech_pvt->local_sdp_video_port;
if (tech_pvt->profile->extrtpip) {
if (sofia_glue_ext_address_lookup(&ip, &sdp_port, tech_pvt->profile->extrtpip, switch_core_session_get_pool(tech_pvt->session)) !=
SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
}
tech_pvt->adv_sdp_video_port = sdp_port;
snprintf(tmp, sizeof(tmp), "%d", sdp_port);
switch_channel_set_variable(channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
switch_channel_set_variable(channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
{
char rpid[1024] = { 0 };
@@ -555,6 +686,77 @@ void sofia_glue_deactivate_rtp(private_object_t *tech_pvt)
}
switch_rtp_destroy(&tech_pvt->rtp_session);
}
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_destroy(&tech_pvt->video_rtp_session);
}
}
switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force)
{
switch_channel_t *channel;
if (tech_pvt->video_read_codec.implementation) {
if (!force) {
return SWITCH_STATUS_SUCCESS;
}
if (strcasecmp(tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding) ||
tech_pvt->video_read_codec.implementation->samples_per_second != tech_pvt->video_rm_rate) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding);
switch_core_codec_destroy(&tech_pvt->video_read_codec);
switch_core_codec_destroy(&tech_pvt->video_write_codec);
//switch_core_session_reset(tech_pvt->session);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->video_read_codec.implementation->iananame);
return SWITCH_STATUS_SUCCESS;
}
}
channel = switch_core_session_get_channel(tech_pvt->session);
assert(channel != NULL);
if (!tech_pvt->video_rm_encoding) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n");
return SWITCH_STATUS_FALSE;
}
if (switch_core_codec_init(&tech_pvt->video_read_codec,
tech_pvt->video_rm_encoding,
tech_pvt->video_rm_fmtp,
tech_pvt->video_rm_rate,
0,
//tech_pvt->video_codec_ms,
1,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
return SWITCH_STATUS_FALSE;
} else {
if (switch_core_codec_init(&tech_pvt->video_write_codec,
tech_pvt->video_rm_encoding,
tech_pvt->video_rm_fmtp,
tech_pvt->video_rm_rate,
0,//tech_pvt->video_codec_ms,
1,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
return SWITCH_STATUS_FALSE;
} else {
int ms;
tech_pvt->video_read_frame.rate = tech_pvt->video_rm_rate;
ms = tech_pvt->video_write_codec.implementation->microseconds_per_frame / 1000;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set VIDEO Codec %s %s/%ld %d ms\n",
switch_channel_get_name(channel), tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate, tech_pvt->video_codec_ms);
tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec;
//switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
//switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->video_write_codec.fmtp_out);
}
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
@@ -625,6 +827,9 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
}
switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
{
int bw, ms;
@@ -674,7 +879,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
flags |= SWITCH_RTP_FLAG_AUTO_CNG;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_audio_port,
@@ -690,9 +895,9 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, &err) !=
SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP CHANGING DEST TO: [%s:%d]\n",
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
@@ -722,7 +927,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
if ((vad_in && inb) || (vad_out && !inb)) {
switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING);
switch_set_flag_locked(tech_pvt, TFLAG_VAD);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP Engage VAD for %s ( %s %s )\n",
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
}
@@ -732,6 +937,41 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
if (tech_pvt->cng_pt) {
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
}
sofia_glue_check_video_codecs(tech_pvt);
if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) {
flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE);
sofia_glue_tech_set_video_codec(tech_pvt, 0);
tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_video_port,
tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port,
tech_pvt->video_agreed_pt,
tech_pvt->video_read_codec.implementation->samples_per_frame,
0,//tech_pvt->video_codec_ms * 1000,
(switch_rtp_flag_t) flags,
NULL,
NULL,//tech_pvt->profile->timer_name,
&err, switch_core_session_get_pool(tech_pvt->session));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_get_name(channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_video_port,
tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
0,//tech_pvt->video_read_codec.implementation->microseconds_per_frame / 1000,
switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_channel_set_flag(channel, CF_VIDEO);
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
@@ -783,8 +1023,6 @@ switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, char *r_sdp)
return SWITCH_STATUS_FALSE;
}
uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
{
uint8_t match = 0;
@@ -811,6 +1049,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
if (switch_strlen_zero(a->a_name)) {
continue;
}
if (!strcasecmp(a->a_name, "sendonly")) {
if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
char *stream;
@@ -840,15 +1079,17 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
sdp_connection_t *connection;
ptime = dptime;
for (a = m->m_attributes; a; a = a->a_next) {
if (!strcasecmp(a->a_name, "ptime") && a->a_value) {
ptime = atoi(a->a_value);
}
}
if (m->m_type == sdp_media_audio) {
sdp_rtpmap_t *map;
for (a = m->m_attributes; a; a = a->a_next) {
if (!strcasecmp(a->a_name, "ptime") && a->a_value) {
ptime = atoi(a->a_value);
}
}
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
@@ -896,14 +1137,18 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n",
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d]/[%s:%d]\n",
rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
if (map->rm_pt < 96) {
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (match && (map->rm_rate == imp->samples_per_second)) {
if (ptime && ptime * 1000 != imp->microseconds_per_frame) {
near_match = imp;
@@ -963,9 +1208,83 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
}
}
}
} else if (m->m_type == sdp_media_video) {
sdp_rtpmap_t *map;
const char *rm_encoding;
int framerate = 0;
const switch_codec_implementation_t *mimp = NULL;
int vmatch = 0, i;
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
if (!connection) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
match = 0;
break;
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
for (a = m->m_attributes; a; a = a->a_next) {
if (!strcasecmp(a->a_name, "framerate") && a->a_value) {
framerate = atoi(a->a_value);
}
}
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
if (map->rm_pt < 96) {
vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (vmatch && (map->rm_rate == imp->samples_per_second)) {
mimp = imp;
break;
} else {
vmatch = 0;
}
}
if (mimp) {
if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
char tmp[50];
tech_pvt->video_pt = (switch_payload_t) map->rm_pt;
tech_pvt->video_rm_rate = map->rm_rate;
tech_pvt->video_codec_ms = mimp->microseconds_per_frame / 1000;
tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection->c_address);
tech_pvt->video_rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
tech_pvt->remote_sdp_video_port = (switch_port_t) m->m_port;
tech_pvt->video_agreed_pt = (switch_payload_t) map->rm_pt;
snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_video_port);
switch_channel_set_variable(channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
} else {
vmatch = 0;
}
}
}
}
}
switch_set_flag_locked(tech_pvt, TFLAG_SDP);
return match;
}