| /[KDE]/tags/KDE/4.10.2/kdenetwork/kopete/protocols/jabber/googletalk/libjingle/talk/session/phone/linphonemediaengine.cc |
Contents of /tags/KDE/4.10.2/kdenetwork/kopete/protocols/jabber/googletalk/libjingle/talk/session/phone/linphonemediaengine.cc
Parent Directory
|
Revision Log
Revision 1347869 -
(show annotations)
(download)
(as text)
Wed Apr 3 15:28:45 2013 UTC (10 years, 7 months ago) by tnyblom
File MIME type: text/x-c++src
File size: 8204 byte(s)
Wed Apr 3 15:28:45 2013 UTC (10 years, 7 months ago) by tnyblom
File MIME type: text/x-c++src
File size: 8204 byte(s)
4.10.2
| 1 | /* |
| 2 | * Jingle call example |
| 3 | * Copyright 2004--2005, Google Inc. |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ |
| 19 | |
| 20 | #ifdef HAVE_CONFIG_H |
| 21 | #include <config.h> |
| 22 | #endif |
| 23 | |
| 24 | #define PORT_UNUSED -1 |
| 25 | |
| 26 | // LinphoneMediaEngine is a Linphone implementation of MediaEngine |
| 27 | extern "C" { |
| 28 | #include <mediastreamer2/mediastream.h> |
| 29 | #include <mediastreamer2/mssndcard.h> |
| 30 | #include <mediastreamer2/msfilter.h> |
| 31 | } |
| 32 | |
| 33 | #include <ortp/ortp.h> |
| 34 | #include <ortp/telephonyevents.h> |
| 35 | #include <netdb.h> |
| 36 | #include <unistd.h> |
| 37 | #include <fcntl.h> |
| 38 | #include <iostream> |
| 39 | #include "talk/base/logging.h" |
| 40 | #include "talk/base/thread.h" |
| 41 | #include "talk/session/phone/codec.h" |
| 42 | #include "talk/session/phone/linphonemediaengine.h" |
| 43 | |
| 44 | using namespace cricket; |
| 45 | |
| 46 | void LinphoneMediaChannel::OnIncomingData(talk_base::AsyncSocket *s) |
| 47 | { |
| 48 | char *buf[2048]; |
| 49 | int len; |
| 50 | len = s->Recv(buf, sizeof(buf)); |
| 51 | if (network_interface_ && !mute_) |
| 52 | network_interface_->SendPacket(buf, len); |
| 53 | } |
| 54 | |
| 55 | LinphoneMediaChannel::LinphoneMediaChannel(LinphoneMediaEngine*eng) : |
| 56 | pt_(-1), |
| 57 | audio_stream_(0), |
| 58 | engine_(eng), |
| 59 | ring_stream_(0) |
| 60 | { |
| 61 | |
| 62 | talk_base::Thread *thread = talk_base::ThreadManager::CurrentThread(); |
| 63 | talk_base::SocketServer *ss = thread->socketserver(); |
| 64 | socket_.reset(ss->CreateAsyncSocket(SOCK_DGRAM)); |
| 65 | |
| 66 | socket_->Bind(talk_base::SocketAddress("localhost", 0)); /* 0 means that OS will choose some free port */ |
| 67 | port1 = socket_->GetLocalAddress().port(); /* and here we get port choosed by OS */ |
| 68 | port2 = PORT_UNUSED; |
| 69 | socket_->SignalReadEvent.connect(this, &LinphoneMediaChannel::OnIncomingData); |
| 70 | } |
| 71 | |
| 72 | LinphoneMediaChannel::~LinphoneMediaChannel() { |
| 73 | |
| 74 | |
| 75 | //bjd |
| 76 | fflush(stdout); |
| 77 | StopRing(); |
| 78 | |
| 79 | if (audio_stream_) |
| 80 | audio_stream_stop(audio_stream_); |
| 81 | } |
| 82 | |
| 83 | void LinphoneMediaChannel::StartRing(bool bIncomingCall) |
| 84 | { |
| 85 | MSSndCard *sndcard = NULL; |
| 86 | sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); |
| 87 | if (sndcard) |
| 88 | { |
| 89 | if (bIncomingCall) |
| 90 | { |
| 91 | if (engine_->GetRingWav().size() > 0) |
| 92 | { |
| 93 | LOG(LS_VERBOSE) << "incoming ring. sound file: " << engine_->GetRingWav().c_str() << "\n"; |
| 94 | ring_stream_ = ring_start (engine_->GetRingWav().c_str(), 1, sndcard); |
| 95 | } |
| 96 | } |
| 97 | else |
| 98 | { |
| 99 | if (engine_->GetCallWav().size() > 0) |
| 100 | { |
| 101 | LOG(LS_VERBOSE) << "outgoing ring. sound file: " << engine_->GetCallWav().c_str() << "\n"; |
| 102 | ring_stream_ = ring_start (engine_->GetCallWav().c_str(), 1, sndcard); |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | void LinphoneMediaChannel::StopRing() |
| 109 | { |
| 110 | if (ring_stream_) { |
| 111 | ring_stop(ring_stream_); |
| 112 | ring_stream_ = 0; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | |
| 117 | void LinphoneMediaChannel::SetCodecs(const std::vector<Codec> &codecs) { |
| 118 | bool first = true; |
| 119 | std::vector<Codec>::const_iterator i; |
| 120 | |
| 121 | ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); |
| 122 | |
| 123 | for (i = codecs.begin(); i < codecs.end(); i++) { |
| 124 | |
| 125 | if (!engine_->FindCodec(*i)) |
| 126 | continue; |
| 127 | if (engine_->have_ilbc && i->name == payload_type_ilbc.mime_type) { |
| 128 | rtp_profile_set_payload(&av_profile, i->id, &payload_type_ilbc); |
| 129 | } else if (engine_->have_speex && i->name == payload_type_speex_wb.mime_type && i->clockrate == payload_type_speex_wb.clock_rate) { |
| 130 | rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_wb); |
| 131 | } else if (engine_->have_speex && i->name == payload_type_speex_nb.mime_type && i->clockrate == payload_type_speex_nb.clock_rate) { |
| 132 | rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_nb); |
| 133 | } else if (engine_->have_gsm && i->name == payload_type_gsm.mime_type) { |
| 134 | rtp_profile_set_payload(&av_profile, i->id, &payload_type_gsm); |
| 135 | } else if (i->name == payload_type_telephone_event.mime_type) { |
| 136 | rtp_profile_set_payload(&av_profile, i->id, &payload_type_telephone_event); |
| 137 | } else if (i->id == 0) { |
| 138 | rtp_profile_set_payload(&av_profile, 0, &payload_type_pcmu8000); |
| 139 | } |
| 140 | |
| 141 | if (first) { |
| 142 | StopRing(); |
| 143 | LOG(LS_INFO) << "Using " << i->name << "/" << i->clockrate; |
| 144 | pt_ = i->id; |
| 145 | audio_stream_ = audio_stream_start(&av_profile, -1, "localhost", port1, i->id, 250, 0); /* -1 means that function will choose some free port */ |
| 146 | port2 = rtp_session_get_local_port(audio_stream_->session); |
| 147 | first = false; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | if (first) { |
| 152 | StopRing(); |
| 153 | // We're being asked to set an empty list of codecs. This will only happen when |
| 154 | // working with a buggy client; let's try PCMU. |
| 155 | LOG(LS_WARNING) << "Received empty list of codces; using PCMU/8000"; |
| 156 | audio_stream_ = audio_stream_start(&av_profile, -1, "localhost", port1, 0, 250, 0); /* -1 means that function will choose some free port */ |
| 157 | port2 = rtp_session_get_local_port(audio_stream_->session); |
| 158 | } |
| 159 | |
| 160 | } |
| 161 | |
| 162 | bool LinphoneMediaEngine::FindCodec(const Codec &c) { |
| 163 | if (c.id == 0) |
| 164 | return true; |
| 165 | if (c.name == payload_type_telephone_event.mime_type) |
| 166 | return true; |
| 167 | if (have_speex && c.name == payload_type_speex_wb.mime_type && c.clockrate == payload_type_speex_wb.clock_rate) |
| 168 | return true; |
| 169 | if (have_speex && c.name == payload_type_speex_nb.mime_type && c.clockrate == payload_type_speex_nb.clock_rate) |
| 170 | return true; |
| 171 | if (have_ilbc && c.name == payload_type_ilbc.mime_type) |
| 172 | return true; |
| 173 | if (have_gsm && c.name == payload_type_gsm.mime_type) |
| 174 | return true; |
| 175 | return false; |
| 176 | } |
| 177 | |
| 178 | void LinphoneMediaChannel::OnPacketReceived(const void *data, int len) { |
| 179 | uint8 buf[2048]; |
| 180 | memcpy(buf, data, len); |
| 181 | |
| 182 | if (port2 == PORT_UNUSED) |
| 183 | return; |
| 184 | |
| 185 | /* We may receive packets with payload type 13: comfort noise. Linphone can't |
| 186 | * handle them, so let's ignore those packets. |
| 187 | */ |
| 188 | int payloadtype = buf[1] & 0x7f; |
| 189 | if (play_ && payloadtype != 13) |
| 190 | socket_->SendTo(buf, len, talk_base::SocketAddress("localhost",port2)); |
| 191 | } |
| 192 | |
| 193 | void LinphoneMediaChannel::SetPlayout(bool playout) { |
| 194 | play_ = playout; |
| 195 | } |
| 196 | |
| 197 | void LinphoneMediaChannel::SetSend(bool send) { |
| 198 | mute_ = !send; |
| 199 | } |
| 200 | |
| 201 | int LinphoneMediaChannel::GetOutputLevel() { return 0; } |
| 202 | |
| 203 | LinphoneMediaEngine::LinphoneMediaEngine(const std::string& ringWav, const std::string& callWav) |
| 204 | : ring_wav_(ringWav), |
| 205 | call_wav_(callWav) |
| 206 | { |
| 207 | ortp_init(); |
| 208 | ms_init(); |
| 209 | |
| 210 | if (ms_filter_codec_supported("speex")) |
| 211 | have_speex = true; |
| 212 | else |
| 213 | have_speex = false; |
| 214 | |
| 215 | if (ms_filter_codec_supported("iLBC")) |
| 216 | have_ilbc = true; |
| 217 | else |
| 218 | have_ilbc = false; |
| 219 | |
| 220 | if (ms_filter_codec_supported("gsm")) |
| 221 | have_gsm = true; |
| 222 | else |
| 223 | have_gsm = false; |
| 224 | |
| 225 | if (have_speex) { |
| 226 | codecs_.push_back(Codec(110, payload_type_speex_wb.mime_type, payload_type_speex_wb.clock_rate, 0, 1, 8)); |
| 227 | codecs_.push_back(Codec(111, payload_type_speex_nb.mime_type, payload_type_speex_nb.clock_rate, 0, 1, 7)); |
| 228 | } |
| 229 | |
| 230 | if (have_ilbc) |
| 231 | codecs_.push_back(Codec(102, payload_type_ilbc.mime_type, payload_type_ilbc.clock_rate, 0, 1, 4)); |
| 232 | |
| 233 | if (have_gsm) |
| 234 | codecs_.push_back(Codec(3, payload_type_gsm.mime_type, payload_type_gsm.clock_rate, 0, 1, 3)); |
| 235 | |
| 236 | codecs_.push_back(Codec(0, payload_type_pcmu8000.mime_type, payload_type_pcmu8000.clock_rate, 0, 1, 2)); |
| 237 | codecs_.push_back(Codec(101, payload_type_telephone_event.mime_type, payload_type_telephone_event.clock_rate, 0, 1, 1)); |
| 238 | } |
| 239 | |
| 240 | LinphoneMediaEngine::~LinphoneMediaEngine() {} |
| 241 | |
| 242 | void LinphoneMediaEngine::Terminate() { |
| 243 | fflush(stdout); |
| 244 | } |
| 245 | |
| 246 | MediaChannel *LinphoneMediaEngine::CreateChannel() { |
| 247 | return new LinphoneMediaChannel(this); |
| 248 | } |
| 249 | |
| 250 | int LinphoneMediaEngine::SetAudioOptions(int options) { return 0; } |
| 251 | int LinphoneMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device) { return 0; } |
| 252 | |
| 253 | float LinphoneMediaEngine::GetCurrentQuality() { return 0; } |
| 254 | int LinphoneMediaEngine::GetInputLevel() { return 0; } |
The KDE Source Repository
Full Width