[Freeswitch-svn] [commit] r4977 - in freeswitch/trunk/src: . include mod/codecs/mod_h26x mod/endpoints/mod_sofia

Freeswitch SVN anthm at freeswitch.org
Thu Apr 19 17:40:50 EDT 2007


Author: anthm
Date: Thu Apr 19 17:40:50 2007
New Revision: 4977

Added:
   freeswitch/trunk/src/mod/codecs/mod_h26x/
   freeswitch/trunk/src/mod/codecs/mod_h26x/Makefile
   freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.c
   freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.vcproj
Modified:
   freeswitch/trunk/src/include/switch_core.h
   freeswitch/trunk/src/include/switch_core_event_hook.h
   freeswitch/trunk/src/include/switch_frame.h
   freeswitch/trunk/src/include/switch_ivr.h
   freeswitch/trunk/src/include/switch_module_interfaces.h
   freeswitch/trunk/src/include/switch_types.h
   freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
   freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h
   freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c
   freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c
   freeswitch/trunk/src/switch_core_event_hook.c
   freeswitch/trunk/src/switch_core_io.c
   freeswitch/trunk/src/switch_core_state_machine.c
   freeswitch/trunk/src/switch_ivr_async.c
   freeswitch/trunk/src/switch_rtp.c

Log:
modest core framework for video stuff

Modified: freeswitch/trunk/src/include/switch_core.h
==============================================================================
--- freeswitch/trunk/src/include/switch_core.h	(original)
+++ freeswitch/trunk/src/include/switch_core.h	Thu Apr 19 17:40:50 2007
@@ -714,6 +714,9 @@
 */
 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

Modified: freeswitch/trunk/src/include/switch_core_event_hook.h
==============================================================================
--- freeswitch/trunk/src/include/switch_core_event_hook.h	(original)
+++ freeswitch/trunk/src/include/switch_core_event_hook.h	Thu Apr 19 17:40:50 2007
@@ -38,7 +38,9 @@
 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_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 *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 *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 @@
 	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 */
@@ -186,6 +208,14 @@
 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
   \param write_frame hook to bind
@@ -194,6 +224,14 @@
 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
   \param kill_channel hook to bind

Modified: freeswitch/trunk/src/include/switch_frame.h
==============================================================================
--- freeswitch/trunk/src/include/switch_frame.h	(original)
+++ freeswitch/trunk/src/include/switch_frame.h	Thu Apr 19 17:40:50 2007
@@ -30,7 +30,7 @@
  *
  */
 /*! \file switch_frame.h
-    \brief Media Frame Structure
+  \brief Media Frame Structure
 */
 
 #ifndef SWITCH_FRAME_H
@@ -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_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;
 };

Modified: freeswitch/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_ivr.h	(original)
+++ freeswitch/trunk/src/include/switch_ivr.h	Thu Apr 19 17:40:50 2007
@@ -203,6 +203,7 @@
 
 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

Modified: freeswitch/trunk/src/include/switch_module_interfaces.h
==============================================================================
--- freeswitch/trunk/src/include/switch_module_interfaces.h	(original)
+++ freeswitch/trunk/src/include/switch_module_interfaces.h	Thu Apr 19 17:40:50 2007
@@ -99,6 +99,10 @@
 	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

Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h	(original)
+++ freeswitch/trunk/src/include/switch_types.h	Thu Apr 19 17:40:50 2007
@@ -110,6 +110,10 @@
 #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_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 @@
 	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 @@
 <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;
 
 

Added: freeswitch/trunk/src/mod/codecs/mod_h26x/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/codecs/mod_h26x/Makefile	Thu Apr 19 17:40:50 2007
@@ -0,0 +1,2 @@
+BASE=../../../..
+include /usr/src/freeswitch.trunk/build/modmake.rules

Added: freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.c	Thu Apr 19 17:40:50 2007
@@ -0,0 +1,154 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct at 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:
+ */

Added: freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.vcproj
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/codecs/mod_h26x/mod_h26x.vcproj	Thu Apr 19 17:40:50 2007
@@ -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>

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	Thu Apr 19 17:40:50 2007
@@ -58,6 +58,8 @@
 												  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,13 @@
 }
 
 
-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_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);
 
@@ -337,7 +340,7 @@
 		return SWITCH_STATUS_FALSE;
 	}
 
-	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+	while (!(tech_pvt->video_read_codec.implementation && switch_rtp_ready(tech_pvt->video_rtp_session))) {
 		if (switch_channel_ready(channel)) {
 			switch_yield(10000);
 		} else {
@@ -346,18 +349,112 @@
 	}
 
 
-	tech_pvt->read_frame.datalen = 0;
-	switch_set_flag_locked(tech_pvt, TFLAG_READING);
+	tech_pvt->video_read_frame.datalen = 0;
 
-#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;
+
+	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;
+			}
 		}
 	}
