#ifndef __CALL_LEG_EVENTS_H #define __CALL_LEG_EVENTS_H // TODO: global event numbering enum { ConnectLeg = B2BMsgBody + 16, ReconnectLeg, ReplaceLeg, ReplaceInProgress, DisconnectLeg, ChangeRtpModeEventId, ResumeHeldLeg, ApplyPendingUpdatesEventId }; #define LAST_B2B_CALL_LEG_EVENT_ID ApplyPendingUpdatesEventId struct ConnectLegEvent: public B2BEvent { AmMimeBody body; string hdrs; unsigned int r_cseq; bool relayed_invite; // constructor from relayed INVITE request ConnectLegEvent(const AmSipRequest &_relayed_invite): B2BEvent(ConnectLeg), body(_relayed_invite.body), hdrs(_relayed_invite.hdrs), r_cseq(_relayed_invite.cseq), relayed_invite(true) { } // constructor from generated INVITE (for example blind call transfer) ConnectLegEvent(const string &_hdrs, const AmMimeBody &_body): B2BEvent(ConnectLeg), body(_body), hdrs(_hdrs), r_cseq(0), relayed_invite(false) { } }; /** B2B event which sends another event back if it was or was not processed. * (note that the back events need to be created in advance because we can not * use overriden virtual methods in destructor (which is the only place which * will be called for sure) */ struct ReliableB2BEvent: public B2BEvent { private: bool processed; B2BEvent *unprocessed_reply; //< reply to be sent back if the original event was not processed B2BEvent *processed_reply; //< event sent back if the original event was processed string sender; // sender will be filled when sending the event out public: ReliableB2BEvent(int ev_id, B2BEvent *_processed, B2BEvent *_unprocessed): B2BEvent(ev_id), processed(false), processed_reply(_processed), unprocessed_reply(_unprocessed) { } ReliableB2BEvent(int ev_id, B2BEventType ev_type, B2BEvent *_processed, B2BEvent *_unprocessed): B2BEvent(ev_id, ev_type), processed(false), processed_reply(_processed), unprocessed_reply(_unprocessed) { } void markAsProcessed() { processed = true; } void setSender(const string &tag) { sender = tag; } virtual ~ReliableB2BEvent(); }; struct ReconnectLegEvent: public ReliableB2BEvent { AmMimeBody body; string hdrs; unsigned int r_cseq; bool relayed_invite; AmB2BMedia *media; // avoid direct access to this AmB2BSession::RTPRelayMode rtp_mode; string session_tag; enum Role { A, B } role; // reconnect as A or B leg void setMedia(AmB2BMedia *m, AmB2BSession::RTPRelayMode _mode) { media = m; if (media) media->addReference(); rtp_mode = _mode; } ReconnectLegEvent(const string &tag, const AmSipRequest &relayed_invite): ReliableB2BEvent(ReconnectLeg, NULL, new B2BEvent(B2BTerminateLeg) /* TODO: choose a better one */), body(relayed_invite.body), hdrs(relayed_invite.hdrs), r_cseq(relayed_invite.cseq), relayed_invite(true), media(NULL), rtp_mode(AmB2BSession::RTP_Direct), session_tag(tag), role(B) // we have relayed_invite (only in A leg) thus reconnect as regular B leg { setSender(tag); } ReconnectLegEvent(Role _role, const string &tag, const string &_hdrs, const AmMimeBody &_body): ReliableB2BEvent(ReconnectLeg, NULL, new B2BEvent(B2BTerminateLeg) /* TODO: choose a better one */), body(_body), hdrs(_hdrs), r_cseq(0), relayed_invite(false), media(NULL), rtp_mode(AmB2BSession::RTP_Direct), session_tag(tag), role(_role) { setSender(tag); } virtual ~ReconnectLegEvent() { if (media) media->releaseReference(); } }; /** Call leg receiving ReplaceLegEvent should replace itself with call leg from * the event parameters. (it terminates itself and forwards ReconnectLegEvent to * the call leg identified by other_id) */ struct ReplaceLegEvent: public ReliableB2BEvent { private: ReconnectLegEvent *ev; public: ReplaceLegEvent(const string &tag, const AmSipRequest &relayed_invite, AmB2BMedia *m, AmB2BSession::RTPRelayMode mode): ReliableB2BEvent(ReplaceLeg, NULL, new B2BEvent(B2BTerminateLeg)) { ev = new ReconnectLegEvent(tag, relayed_invite); ev->setMedia(m, mode); setSender(tag); } ReplaceLegEvent(const string &tag, ReconnectLegEvent *e): ReliableB2BEvent(ReplaceLeg, NULL, new B2BEvent(B2BTerminateLeg)), ev(e) { setSender(tag); } ReconnectLegEvent *getReconnectEvent() { ReconnectLegEvent *e = ev; ev = NULL; return e; } virtual ~ReplaceLegEvent() { if (ev) delete ev; } }; struct ReplaceInProgressEvent: public B2BEvent { string dst_session; // session to be connected to ReplaceInProgressEvent(const string &_dst_session): B2BEvent(ReplaceInProgress), dst_session(_dst_session) { } }; struct DisconnectLegEvent: public B2BEvent { bool put_remote_on_hold; bool preserve_media_session; DisconnectLegEvent(bool _put_remote_on_hold, bool _preserve_media_session = false): B2BEvent(DisconnectLeg), put_remote_on_hold(_put_remote_on_hold), preserve_media_session(_preserve_media_session) { } }; /* we don't need to have 'reliable event' for this because we are always * connected to CallLeg, right? */ struct ChangeRtpModeEvent: public B2BEvent { AmB2BSession::RTPRelayMode new_mode; AmB2BMedia *media; // avoid direct access to this ChangeRtpModeEvent(AmB2BSession::RTPRelayMode _new_mode, AmB2BMedia *_media): B2BEvent(ChangeRtpModeEventId), new_mode(_new_mode), media(_media) { if (media) media->addReference(); } virtual ~ChangeRtpModeEvent() { if (media) media->releaseReference(); } }; struct ResumeHeldEvent: public B2BEvent { ResumeHeldEvent(): B2BEvent(ResumeHeldLeg) { } }; struct ApplyPendingUpdatesEvent: public B2BEvent { ApplyPendingUpdatesEvent(): B2BEvent(ApplyPendingUpdatesEventId) { } }; #endif