diff --git a/core/AmAudio.cpp b/core/AmAudio.cpp index 65cf9028..2bd1656a 100644 --- a/core/AmAudio.cpp +++ b/core/AmAudio.cpp @@ -28,6 +28,7 @@ #include "AmAudio.h" #include "AmPlugIn.h" #include "AmUtils.h" +#include "AmSdp.h" #include "amci/codecs.h" #include "log.h" @@ -38,19 +39,89 @@ #include -AmAudioRtpFormat::AmAudioRtpFormat(int payload, string format_parameters) - : AmAudioFormat(), payload(payload), amci_pl(0) +struct CodecContainer { - sdp_format_parameters = format_parameters; - codec = getCodec(); - - amci_payload_t* pl = getPayloadP(); - if(pl && codec){ - channels = pl->channels; - rate = pl->sample_rate; - } else { - ERROR("Could not find payload <%i>\n",payload); - } + amci_codec_t *codec; + int frame_size; + int frame_length; + int frame_encoded_size; + long h_codec; +}; + +AmAudioRtpFormat::AmAudioRtpFormat(const vector& payloads) + : AmAudioFormat(), m_payloads(payloads), m_currentPayload(-1) +{ + for (vector::iterator it = m_payloads.begin(); + it != m_payloads.end(); ++it) + { + m_sdpPayloadByPayload[(*it)->payload_type] = *it; + } + setCurrentPayload(m_payloads[0]->payload_type); +} + +void AmAudioRtpFormat::setCurrentPayload(int payload) +{ + if (m_currentPayload != payload) + { + map::iterator p = m_sdpPayloadByPayload.find(payload); + if (p == m_sdpPayloadByPayload.end()) + { + ERROR("Could not find payload <%i>\n", payload); + return; + } + map::iterator pp = m_payloadPByPayload.find(payload); + if (pp == m_payloadPByPayload.end()) + { + m_currentPayloadP = AmPlugIn::instance()->payload(p->second->int_pt); + if (m_currentPayloadP == NULL) + { + ERROR("Could not find payload <%i>\n", payload); + return; + } + m_payloadPByPayload[payload] = m_currentPayloadP; + } + else + m_currentPayloadP = pp->second; + m_currentPayload = payload; + sdp_format_parameters = p->second->sdp_format_parameters; + + map::iterator c = m_codecContainerByPayload.find(payload); + if (c == m_codecContainerByPayload.end()) + { + codec = NULL; + getCodec(); + if (codec) + { + CodecContainer *cc = new CodecContainer(); + cc->codec = codec; + cc->frame_size = frame_size; + cc->frame_length = frame_length; + cc->frame_encoded_size = frame_encoded_size; + cc->h_codec = h_codec; + m_codecContainerByPayload[payload] = cc; + } + } + else + { + codec = c->second->codec; + frame_size = c->second->frame_size; + frame_length = c->second->frame_length; + frame_encoded_size = c->second->frame_encoded_size; + h_codec = c->second->h_codec; + } + if (m_currentPayloadP && codec) { + channels = m_currentPayloadP->channels; + rate = m_currentPayloadP->sample_rate; + } else { + ERROR("Could not find payload <%i>\n", payload); + } + } +} + +AmAudioRtpFormat::~AmAudioRtpFormat() +{ + for (map::iterator it = m_codecContainerByPayload.begin(); it != m_codecContainerByPayload.end(); ++it) + delete it->second; } AmAudioFormat::AmAudioFormat() @@ -677,22 +748,12 @@ int AmAudioFileFormat::getCodecId() } -amci_payload_t* AmAudioRtpFormat::getPayloadP() -{ - if(!amci_pl) - amci_pl = AmPlugIn::instance()->payload(payload); - - return amci_pl; -} - int AmAudioRtpFormat::getCodecId() { - amci_payload_t* pl = getPayloadP(); - if(!pl){ - ERROR("AmAudioRtpFormat::getCodecId: could not find payload %i\n",payload); + if(!m_currentPayloadP){ + ERROR("AmAudioRtpFormat::getCodecId: could not find payload %i\n", m_currentPayload); return -1; } else - return pl->codec_id; + return m_currentPayloadP->codec_id; } - diff --git a/core/AmAudio.h b/core/AmAudio.h index 4301c015..59ba8a97 100644 --- a/core/AmAudio.h +++ b/core/AmAudio.h @@ -38,10 +38,15 @@ using std::auto_ptr; #include using std::string; +#include +using std::map; #define PCM16_B2S(b) ((b) >> 1) #define PCM16_S2B(s) ((s) << 1) +class SdpPayload; +class CodecContainer; + /** \brief Audio Event */ class AmAudioEvent: public AmEvent { @@ -206,14 +211,15 @@ public: /** \brief RTP audio format */ class AmAudioRtpFormat: public AmAudioFormat { - /** ==-1 if not yet initialized. */ - int payload; - /** == 0 if not yet initialized. */ - amci_payload_t* amci_pl; + vector m_payloads; + int m_currentPayload; + amci_payload_t *m_currentPayloadP; + map m_sdpPayloadByPayload; + map m_payloadPByPayload; + map m_codecContainerByPayload; protected: int getCodecId(); - amci_payload_t* getPayloadP(); public: /** @@ -221,10 +227,10 @@ public: * All the information are taken from the * payload description in the originating plug-in. */ - AmAudioRtpFormat(int payload, string format_parameters); + AmAudioRtpFormat(const vector& payloads); + ~AmAudioRtpFormat(); - /** @return Payload ID. */ - int getPayload() { return payload; } + void setCurrentPayload(int payload); }; /** diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp index 448fc90c..9504d342 100644 --- a/core/AmConfig.cpp +++ b/core/AmConfig.cpp @@ -55,6 +55,7 @@ int AmConfig::MediaProcessorThreads = NUM_MEDIA_PROCESSORS; int AmConfig::LocalSIPPort = 5060; string AmConfig::LocalSIPIP = ""; string AmConfig::Signature = ""; +bool AmConfig::SingleCodecInOK = false; AmSessionTimerConfig AmConfig::defaultSessionTimerConfig; @@ -237,6 +238,10 @@ int AmConfig::readConfiguration() return -1; } } + // single codec in 200 OK + if(cfg.hasParameter("single_codec_in_ok")){ + SingleCodecInOK = (cfg.getParameter("single_codec_in_ok") == "yes"); + } return defaultSessionTimerConfig.readFromConfig(cfg); } diff --git a/core/AmConfig.h b/core/AmConfig.h index d56a1fb7..4c4a7570 100644 --- a/core/AmConfig.h +++ b/core/AmConfig.h @@ -85,6 +85,8 @@ struct AmConfig static int LocalSIPPort; /** Server/User-Agent header (optional) */ static string Signature; + /** If 200 OK reply should be limited to preferred codec only */ + static bool SingleCodecInOK; /** Init function. Resolves SMTP server address. */ static int init(); diff --git a/core/AmRtpAudio.cpp b/core/AmRtpAudio.cpp index 491f4519..9a31c497 100644 --- a/core/AmRtpAudio.cpp +++ b/core/AmRtpAudio.cpp @@ -77,10 +77,14 @@ int AmRtpAudio::receive(unsigned int audio_buffer_ts) unsigned int rtp_ts; while(true) { + int payload; size = AmRtpStream::receive((unsigned char*)samples, - (unsigned int)AUDIO_BUFFER_SIZE, rtp_ts); + (unsigned int)AUDIO_BUFFER_SIZE, rtp_ts, + payload); if(size <= 0) break; + + setCurrentPayload(payload); if(send_only){ playout_buffer->clearLastTs(); @@ -122,12 +126,16 @@ int AmRtpAudio::write(unsigned int user_ts, unsigned int size) return send(user_ts,(unsigned char*)samples,size); } -void AmRtpAudio::init(const SdpPayload* sdp_payload) +void AmRtpAudio::init(const vector& sdp_payloads) { DBG("AmRtpAudio::init(...)\n"); - AmRtpStream::init(sdp_payload); - fmt.reset(new AmAudioRtpFormat(int_payload, format_parameters)); + AmRtpStream::init(sdp_payloads); + fmt.reset(new AmAudioRtpFormat(sdp_payloads)); +} +void AmRtpAudio::setCurrentPayload(int payload) +{ + ((AmAudioRtpFormat *) fmt.get())->setCurrentPayload(payload); amci_codec_t* codec = fmt->getCodec(); use_default_plc = !(codec && codec->plc); } diff --git a/core/AmRtpAudio.h b/core/AmRtpAudio.h index 77873510..ebc3fa5e 100644 --- a/core/AmRtpAudio.h +++ b/core/AmRtpAudio.h @@ -70,6 +70,8 @@ public: bool checkInterval(unsigned int ts); bool sendIntReached(); + void setCurrentPayload(int payload); + int receive(unsigned int audio_buffer_ts); void setSendOnly(bool so){ @@ -84,7 +86,7 @@ public: unsigned int nb_samples); // AmRtpStream interface - void init(const SdpPayload* sdp_payload); + void init(const vector& sdp_payloads); void setPlayoutType(PlayoutType type); diff --git a/core/AmRtpStream.cpp b/core/AmRtpStream.cpp index 041bf0bc..548add2b 100644 --- a/core/AmRtpStream.cpp +++ b/core/AmRtpStream.cpp @@ -193,7 +193,7 @@ int AmRtpStream::send( unsigned int ts, unsigned char* buffer, unsigned int size // @param audio_buffer_ts [in] current ts at the audio_buffer int AmRtpStream::receive( unsigned char* buffer, unsigned int size, - unsigned int& ts) + unsigned int& ts, int &out_payload) { AmRtpPacket rp; int err = nextPacket(rp); @@ -247,9 +247,11 @@ int AmRtpStream::receive( unsigned char* buffer, unsigned int size, return RTP_DTMF; } +/* if (payload != rp.payload){ return RTP_UNKNOWN_PL; } +*/ assert(rp.getData()); if(rp.getDataSize() > size){ @@ -258,6 +260,7 @@ int AmRtpStream::receive( unsigned char* buffer, unsigned int size, } memcpy(buffer,rp.getData(),rp.getDataSize()); ts = rp.timestamp; + out_payload = rp.payload; return rp.getDataSize(); } @@ -361,15 +364,12 @@ void AmRtpStream::setRAddr(const string& addr, unsigned short port) #endif } -void AmRtpStream::init(const SdpPayload* sdp_payload) +void AmRtpStream::init(const vector& sdp_payloads) { + SdpPayload *sdp_payload = sdp_payloads[0]; payload = sdp_payload->payload_type; int_payload = sdp_payload->int_pt; last_payload = payload; - if(!sdp_payload->sdp_format_parameters.empty()) - format_parameters = sdp_payload->sdp_format_parameters; - else - format_parameters = ""; resume(); } diff --git a/core/AmRtpStream.h b/core/AmRtpStream.h index d1fe170d..094c8fc4 100644 --- a/core/AmRtpStream.h +++ b/core/AmRtpStream.h @@ -98,8 +98,6 @@ protected: */ int last_payload; - string format_parameters; - string r_host; unsigned short r_port; #ifdef SUPPORT_IPV6 @@ -153,7 +151,7 @@ public: int receive( unsigned char* buffer, unsigned int size, - unsigned int& ts); + unsigned int& ts, int& payload); /** Allocates resources for future use of RTP. */ AmRtpStream(AmSession* _s=0); @@ -211,7 +209,7 @@ public: * @warning It should be called only if the stream has been completly initialized, * @warning and only once per session. Use resume() then. */ - virtual void init(const SdpPayload* sdp_payload); + virtual void init(const vector& sdp_payloads); /** * Stops RTP stream. diff --git a/core/AmSdp.cpp b/core/AmSdp.cpp index 21ea4ba1..789bf691 100644 --- a/core/AmSdp.cpp +++ b/core/AmSdp.cpp @@ -185,7 +185,7 @@ int AmSdp::parse() int AmSdp::genResponse(const string& localip, int localport, - string& out_buf) + string& out_buf, bool single_codec) { string l_ip = "IP4 " + localip; @@ -218,6 +218,7 @@ int AmSdp::genResponse(const string& localip, int localport, options += "a=fmtp:" + int2str((*it)->payload_type) + " " + (*it)->sdp_format_parameters + "\r\n"; } + if (single_codec) break; } if (hasTelephoneEvent()) @@ -286,10 +287,11 @@ int AmSdp::genRequest(const string& localip,int localport, string& out_buf) return 0; } -SdpPayload* AmSdp::getCompatiblePayload(int media_type, string& addr, int& port) +const vector& AmSdp::getCompatiblePayloads(int media_type, string& addr, int& port) { vector::iterator m_it; - SdpPayload* payload=0; + SdpPayload *payload; + sup_pl.clear(); AmPlugIn* pi = AmPlugIn::instance(); @@ -313,7 +315,7 @@ SdpPayload* AmSdp::getCompatiblePayload(int media_type, string& addr, int& port) payload->int_pt = a_pl->payload_id; payload->encoding_name = a_pl->name; payload->clock_rate = a_pl->sample_rate; - goto end; + sup_pl.push_back(payload); } else { // Try dynamic payloads @@ -331,37 +333,30 @@ SdpPayload* AmSdp::getCompatiblePayload(int media_type, string& addr, int& port) payload = &(*it); payload->int_pt = int_pt; - goto end; + sup_pl.push_back(payload); } } } - } - - end: - sup_pl.clear(); - - if(payload){ - - DBG("payload found: %i/%s/%i\n", - payload->int_pt,payload->encoding_name.c_str(),payload->clock_rate); - - if(m_it->conn.address.empty()){ - DBG("using global address: %s\n",conn.address.c_str()); - addr = conn.address; - } - else { - DBG("using media specific address: %s\n",m_it->conn.address.c_str()); - addr = m_it->conn.address; + if (sup_pl.size() > 0) + { + if (m_it->conn.address.empty()) + { + DBG("using global address: %s\n",conn.address.c_str()); + addr = conn.address; + } + else { + DBG("using media specific address: %s\n",m_it->conn.address.c_str()); + addr = m_it->conn.address; + } + + if(m_it->dir == SdpMedia::DirActive) + remote_active = true; + + port = (int)m_it->port; } - - if(m_it->dir == SdpMedia::DirActive) - remote_active = true; - - sup_pl.push_back(payload); - port = (int)m_it->port; + break; } - - return payload; + return sup_pl; } bool AmSdp::hasTelephoneEvent() diff --git a/core/AmSdp.h b/core/AmSdp.h index f726b007..ada0e672 100644 --- a/core/AmSdp.h +++ b/core/AmSdp.h @@ -171,7 +171,7 @@ public: * @return !=0 if error encountered. */ int genResponse(const string& localip, int localport, - string& out_buf); + string& out_buf, bool single_codec = false); /** * Generate an SDP offer. @@ -181,9 +181,9 @@ public: /** * Get a compatible payload from SDP offer/response. - * @return NULL if error encountered. + * @return empty vector if error encountered. */ - SdpPayload* getCompatiblePayload(int media_type, string& addr, int& port); + const vector& getCompatiblePayloads(int media_type, string& addr, int& port); /** * Test if remote UA supports 'telefone_event'. diff --git a/core/AmSession.cpp b/core/AmSession.cpp index ce07f077..200794e7 100644 --- a/core/AmSession.cpp +++ b/core/AmSession.cpp @@ -125,7 +125,7 @@ AmSession::AmSession() dlg(this), detached(true), sess_stopped(false),rtp_str(this),negotiate_onreply(false), - input(0), output(0), payload(0), + input(0), output(0), m_dtmfDetector(this), m_dtmfEventQueue(&m_dtmfDetector), m_dtmfDetectionEnabled(true) { @@ -207,9 +207,9 @@ void AmSession::setLocalTag(const string& tag) dlg.local_tag = tag; } -const SdpPayload* AmSession::getPayload() +const vector& AmSession::getPayloads() { - return &payload; + return m_payloads; } int AmSession::getRPort() @@ -232,11 +232,12 @@ void AmSession::negotiate(const string& sdp_body, if(sdp.media.empty()) throw AmSession::Exception(400,"no media line found in SDP message"); - SdpPayload* tmp_pl = sdp.getCompatiblePayload(MT_AUDIO,r_host,r_port); + m_payloads = sdp.getCompatiblePayloads(MT_AUDIO, r_host, r_port); - if(!tmp_pl) + if (m_payloads.size() == 0) throw AmSession::Exception(606,"could not find compatible payload"); +/* if(payload.int_pt == -1){ payload = *tmp_pl; @@ -246,6 +247,7 @@ void AmSession::negotiate(const string& sdp_body, DBG("old payload: %i; new payload: %i\n",payload.int_pt,tmp_pl->int_pt); throw AmSession::Exception(400,"do not accept payload changes"); } +*/ const SdpPayload *telephone_event_payload = sdp.telephoneEventPayload(); if(telephone_event_payload) @@ -277,7 +279,7 @@ void AmSession::negotiate(const string& sdp_body, unlockAudio(); if(sdp_reply) - sdp.genResponse(AmConfig::LocalIP,rtp_str.getLocalPort(),*sdp_reply); + sdp.genResponse(AmConfig::LocalIP,rtp_str.getLocalPort(),*sdp_reply, AmConfig::SingleCodecInOK); } void AmSession::run() @@ -620,7 +622,7 @@ int AmSession::acceptAudio(const string& body, // enable RTP stream lockAudio(); - rtp_str.init(&payload); + rtp_str.init(m_payloads); unlockAudio(); DBG("Sending Rtp data to %s/%i\n", diff --git a/core/AmSession.h b/core/AmSession.h index 90852713..0e1e764a 100644 --- a/core/AmSession.h +++ b/core/AmSession.h @@ -108,7 +108,7 @@ class AmSession : public AmThread, AmAudio* input; AmAudio* output; - SdpPayload payload; + vector m_payloads; bool negotiate_onreply; AmDtmfDetector m_dtmfDetector; @@ -248,7 +248,7 @@ public: void setLocalTag(const string& tag); /** Gets the current RTP payload */ - const SdpPayload* getPayload(); + const vector& getPayloads(); /** Gets the port number of the remote part of the session */ int getRPort(); diff --git a/core/sems.conf.sample b/core/sems.conf.sample index 09514c39..8d7ae433 100644 --- a/core/sems.conf.sample +++ b/core/sems.conf.sample @@ -143,3 +143,11 @@ media_processor_threads=1 # # # signature="SEMS media server 1.0" + +# optional parameter: single_codec_in_ok={yes|no} +# +# - use single codec in 200 OK response +# +# default=no +# +# single_codec_in_ok=no