From e39a63d820339aa3a3dcc38443c2b71c9a486d9f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 12 Feb 2009 00:26:04 +0000 Subject: [PATCH] changes to put freeswitch in control of lifecycle of some critical objects, -sigh git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11899 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_opal/mod_opal.cpp | 145 +++++++++++++++--------- src/mod/endpoints/mod_opal/mod_opal.h | 39 +++++-- 2 files changed, 118 insertions(+), 66 deletions(-) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 7e21b07891..4526942535 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -47,6 +47,9 @@ static FSProcess *opal_process = NULL; static const char ModuleName[] = "opal"; +static switch_status_t on_hangup(switch_core_session_t *session); + + static switch_io_routines_t opalfs_io_routines = { /*.outgoing_channel */ create_outgoing_channel, /*.read_frame */ FSConnection::read_audio_frame, @@ -64,7 +67,7 @@ static switch_state_handler_table_t opalfs_event_handlers = { /*.on_init */ FSConnection::on_init, /*.on_routing */ FSConnection::on_routing, /*.on_execute */ FSConnection::on_execute, - /*.on_hangup */ FSConnection::on_hangup, + /*.on_hangup */ on_hangup, /*.on_loopback */ FSConnection::on_loopback, /*.on_transmit */ FSConnection::on_transmit }; @@ -486,14 +489,19 @@ OpalLocalConnection *FSEndPoint::CreateConnection(OpalCall & call, void *userDat /////////////////////////////////////////////////////////////////////// + FSConnection::FSConnection(OpalCall & call, FSEndPoint & endpoint) : OpalLocalConnection(call, endpoint, NULL) , m_endpoint(endpoint) { + opal_private_t *tech_pvt; FSManager & mgr = (FSManager &) endpoint.GetManager(); m_fsSession = switch_core_session_request(mgr.GetSwitchInterface(), NULL); m_fsChannel = switch_core_session_get_channel(m_fsSession); - switch_core_session_set_private(m_fsSession, this); + + tech_pvt = (opal_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt)); + tech_pvt->me = this; + switch_core_session_set_private(m_fsSession, tech_pvt); } @@ -568,11 +576,16 @@ bool FSConnection::OnIncoming() void FSConnection::OnReleased() { + opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession); + + /* so FS on_hangup will not try to deref a landmine */ + tech_pvt->me = NULL; + m_rxAudioOpened.Signal(); // Just in case m_txAudioOpened.Signal(); H225_ReleaseCompleteReason dummy; switch_channel_hangup(switch_core_session_get_channel(m_fsSession), - (switch_call_cause_t)H323TranslateFromCallEndReason(GetCallEndReason(), dummy)); + (switch_call_cause_t)H323TranslateFromCallEndReason(GetCallEndReason(), dummy)); OpalLocalConnection::OnReleased(); } @@ -752,16 +765,49 @@ switch_status_t FSConnection::on_execute() } -switch_status_t FSConnection::on_hangup() +/* this function has to be called with the original session beause the FSConnection might already be destroyed and we + will can't have it be a method of a dead object + */ +static switch_status_t on_hangup(switch_core_session_t *session) { - switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); - if (channel == NULL) { - return SWITCH_STATUS_FALSE; + switch_channel_t *channel = switch_core_session_get_channel(session); + opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(session); + + /* if this is still here it was our idea to hangup not opal's */ + if (tech_pvt->me) { + Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel); + tech_pvt->me->SetQ931Cause(cause); + tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX)); + tech_pvt->me = NULL; + } + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); } - Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel); - SetQ931Cause(cause); - ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX)); + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + + if (tech_pvt->vid_read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->vid_read_codec); + } + + if (tech_pvt->vid_write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->vid_write_codec); + } + + if (tech_pvt->read_timer.timer_interface) { + switch_core_timer_destroy(&tech_pvt->read_timer); + } + + if (tech_pvt->vid_read_timer.timer_interface) { + switch_core_timer_destroy(&tech_pvt->vid_read_timer); + } + + switch_core_session_unset_read_codec(session); + switch_core_session_unset_write_codec(session); + return SWITCH_STATUS_SUCCESS; } @@ -808,8 +854,7 @@ switch_status_t FSConnection::send_dtmf(const switch_dtmf_t *dtmf) switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg) { - switch_core_session_t *session = GetSession(); - switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); /* @@ -969,13 +1014,15 @@ FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaF , m_callOnStart(true) { memset(&m_readFrame, 0, sizeof(m_readFrame)); - m_readFrame.codec = &m_switchCodec; + m_readFrame.codec = m_switchCodec; m_readFrame.flags = SFF_RAW_RTP; } PBoolean FSMediaStream::Open() { + opal_private_t *tech_pvt = (opal_private_t *) switch_core_session_get_private(m_fsSession); + if (IsOpen()) { return true; } @@ -993,13 +1040,21 @@ PBoolean FSMediaStream::Open() int ptime = mediaFormat.GetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption()) * mediaFormat.GetFrameTime() / mediaFormat.GetTimeUnits(); + + if (IsSink()) { + m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec; + m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer; + } else { + m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec; + } + // The following is performed on two different instances of this object. - if (switch_core_codec_init(&m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP + if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP mediaFormat.GetClockRate(), ptime, 1, // Channels SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { // Could not select a codecs using negotiated frames/packet, so try using default. - if (switch_core_codec_init(&m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP + if (switch_core_codec_init(m_switchCodec, mediaFormat.GetEncodingName(), NULL, // FMTP mediaFormat.GetClockRate(), 0, 1, // Channels SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { @@ -1020,24 +1075,25 @@ PBoolean FSMediaStream::Open() m_readFrame.rate = mediaFormat.GetClockRate(); if (isAudio) { - switch_core_session_set_read_codec(m_fsSession, &m_switchCodec); - if (switch_core_timer_init(&m_switchTimer, + switch_core_session_set_read_codec(m_fsSession, m_switchCodec); + if (switch_core_timer_init(m_switchTimer, "soft", - m_switchCodec.implementation->microseconds_per_packet / 1000, - m_switchCodec.implementation->samples_per_packet, + m_switchCodec->implementation->microseconds_per_packet / 1000, + m_switchCodec->implementation->samples_per_packet, switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { - switch_core_codec_destroy(&m_switchCodec); + switch_core_codec_destroy(m_switchCodec); + m_switchCodec = NULL; return false; } } else { - switch_core_session_set_video_read_codec(m_fsSession, &m_switchCodec); + switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec); switch_channel_set_flag(m_fsChannel, CF_VIDEO); } } else { if (isAudio) { - switch_core_session_set_write_codec(m_fsSession, &m_switchCodec); + switch_core_session_set_write_codec(m_fsSession, m_switchCodec); } else { - switch_core_session_set_video_write_codec(m_fsSession, &m_switchCodec); + switch_core_session_set_video_write_codec(m_fsSession, m_switchCodec); switch_channel_set_flag(m_fsChannel, CF_VIDEO); } } @@ -1053,36 +1109,11 @@ PBoolean FSMediaStream::Close() { if (!IsOpen()) return false; + + /* forget these FS will properly destroy them for us */ - bool isAudio; - - if (mediaFormat.GetMediaType() == OpalMediaType::Audio()) { - isAudio = true; - } else if (mediaFormat.GetMediaType() == OpalMediaType::Video()) { - isAudio = false; - } else { - return OpalMediaStream::Close(); - } - - if (IsSink()) { - if (isAudio) { - switch_core_session_unset_read_codec(m_fsSession); - switch_core_timer_destroy(&m_switchTimer); - } else { - switch_core_session_set_video_read_codec(m_fsSession, NULL); - } - - switch_core_codec_destroy(&m_switchCodec); - } else { - if (isAudio) - switch_core_session_unset_write_codec(m_fsSession); - else - switch_core_session_set_video_write_codec(m_fsSession, NULL); - switch_core_codec_destroy(&m_switchCodec); - } - - PTRACE(3, "mod_opal\tReset & destroyed " << (IsSink()? "read" : "write") - << ' ' << mediaFormat.GetMediaType() << " codec for connection " << *this); + m_switchTimer = NULL; + m_switchCodec = NULL; return OpalMediaStream::Close(); } @@ -1102,6 +1133,11 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags) { + + if (!m_switchCodec) { + return SWITCH_STATUS_FALSE; + } + if (m_callOnStart) { /* There is a race here... sometimes we make it here and GetPatch() is NULL @@ -1148,11 +1184,11 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag } } else { - if (!GetPatch()->GetSource().ReadPacket(m_readRTP)) { + if (!m_switchTimer || !GetPatch()->GetSource().ReadPacket(m_readRTP)) { return SWITCH_STATUS_FALSE; } - switch_core_timer_next(&m_switchTimer); + switch_core_timer_next(m_switchTimer); if (!(m_readFrame.datalen = m_readRTP.GetPayloadSize())) { m_readFrame.flags = SFF_CNG; @@ -1174,6 +1210,7 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag m_readFrame.m = (switch_bool_t) m_readRTP.GetMarker(); m_readFrame.seq = m_readRTP.GetSequenceNumber(); m_readFrame.ssrc = m_readRTP.GetSyncSource(); + m_readFrame.codec = m_switchCodec; *frame = &m_readFrame; return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_opal/mod_opal.h b/src/mod/endpoints/mod_opal/mod_opal.h index fc9d91b7fb..24d7367d82 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.h +++ b/src/mod/endpoints/mod_opal/mod_opal.h @@ -106,6 +106,18 @@ class FSManager : public OpalManager { 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); @@ -117,23 +129,25 @@ class FSEndPoint:public 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 { @@ -156,7 +170,8 @@ 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); @@ -206,8 +221,8 @@ class FSMediaStream:public OpalMediaStream { 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;