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:
parent
bdaab6dbbd
commit
a1725ad334
|
@ -714,6 +714,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_private_event(switch
|
|||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, int stream_id);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, int stream_id);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, int stream_id);
|
||||
|
||||
/*!
|
||||
\brief Reset the buffers and resampler on a session
|
||||
\param session the session to reset
|
||||
|
|
|
@ -38,7 +38,9 @@ typedef struct switch_io_event_hook_outgoing_channel switch_io_event_hook_outgoi
|
|||
typedef struct switch_io_event_hook_receive_message switch_io_event_hook_receive_message_t;
|
||||
typedef struct switch_io_event_hook_receive_event switch_io_event_hook_receive_event_t;
|
||||
typedef struct switch_io_event_hook_read_frame switch_io_event_hook_read_frame_t;
|
||||
typedef struct switch_io_event_hook_video_read_frame switch_io_event_hook_video_read_frame_t;
|
||||
typedef struct switch_io_event_hook_write_frame switch_io_event_hook_write_frame_t;
|
||||
typedef struct switch_io_event_hook_video_write_frame switch_io_event_hook_video_write_frame_t;
|
||||
typedef struct switch_io_event_hook_kill_channel switch_io_event_hook_kill_channel_t;
|
||||
typedef struct switch_io_event_hook_waitfor_read switch_io_event_hook_waitfor_read_t;
|
||||
typedef struct switch_io_event_hook_waitfor_write switch_io_event_hook_waitfor_write_t;
|
||||
|
@ -50,7 +52,9 @@ typedef switch_status_t (*switch_outgoing_channel_hook_t) (switch_core_session_t
|
|||
typedef switch_status_t (*switch_receive_message_hook_t) (switch_core_session_t *, switch_core_session_message_t *);
|
||||
typedef switch_status_t (*switch_receive_event_hook_t) (switch_core_session_t *, switch_event_t *);
|
||||
typedef switch_status_t (*switch_read_frame_hook_t) (switch_core_session_t *, switch_frame_t **, int, switch_io_flag_t, int);
|
||||
typedef switch_status_t (*switch_video_read_frame_hook_t) (switch_core_session_t *, switch_frame_t **, int, switch_io_flag_t, int);
|
||||
typedef switch_status_t (*switch_write_frame_hook_t) (switch_core_session_t *, switch_frame_t *, int, switch_io_flag_t, int);
|
||||
typedef switch_status_t (*switch_video_write_frame_hook_t) (switch_core_session_t *, switch_frame_t *, int, switch_io_flag_t, int);
|
||||
typedef switch_status_t (*switch_kill_channel_hook_t) (switch_core_session_t *, int);
|
||||
typedef switch_status_t (*switch_waitfor_read_hook_t) (switch_core_session_t *, int, int);
|
||||
typedef switch_status_t (*switch_waitfor_write_hook_t) (switch_core_session_t *, int, int);
|
||||
|
@ -86,6 +90,13 @@ struct switch_io_event_hook_read_frame {
|
|||
struct switch_io_event_hook_read_frame *next;
|
||||
};
|
||||
|
||||
/*! \brief Node in which to store custom read frame channel callback hooks */
|
||||
struct switch_io_event_hook_video_read_frame {
|
||||
/*! the read frame channel callback hook */
|
||||
switch_read_frame_hook_t video_read_frame;
|
||||
struct switch_io_event_hook_video_read_frame *next;
|
||||
};
|
||||
|
||||
/*! \brief Node in which to store custom write_frame channel callback hooks */
|
||||
struct switch_io_event_hook_write_frame {
|
||||
/*! the write_frame channel callback hook */
|
||||
|
@ -93,6 +104,13 @@ struct switch_io_event_hook_write_frame {
|
|||
struct switch_io_event_hook_write_frame *next;
|
||||
};
|
||||
|
||||
/*! \brief Node in which to store custom video_write_frame channel callback hooks */
|
||||
struct switch_io_event_hook_video_write_frame {
|
||||
/*! the video_write_frame channel callback hook */
|
||||
switch_video_write_frame_hook_t video_write_frame;
|
||||
struct switch_io_event_hook_video_write_frame *next;
|
||||
};
|
||||
|
||||
/*! \brief Node in which to store custom kill channel callback hooks */
|
||||
struct switch_io_event_hook_kill_channel {
|
||||
/*! the kill channel callback hook */
|
||||
|
@ -138,8 +156,12 @@ struct switch_io_event_hooks {
|
|||
switch_io_event_hook_receive_event_t *receive_event;
|
||||
/*! a list of read frame hooks */
|
||||
switch_io_event_hook_read_frame_t *read_frame;
|
||||
/*! a list of video read frame hooks */
|
||||
switch_io_event_hook_video_read_frame_t *video_read_frame;
|
||||
/*! a list of write frame hooks */
|
||||
switch_io_event_hook_write_frame_t *write_frame;
|
||||
/*! a list of video write frame hooks */
|
||||
switch_io_event_hook_video_write_frame_t *video_write_frame;
|
||||
/*! a list of kill channel hooks */
|
||||
switch_io_event_hook_kill_channel_t *kill_channel;
|
||||
/*! a list of wait for read hooks */
|
||||
|
@ -185,6 +207,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_receive_message(switc
|
|||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_read_frame(switch_core_session_t *session, switch_read_frame_hook_t read_frame);
|
||||
|
||||
/*!
|
||||
\brief Add an event hook to be executed when a session reads a frame
|
||||
\param session session to bind hook to
|
||||
\param video_read_frame hook to bind
|
||||
\return SWITCH_STATUS_SUCCESS on suceess
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_video_read_frame(switch_core_session_t *session, switch_read_frame_hook_t video_read_frame);
|
||||
|
||||
/*!
|
||||
\brief Add an event hook to be executed when a session writes a frame
|
||||
\param session session to bind hook to
|
||||
|
@ -193,6 +223,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_read_frame(switch_cor
|
|||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_write_frame(switch_core_session_t *session, switch_write_frame_hook_t write_frame);
|
||||
|
||||
/*!
|
||||
\brief Add an event hook to be executed when a session writes a video frame
|
||||
\param session session to bind hook to
|
||||
\param write_frame hook to bind
|
||||
\return SWITCH_STATUS_SUCCESS on suceess
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_video_write_frame(switch_core_session_t *session, switch_video_write_frame_hook_t video_write_frame);
|
||||
|
||||
/*!
|
||||
\brief Add an event hook to be executed when a session kills a channel
|
||||
\param session session to bind hook to
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
/*! \brief An abstraction of a data frame */
|
||||
struct switch_frame {
|
||||
struct switch_frame {
|
||||
/*! a pointer to the codec information */
|
||||
switch_codec_t *codec;
|
||||
/*! the originating source of the frame */
|
||||
|
@ -63,6 +63,9 @@ SWITCH_BEGIN_EXTERN_C
|
|||
switch_payload_t payload;
|
||||
/*! the timestamp of the frame */
|
||||
switch_size_t timestamp;
|
||||
uint16_t seq;
|
||||
uint32_t ssrc;
|
||||
switch_bool_t m;
|
||||
/*! frame flags */
|
||||
switch_frame_flag_t flags;
|
||||
};
|
||||
|
|
|
@ -203,6 +203,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_sessi
|
|||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_inband_dtmf_session(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_stop_inband_dtmf_session(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session);
|
||||
|
||||
/*!
|
||||
\brief play a file from the disk to the session
|
||||
|
|
|
@ -99,6 +99,10 @@ struct switch_io_routines {
|
|||
switch_status_t (*receive_event) (switch_core_session_t *, switch_event_t *);
|
||||
/*! change a sessions channel state */
|
||||
switch_status_t (*state_change) (switch_core_session_t *);
|
||||
/*! read a video frame from a session */
|
||||
switch_status_t (*read_video_frame) (switch_core_session_t *, switch_frame_t **, int, switch_io_flag_t, int);
|
||||
/*! write a video frame to a session */
|
||||
switch_status_t (*write_video_frame) (switch_core_session_t *, switch_frame_t *, int, switch_io_flag_t, int);
|
||||
};
|
||||
|
||||
/*! \brief Abstraction of an module endpoint interface
|
||||
|
|
|
@ -110,6 +110,10 @@ SWITCH_BEGIN_EXTERN_C
|
|||
#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "local_media_port"
|
||||
#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "remote_media_ip"
|
||||
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "remote_media_port"
|
||||
#define SWITCH_REMOTE_VIDEO_IP_VARIABLE "remote_video_ip"
|
||||
#define SWITCH_REMOTE_VIDEO_PORT_VARIABLE "remote_video_port"
|
||||
#define SWITCH_LOCAL_VIDEO_IP_VARIABLE "local_video_ip"
|
||||
#define SWITCH_LOCAL_VIDEO_PORT_VARIABLE "local_video_port"
|
||||
#define SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE "hangup_after_bridge"
|
||||
#define SWITCH_MAX_FORWARDS_VARIABLE "max_forwards"
|
||||
#define SWITCH_SPEECH_KEY "speech"
|
||||
|
@ -542,6 +546,7 @@ CF_RING_READY = (1 << 18) - Channel is ready to send ringback
|
|||
CF_BREAK = (1 << 19) - Channel should stop what it's doing
|
||||
CF_BROADCAST = (1 << 20) - Channel is broadcasting
|
||||
CF_UNICAST = (1 << 21) - Channel has a unicast connection
|
||||
CF_VIDEO = (1 << 22) - Channel has video
|
||||
</pre>
|
||||
*/
|
||||
|
||||
|
@ -567,7 +572,8 @@ typedef enum {
|
|||
CF_RING_READY = (1 << 18),
|
||||
CF_BREAK = (1 << 19),
|
||||
CF_BROADCAST = (1 << 20),
|
||||
CF_UNICAST = (1 << 21)
|
||||
CF_UNICAST = (1 << 21),
|
||||
CF_VIDEO = (1 << 22)
|
||||
} switch_channel_flag_t;
|
||||
|
||||
|
||||
|
@ -578,12 +584,14 @@ typedef enum {
|
|||
<pre>
|
||||
SFF_CNG = (1 << 0) - Frame represents comfort noise
|
||||
SFF_RAW_RTP = (1 << 1) - Frame has raw rtp accessible
|
||||
SFF_RTP_HEADER = (1 << 2) - Get the rtp header from the frame header
|
||||
</pre>
|
||||
*/
|
||||
typedef enum {
|
||||
SFF_NONE = 0,
|
||||
SFF_CNG = (1 << 0),
|
||||
SFF_RAW_RTP = (1 << 1)
|
||||
SFF_RAW_RTP = (1 << 1),
|
||||
SFF_RTP_HEADER = (1 << 2)
|
||||
} switch_frame_flag_t;
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
BASE=../../../..
|
||||
include /usr/src/freeswitch.trunk/build/modmake.rules
|
|
@ -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:
|
||||
*/
|
|
@ -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=""$(InputDir)..\..\..\include";"$(InputDir)include";"$(InputDir)..\..\..\..\libs\include";"$(InputDir)..\..\..\..\libs\libresample\include""
|
||||
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=""$(InputDir)..\..\..\..\libs\libresample\win";..\..\..\..\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=""$(InputDir)..\..\..\include";"$(InputDir)include";"$(InputDir)..\..\..\..\libs\include";"$(InputDir)..\..\..\..\libs\libresample\include""
|
||||
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=""$(InputDir)..\..\..\..\libs\libresample\win";..\..\..\..\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>
|
|
@ -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,6 +323,111 @@ 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;
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" : "");
|
||||
}
|
||||
|
||||
|
@ -733,6 +938,41 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt)
|
|||
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);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
|
@ -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;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (m->m_type == sdp_media_audio) {
|
||||
sdp_rtpmap_t *map;
|
||||
|
||||
connection = sdp->sdp_connection;
|
||||
if (m->m_connections) {
|
||||
connection = m->m_connections;
|
||||
|
@ -896,7 +1137,11 @@ 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;
|
||||
|
@ -963,8 +1208,82 @@ 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;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,50 @@ SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_write_frame(switch_co
|
|||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_video_read_frame(switch_core_session_t *session, switch_video_read_frame_hook_t video_read_frame)
|
||||
{
|
||||
switch_io_event_hook_video_read_frame_t *hook, *ptr;
|
||||
|
||||
assert(video_read_frame != NULL);
|
||||
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
|
||||
hook->video_read_frame = video_read_frame;
|
||||
if (!session->event_hooks.video_read_frame) {
|
||||
session->event_hooks.video_read_frame = hook;
|
||||
} else {
|
||||
for (ptr = session->event_hooks.video_read_frame; ptr && ptr->next; ptr = ptr->next);
|
||||
ptr->next = hook;
|
||||
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_video_write_frame(switch_core_session_t *session, switch_video_write_frame_hook_t video_write_frame)
|
||||
{
|
||||
switch_io_event_hook_video_write_frame_t *hook, *ptr;
|
||||
|
||||
assert(video_write_frame != NULL);
|
||||
if ((hook = switch_core_session_alloc(session, sizeof(*hook))) != 0) {
|
||||
hook->video_write_frame = video_write_frame;
|
||||
if (!session->event_hooks.video_write_frame) {
|
||||
session->event_hooks.video_write_frame = hook;
|
||||
} else {
|
||||
for (ptr = session->event_hooks.video_write_frame; ptr && ptr->next; ptr = ptr->next);
|
||||
ptr->next = hook;
|
||||
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_event_hook_add_kill_channel(switch_core_session_t *session, switch_kill_channel_hook_t kill_channel)
|
||||
{
|
||||
switch_io_event_hook_kill_channel_t *hook, *ptr;
|
||||
|
|
|
@ -35,6 +35,61 @@
|
|||
#include "private/switch_core.h"
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, int stream_id)
|
||||
{
|
||||
switch_io_event_hook_video_write_frame_t *ptr;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_io_flag_t flags = 0;
|
||||
if (session->endpoint_interface->io_routines->write_video_frame) {
|
||||
if ((status = session->endpoint_interface->io_routines->write_video_frame(session, frame, timeout, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||
for (ptr = session->event_hooks.video_write_frame; ptr; ptr = ptr->next) {
|
||||
if ((status = ptr->video_write_frame(session, frame, timeout, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, int stream_id)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_io_event_hook_video_read_frame_t *ptr;
|
||||
|
||||
if (session->endpoint_interface->io_routines->read_video_frame) {
|
||||
if ((status =
|
||||
session->endpoint_interface->io_routines->read_video_frame(session, frame, timeout, SWITCH_IO_FLAG_NOOP, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||
for (ptr = session->event_hooks.video_read_frame; ptr; ptr = ptr->next) {
|
||||
if ((status = ptr->video_read_frame(session, frame, timeout, SWITCH_IO_FLAG_NOOP, stream_id)) != SWITCH_STATUS_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(*frame)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
assert(session != NULL);
|
||||
assert(*frame != NULL);
|
||||
|
||||
if (switch_test_flag(*frame, SFF_CNG)) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, int stream_id)
|
||||
{
|
||||
switch_io_event_hook_read_frame_t *ptr;
|
||||
|
@ -128,6 +183,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
|||
session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
|
||||
session->raw_read_frame.rate = read_frame->rate;
|
||||
session->raw_read_frame.timestamp = read_frame->timestamp;
|
||||
session->raw_read_frame.ssrc = read_frame->ssrc;
|
||||
session->raw_read_frame.seq = read_frame->seq;
|
||||
session->raw_read_frame.m = read_frame->m;
|
||||
session->raw_read_frame.payload = read_frame->payload;
|
||||
read_frame = &session->raw_read_frame;
|
||||
break;
|
||||
case SWITCH_STATUS_NOOP:
|
||||
|
@ -139,6 +198,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
|||
session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
|
||||
session->raw_read_frame.timestamp = read_frame->timestamp;
|
||||
session->raw_read_frame.rate = read_frame->rate;
|
||||
session->raw_read_frame.ssrc = read_frame->ssrc;
|
||||
session->raw_read_frame.seq = read_frame->seq;
|
||||
session->raw_read_frame.m = read_frame->m;
|
||||
session->raw_read_frame.payload = read_frame->payload;
|
||||
read_frame = &session->raw_read_frame;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
break;
|
||||
|
@ -244,6 +307,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
|||
session->enc_read_frame.codec = session->read_codec;
|
||||
session->enc_read_frame.samples = session->read_codec->implementation->bytes_per_frame / sizeof(int16_t);
|
||||
session->enc_read_frame.timestamp = read_frame->timestamp;
|
||||
session->enc_read_frame.rate = read_frame->rate;
|
||||
session->enc_read_frame.ssrc = read_frame->ssrc;
|
||||
session->enc_read_frame.seq = read_frame->seq;
|
||||
session->enc_read_frame.m = read_frame->m;
|
||||
session->enc_read_frame.payload = session->read_codec->implementation->ianacode;
|
||||
*frame = &session->enc_read_frame;
|
||||
break;
|
||||
|
@ -252,6 +319,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
|||
session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_frame;
|
||||
session->raw_read_frame.timestamp = read_frame->timestamp;
|
||||
session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode;
|
||||
session->raw_read_frame.m = read_frame->m;
|
||||
session->raw_read_frame.ssrc = read_frame->ssrc;
|
||||
session->raw_read_frame.seq = read_frame->seq;
|
||||
*frame = &session->raw_read_frame;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
break;
|
||||
|
@ -371,6 +441,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
|||
session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t);
|
||||
session->raw_write_frame.timestamp = frame->timestamp;
|
||||
session->raw_write_frame.rate = frame->rate;
|
||||
session->raw_write_frame.m = frame->m;
|
||||
session->raw_write_frame.ssrc = frame->ssrc;
|
||||
session->raw_write_frame.seq = frame->seq;
|
||||
session->raw_write_frame.payload = frame->payload;
|
||||
write_frame = &session->raw_write_frame;
|
||||
break;
|
||||
case SWITCH_STATUS_BREAK:
|
||||
|
@ -500,12 +574,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
|||
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
|
||||
session->enc_write_frame.timestamp = frame->timestamp;
|
||||
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
|
||||
session->enc_write_frame.m = frame->m;
|
||||
session->enc_write_frame.ssrc = frame->ssrc;
|
||||
session->enc_write_frame.seq = frame->seq;
|
||||
write_frame = &session->enc_write_frame;
|
||||
break;
|
||||
case SWITCH_STATUS_NOOP:
|
||||
enc_frame->codec = session->write_codec;
|
||||
enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
|
||||
enc_frame->timestamp = frame->timestamp;
|
||||
enc_frame->m = frame->m;
|
||||
enc_frame->seq = frame->seq;
|
||||
enc_frame->ssrc = frame->ssrc;
|
||||
enc_frame->payload = enc_frame->codec->implementation->ianacode;
|
||||
write_frame = enc_frame;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
@ -553,6 +633,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
|||
session->enc_write_frame.codec = session->write_codec;
|
||||
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
|
||||
session->enc_write_frame.timestamp = frame->timestamp;
|
||||
session->enc_write_frame.m = frame->m;
|
||||
session->enc_write_frame.ssrc = frame->ssrc;
|
||||
session->enc_write_frame.seq = frame->seq;
|
||||
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
|
||||
write_frame = &session->enc_write_frame;
|
||||
if (!session->read_resampler) {
|
||||
|
@ -571,6 +654,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
|||
session->enc_write_frame.codec = session->write_codec;
|
||||
session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
|
||||
session->enc_write_frame.timestamp = frame->timestamp;
|
||||
session->enc_write_frame.m = frame->m;
|
||||
session->enc_write_frame.ssrc = frame->ssrc;
|
||||
session->enc_write_frame.seq = frame->seq;
|
||||
session->enc_write_frame.payload = session->write_codec->implementation->ianacode;
|
||||
write_frame = &session->enc_write_frame;
|
||||
break;
|
||||
|
@ -578,6 +664,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
|||
enc_frame->codec = session->write_codec;
|
||||
enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
|
||||
enc_frame->timestamp = frame->timestamp;
|
||||
enc_frame->m = frame->m;
|
||||
enc_frame->ssrc = frame->ssrc;
|
||||
enc_frame->seq = frame->seq;
|
||||
enc_frame->payload = enc_frame->codec->implementation->ianacode;
|
||||
write_frame = enc_frame;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
|
|
@ -181,18 +181,9 @@ static void switch_core_standard_on_execute(switch_core_session_t *session)
|
|||
|
||||
static void switch_core_standard_on_loopback(switch_core_session_t *session)
|
||||
{
|
||||
switch_frame_t *frame;
|
||||
int stream_id;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard LOOPBACK\n");
|
||||
|
||||
while (switch_channel_get_state(session->channel) == CS_LOOPBACK) {
|
||||
for (stream_id = 0; stream_id < session->stream_count; stream_id++) {
|
||||
if (switch_core_session_read_frame(session, &frame, -1, stream_id) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_write_frame(session, frame, -1, stream_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_ivr_session_echo(session);
|
||||
}
|
||||
|
||||
static void switch_core_standard_on_transmit(switch_core_session_t *session)
|
||||
|
|
|
@ -31,6 +31,71 @@
|
|||
*/
|
||||
#include <switch.h>
|
||||
|
||||
struct echo_helper {
|
||||
switch_core_session_t *session;
|
||||
int up;
|
||||
};
|
||||
|
||||
static void *SWITCH_THREAD_FUNC echo_video_thread(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
struct echo_helper *eh = obj;
|
||||
switch_core_session_t *session = eh->session;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_status_t status;
|
||||
switch_frame_t *read_frame;
|
||||
|
||||
eh->up = 1;
|
||||
while(switch_channel_ready(channel) && switch_channel_get_state(channel) == CS_LOOPBACK) {
|
||||
status = switch_core_session_read_video_frame(session, &read_frame, -1, 0);
|
||||
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch_core_session_write_video_frame(session, read_frame, -1, 0);
|
||||
|
||||
}
|
||||
eh->up = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session)
|
||||
{
|
||||
switch_status_t status;
|
||||
switch_frame_t *read_frame;
|
||||
struct echo_helper eh = {0};
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
|
||||
|
||||
switch_channel_answer(channel);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
eh.session = session;
|
||||
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&thread, thd_attr, echo_video_thread, &eh, switch_core_session_get_pool(session));
|
||||
}
|
||||
|
||||
while(switch_channel_ready(channel) && switch_channel_get_state(channel) == CS_LOOPBACK) {
|
||||
status = switch_core_session_read_frame(session, &read_frame, -1, 0);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
switch_core_session_write_frame(session, read_frame, -1, 0);
|
||||
}
|
||||
|
||||
if (eh.up) {
|
||||
while(eh.up) {
|
||||
switch_yield(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
switch_file_handle_t *fh = (switch_file_handle_t *) user_data;
|
||||
|
|
|
@ -352,8 +352,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
|
|||
rtp_session->sock = new_sock;
|
||||
new_sock = NULL;
|
||||
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)
|
||||
|| switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) {
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) {
|
||||
switch_socket_opt_set(rtp_session->sock, SWITCH_SO_NONBLOCK, TRUE);
|
||||
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
|
||||
}
|
||||
|
@ -900,7 +899,11 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||
|
||||
if (status == SWITCH_STATUS_BREAK || bytes == 0) {
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DATAWAIT)) {
|
||||
if (rtp_session->ms_per_packet) {
|
||||
switch_yield((rtp_session->ms_per_packet / 1000) * 750);
|
||||
} else {
|
||||
switch_yield(1000);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1143,6 +1146,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
|||
frame->source = __FILE__;
|
||||
frame->flags |= SFF_RAW_RTP;
|
||||
frame->timestamp = ntohl(rtp_session->recv_msg.header.ts);
|
||||
frame->seq = ntohs(rtp_session->recv_msg.header.seq);
|
||||
frame->ssrc = ntohl(rtp_session->recv_msg.header.ssrc);
|
||||
frame->m = rtp_session->recv_msg.header.m ? SWITCH_TRUE : SWITCH_FALSE;
|
||||
|
||||
if (bytes < 0) {
|
||||
frame->datalen = 0;
|
||||
|
@ -1155,6 +1161,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
|||
}
|
||||
|
||||
frame->datalen = bytes;
|
||||
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1350,7 +1359,6 @@ static int rtp_common_write(switch_rtp_t *rtp_session, void *data, uint32_t data
|
|||
switch_core_timer_check(&rtp_session->timer);
|
||||
rtp_session->last_write_samplecount = rtp_session->timer.samplecount;
|
||||
}
|
||||
|
||||
switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void *) send_msg, &bytes);
|
||||
}
|
||||
|
||||
|
@ -1478,6 +1486,12 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra
|
|||
payload = rtp_session->payload;
|
||||
}
|
||||
|
||||
if (switch_test_flag(frame, SFF_RTP_HEADER)) {
|
||||
return switch_rtp_write_manual(rtp_session, frame->data, frame->datalen, frame->m, frame->payload,
|
||||
frame->timestamp, frame->seq, frame->ssrc, &frame->flags);
|
||||
}
|
||||
|
||||
|
||||
if (fwd) {
|
||||
data = frame->packet;
|
||||
len = frame->packetlen;
|
||||
|
@ -1551,7 +1565,7 @@ SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session,
|
|||
}
|
||||
return (int) bytes;
|
||||
|
||||
//return rtp_common_write(rtp_session, (void *) &send_msg, rtp_header_len + datalen, m, payload, NULL);
|
||||
//return rtp_common_write(rtp_session, (void *) &send_msg, rtp_header_len + datalen, m, payload);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(uint32_t) switch_rtp_get_ssrc(switch_rtp_t *rtp_session)
|
||||
|
|
Loading…
Reference in New Issue