Contents of /tags/KDE/4.10.2/kdenetwork/kopete/protocols/jabber/googletalk/libjingle/talk/session/phone/linphonemediaengine.cc

Parent Directory Parent Directory | Revision Log 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)
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; }