-#endif
 
+	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);
+
+	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->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+		if (switch_channel_ready(channel)) {
+			switch_yield(10000);
+		} else {
+			return SWITCH_STATUS_GENERR;
+		}
+	}
+
+
+	tech_pvt->read_frame.datalen = 0;
+	switch_set_flag_locked(tech_pvt, TFLAG_READING);
 
 	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
 		switch_status_t status;
@@ -382,20 +479,6 @@
 
 			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 @@
 		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 @@
 		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 @@
 	/*.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 = {

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h	Thu Apr 19 17:40:50 2007
@@ -137,7 +137,9 @@
 	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 @@
 	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_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);

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	Thu Apr 19 17:40:50 2007
@@ -924,14 +924,8 @@
 		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 @@
 		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 @@
 				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);

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c	Thu Apr 19 17:40:50 2007
@@ -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 @@
 	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 @@
 			port = tech_pvt->proxy_sdp_audio_port;
 		}
 	}
+
+
 	if (!sr) {
 		sr = "sendrecv";
 	}
@@ -63,7 +68,10 @@
 	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 @@
 		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 @@
 			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 @@
 		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 @@
 	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 @@
 											  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 @@
 	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 @@
 		}
 		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_activate_rtp(private_object_t *tech_pvt)
 {
 	int bw, ms;
@@ -674,7 +879,7 @@
 		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 @@
 
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 
 				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 @@
 					}
 				}
 			}
+		} 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;
 }
 

Modified: freeswitch/trunk/src/switch_core_event_hook.c
==============================================================================
--- freeswitch/trunk/src/switch_core_event_hook.c	(original)
+++ freeswitch/trunk/src/switch_core_event_hook.c	Thu Apr 19 17:40:50 2007
@@ -118,6 +118,50 @@
 
 }
 
+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;

Modified: freeswitch/trunk/src/switch_core_io.c
==============================================================================
--- freeswitch/trunk/src/switch_core_io.c	(original)
+++ freeswitch/trunk/src/switch_core_io.c	Thu Apr 19 17:40:50 2007
@@ -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 @@
 				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 @@
 				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 @@
 					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 @@
 					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 @@
 				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 @@
 					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 @@
 								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 @@
 								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 @@
 								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;

Modified: freeswitch/trunk/src/switch_core_state_machine.c
==============================================================================
--- freeswitch/trunk/src/switch_core_state_machine.c	(original)
+++ freeswitch/trunk/src/switch_core_state_machine.c	Thu Apr 19 17:40:50 2007
@@ -181,18 +181,9 @@
 
 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)

Modified: freeswitch/trunk/src/switch_ivr_async.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr_async.c	(original)
+++ freeswitch/trunk/src/switch_ivr_async.c	Thu Apr 19 17:40:50 2007
@@ -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;

Modified: freeswitch/trunk/src/switch_rtp.c
==============================================================================
--- freeswitch/trunk/src/switch_rtp.c	(original)
+++ freeswitch/trunk/src/switch_rtp.c	Thu Apr 19 17:40:50 2007
@@ -352,8 +352,7 @@
 	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);
 	}
@@ -803,7 +802,7 @@
 	while (switch_rtp_ready(rtp_session)) {
 		bytes = sizeof(rtp_msg_t);
 		status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *) &rtp_session->recv_msg, &bytes);
-
+		
 		if (!SWITCH_STATUS_IS_BREAK(status) && rtp_session->timer.interval) {
 			switch_core_timer_step(&rtp_session->timer);
 		}
@@ -900,7 +899,11 @@
 
 		if (status == SWITCH_STATUS_BREAK || bytes == 0) {
 			if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DATAWAIT)) {
-				switch_yield((rtp_session->ms_per_packet / 1000) * 750);
+				if (rtp_session->ms_per_packet) {
+					switch_yield((rtp_session->ms_per_packet / 1000) * 750);
+				} else {
+					switch_yield(1000);
+				}
 				continue;
 			}
 			return 0;
@@ -1136,13 +1139,16 @@
 	}
 
 	bytes = rtp_common_read(rtp_session, &frame->payload, &frame->flags);
-
+	
 	frame->data = rtp_session->recv_msg.body;
 	frame->packet = &rtp_session->recv_msg;
 	frame->packetlen = bytes;
 	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;
@@ -1153,8 +1159,11 @@
 	} else {
 		bytes -= rtp_header_len;
 	}
-
+	
 	frame->datalen = bytes;
+		
+
+
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1350,7 +1359,6 @@
 			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 @@
 		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 @@
 	}
 	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)



More information about the Freeswitch-svn mailing list