static const char ModuleName[] = "opal";\r
\r
\r
+static switch_status_t on_hangup(switch_core_session_t *session);\r
+\r
+\r
static switch_io_routines_t opalfs_io_routines = {\r
/*.outgoing_channel */ create_outgoing_channel,\r
/*.read_frame */ FSConnection::read_audio_frame,\r
/*.on_init */ FSConnection::on_init,\r
/*.on_routing */ FSConnection::on_routing,\r
/*.on_execute */ FSConnection::on_execute,\r
- /*.on_hangup */ FSConnection::on_hangup,\r
+ /*.on_hangup */ on_hangup,\r
/*.on_loopback */ FSConnection::on_loopback,\r
/*.on_transmit */ FSConnection::on_transmit\r
};\r
\r
///////////////////////////////////////////////////////////////////////\r
\r
+\r
FSConnection::FSConnection(OpalCall & call, FSEndPoint & endpoint)\r
: OpalLocalConnection(call, endpoint, NULL)\r
, m_endpoint(endpoint)\r
{\r
+ opal_private_t *tech_pvt;\r
FSManager & mgr = (FSManager &) endpoint.GetManager();\r
m_fsSession = switch_core_session_request(mgr.GetSwitchInterface(), NULL);\r
m_fsChannel = switch_core_session_get_channel(m_fsSession);\r
- switch_core_session_set_private(m_fsSession, this);\r
+\r
+ tech_pvt = (opal_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt));\r
+ tech_pvt->me = this;\r
+ switch_core_session_set_private(m_fsSession, tech_pvt);\r
}\r
\r
\r
\r
void FSConnection::OnReleased()\r
{\r
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession);\r
+ \r
+ /* so FS on_hangup will not try to deref a landmine */\r
+ tech_pvt->me = NULL;\r
+ \r
m_rxAudioOpened.Signal(); // Just in case\r
m_txAudioOpened.Signal();\r
H225_ReleaseCompleteReason dummy;\r
switch_channel_hangup(switch_core_session_get_channel(m_fsSession),\r
- (switch_call_cause_t)H323TranslateFromCallEndReason(GetCallEndReason(), dummy));\r
+ (switch_call_cause_t)H323TranslateFromCallEndReason(GetCallEndReason(), dummy)); \r
OpalLocalConnection::OnReleased();\r
}\r
\r
}\r
\r
\r
-switch_status_t FSConnection::on_hangup()\r
+/* this function has to be called with the original session beause the FSConnection might already be destroyed and we \r
+ will can't have it be a method of a dead object\r
+ */\r
+static switch_status_t on_hangup(switch_core_session_t *session)\r
{\r
- switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);\r
- if (channel == NULL) {\r
- return SWITCH_STATUS_FALSE;\r
+ switch_channel_t *channel = switch_core_session_get_channel(session);\r
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session);\r
+ \r
+ /* if this is still here it was our idea to hangup not opal's */\r
+ if (tech_pvt->me) {\r
+ Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);\r
+ tech_pvt->me->SetQ931Cause(cause);\r
+ tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));\r
+ tech_pvt->me = NULL;\r
+ }\r
+ \r
+ if (tech_pvt->read_codec.implementation) {\r
+ switch_core_codec_destroy(&tech_pvt->read_codec);\r
}\r
\r
- Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);\r
- SetQ931Cause(cause);\r
- ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));\r
+ if (tech_pvt->write_codec.implementation) {\r
+ switch_core_codec_destroy(&tech_pvt->write_codec);\r
+ }\r
+\r
+ if (tech_pvt->vid_read_codec.implementation) {\r
+ switch_core_codec_destroy(&tech_pvt->vid_read_codec);\r
+ }\r
+\r
+ if (tech_pvt->vid_write_codec.implementation) {\r
+ switch_core_codec_destroy(&tech_pvt->vid_write_codec);\r
+ }\r
+\r
+ if (tech_pvt->read_timer.timer_interface) {\r
+ switch_core_timer_destroy(&tech_pvt->read_timer);\r
+ }\r
+\r
+ if (tech_pvt->vid_read_timer.timer_interface) {\r
+ switch_core_timer_destroy(&tech_pvt->vid_read_timer);\r
+ }\r
+\r
+ switch_core_session_unset_read_codec(session);\r
+ switch_core_session_unset_write_codec(session);\r
+\r
return SWITCH_STATUS_SUCCESS;\r
}\r
\r
\r
switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg)\r
{\r
- switch_core_session_t *session = GetSession();\r
- switch_channel_t *channel = switch_core_session_get_channel(session);\r
+ switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);\r
\r
\r
/*\r
, m_callOnStart(true)\r
{\r
memset(&m_readFrame, 0, sizeof(m_readFrame));\r
- m_readFrame.codec = &m_switchCodec;\r
+ m_readFrame.codec = m_switchCodec;\r
m_readFrame.flags = SFF_RAW_RTP;\r
}\r
\r
\r
PBoolean FSMediaStream::Open()\r
{\r
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession);\r
+\r
if (IsOpen()) {\r
return true;\r
}\r
\r
int ptime = mediaFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption()) * mediaFormat.GetFrameTime() / mediaFormat.GetTimeUnits();\r
\r
+\r
+ if (IsSink()) {\r
+ m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec;\r
+ m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer;\r
+ } else {\r
+ m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec;\r
+ }\r
+\r
// The following is performed on two different instances of this object.\r
- if (switch_core_codec_init(&m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
+ if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
mediaFormat.GetClockRate(), ptime, 1, // Channels\r
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings\r
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {\r
// Could not select a codecs using negotiated frames/packet, so try using default.\r
- if (switch_core_codec_init(&m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
+ if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP\r
mediaFormat.GetClockRate(), 0, 1, // Channels\r
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings\r
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {\r
m_readFrame.rate = mediaFormat.GetClockRate();\r
\r
if (isAudio) {\r
- switch_core_session_set_read_codec(m_fsSession, &m_switchCodec);\r
- if (switch_core_timer_init(&m_switchTimer,\r
+ switch_core_session_set_read_codec(m_fsSession, m_switchCodec);\r
+ if (switch_core_timer_init(m_switchTimer,\r
"soft",\r
- m_switchCodec.implementation->microseconds_per_packet / 1000,\r
- m_switchCodec.implementation->samples_per_packet,\r
+ m_switchCodec->implementation->microseconds_per_packet / 1000,\r
+ m_switchCodec->implementation->samples_per_packet,\r
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {\r
- switch_core_codec_destroy(&m_switchCodec);\r
+ switch_core_codec_destroy(m_switchCodec);\r
+ m_switchCodec = NULL;\r
return false;\r
}\r
} else {\r
- switch_core_session_set_video_read_codec(m_fsSession, &m_switchCodec);\r
+ switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec);\r
switch_channel_set_flag(m_fsChannel, CF_VIDEO);\r
}\r
} else {\r
if (isAudio) {\r
- switch_core_session_set_write_codec(m_fsSession, &m_switchCodec);\r
+ switch_core_session_set_write_codec(m_fsSession, m_switchCodec);\r
} else {\r
- switch_core_session_set_video_write_codec(m_fsSession, &m_switchCodec);\r
+ switch_core_session_set_video_write_codec(m_fsSession, m_switchCodec);\r
switch_channel_set_flag(m_fsChannel, CF_VIDEO);\r
}\r
}\r
{\r
if (!IsOpen())\r
return false;\r
+ \r
+ /* forget these FS will properly destroy them for us */\r
\r
- bool isAudio;\r
-\r
- if (mediaFormat.GetMediaType() == OpalMediaType::Audio()) {\r
- isAudio = true;\r
- } else if (mediaFormat.GetMediaType() == OpalMediaType::Video()) {\r
- isAudio = false;\r
- } else {\r
- return OpalMediaStream::Close();\r
- }\r
-\r
- if (IsSink()) {\r
- if (isAudio) {\r
- switch_core_session_unset_read_codec(m_fsSession);\r
- switch_core_timer_destroy(&m_switchTimer);\r
- } else {\r
- switch_core_session_set_video_read_codec(m_fsSession, NULL);\r
- }\r
-\r
- switch_core_codec_destroy(&m_switchCodec);\r
- } else {\r
- if (isAudio)\r
- switch_core_session_unset_write_codec(m_fsSession);\r
- else\r
- switch_core_session_set_video_write_codec(m_fsSession, NULL);\r
- switch_core_codec_destroy(&m_switchCodec);\r
- }\r
-\r
- PTRACE(3, "mod_opal\tReset & destroyed " << (IsSink()? "read" : "write")\r
- << ' ' << mediaFormat.GetMediaType() << " codec for connection " << *this);\r
+ m_switchTimer = NULL;\r
+ m_switchCodec = NULL;\r
\r
return OpalMediaStream::Close();\r
}\r
\r
switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags)\r
{\r
+\r
+ if (!m_switchCodec) {\r
+ return SWITCH_STATUS_FALSE;\r
+ }\r
+\r
if (m_callOnStart) {\r
/*\r
There is a race here... sometimes we make it here and GetPatch() is NULL\r
}\r
} else {\r
\r
- if (!GetPatch()->GetSource().ReadPacket(m_readRTP)) {\r
+ if (!m_switchTimer || !GetPatch()->GetSource().ReadPacket(m_readRTP)) {\r
return SWITCH_STATUS_FALSE;\r
}\r
\r
- switch_core_timer_next(&m_switchTimer);\r
+ switch_core_timer_next(m_switchTimer);\r
\r
if (!(m_readFrame.datalen = m_readRTP.GetPayloadSize())) {\r
m_readFrame.flags = SFF_CNG;\r
m_readFrame.m = (switch_bool_t) m_readRTP.GetMarker();\r
m_readFrame.seq = m_readRTP.GetSequenceNumber();\r
m_readFrame.ssrc = m_readRTP.GetSyncSource();\r
+ m_readFrame.codec = m_switchCodec;\r
*frame = &m_readFrame;\r
\r
return SWITCH_STATUS_SUCCESS;\r
list < FSListener > m_listeners;
};
+class FSConnection;
+typedef struct {
+ switch_timer_t read_timer;
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+
+ switch_timer_t vid_read_timer;
+ switch_codec_t vid_read_codec;
+ switch_codec_t vid_write_codec;
+ FSConnection *me;
+} opal_private_t;
+
class FSEndPoint:public OpalLocalEndPoint {
PCLASSINFO(FSEndPoint, OpalLocalEndPoint);
};
-#define DECLARE_CALLBACK0(name) \
+#define DECLARE_CALLBACK0(name) \
static switch_status_t name(switch_core_session_t *session) { \
- FSConnection * conn = (FSConnection *)switch_core_session_get_private(session); \
- return conn != NULL ? conn->name() : SWITCH_STATUS_FALSE; } \
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name() : SWITCH_STATUS_FALSE; } \
switch_status_t name()
#define DECLARE_CALLBACK1(name, type1, name1) \
static switch_status_t name(switch_core_session_t *session, type1 name1) { \
- FSConnection * conn = (FSConnection *)switch_core_session_get_private(session); \
- return conn != NULL ? conn->name(name1) : SWITCH_STATUS_FALSE; } \
- switch_status_t name(type1 name1)
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1) : SWITCH_STATUS_FALSE; } \
+switch_status_t name(type1 name1)
#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \
static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \
- FSConnection * conn = (FSConnection *)switch_core_session_get_private(session); \
- return conn != NULL ? conn->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
- switch_status_t name(type1 name1, type2 name2, type3 name3)
+ opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
+switch_status_t name(type1 name1, type2 name2, type3 name3)
+
+
class FSConnection:public OpalLocalConnection {
DECLARE_CALLBACK0(on_init);
DECLARE_CALLBACK0(on_routing);
DECLARE_CALLBACK0(on_execute);
- DECLARE_CALLBACK0(on_hangup);
+ //DECLARE_CALLBACK0(on_hangup);
+
DECLARE_CALLBACK0(on_loopback);
DECLARE_CALLBACK0(on_transmit);
private:
switch_core_session_t *m_fsSession;
switch_channel_t *m_fsChannel;
- switch_timer_t m_switchTimer;
- switch_codec_t m_switchCodec;
+ switch_timer_t *m_switchTimer;
+ switch_codec_t *m_switchCodec;
switch_frame_t m_readFrame;
RTP_DataFrame m_readRTP;
bool m_callOnStart;