141
130
///////////////////////////////////////////////////////////////////////////
142
131
LinphoneVoiceChannel::LinphoneVoiceChannel(LinphoneMediaEngine*eng)
149
138
talk_base::Thread *thread = talk_base::ThreadManager::Instance()->CurrentThread();
150
139
talk_base::SocketServer *ss = thread->socketserver();
151
141
socket_.reset(ss->CreateAsyncSocket(SOCK_DGRAM));
153
142
socket_->Bind(talk_base::SocketAddress("localhost", 0)); /* 0 means that OS will choose some free port */
154
port1 = socket_->GetLocalAddress().port(); /* and here we get port choosed by OS */
143
captport = socket_->GetLocalAddress().port(); /* and here we get port choosed by OS */
156
144
socket_->SignalReadEvent.connect(this, &LinphoneVoiceChannel::OnIncomingData);
146
socketRtcp_.reset(ss->CreateAsyncSocket(SOCK_DGRAM));
147
socketRtcp_->Bind(talk_base::SocketAddress("localhost", captport+1));
148
socketRtcp_->SignalReadEvent.connect(this, &LinphoneVoiceChannel::OnIncomingRtcp);
150
playport = PORT_UNUSED;
151
playport2 = PORT_UNUSED;
154
ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
156
ortp_set_log_level_mask(ORTP_FATAL);
159
#ifdef MEDIASTREAMER_LESS_2_9
160
audio_stream_ = audio_stream_new(-1, 0); /* -1 means that function will choose some free port */
162
audio_stream_ = audio_stream_new(-1, -1, 0); /* -1 means that function will choose some free port */
160
167
LinphoneVoiceChannel::~LinphoneVoiceChannel()
166
audio_stream_stop(audio_stream_);
171
audio_stream_stop(audio_stream_);
169
174
bool LinphoneVoiceChannel::SetPlayout(bool playout) {
189
#if defined(MEDIASTREAMER_LESS_2_11) && !defined(MEDIASTREAMER_LESS_2_9)
190
static inline int rtp_session_get_local_rtcp_port(const RtpSession *session) {
191
return (session->rtcp.loc_port>0) ? session->rtcp.loc_port : -1;
184
195
bool LinphoneVoiceChannel::SetSendCodecs(const std::vector<AudioCodec>& codecs) {
187
std::vector<AudioCodec>::const_iterator i;
189
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
191
for (i = codecs.begin(); i < codecs.end(); i++) {
193
if (!engine_->FindAudioCodec(*i))
195
if (engine_->have_ilbc && i->name == payload_type_ilbc.mime_type) {
197
std::vector<AudioCodec>::const_iterator i;
201
for (i = codecs.begin(); i < codecs.end(); i++) {
203
if (!engine_->FindAudioCodec(*i)) {
204
LOG(LS_INFO) << "Codec " << i->name << "/" << i->clockrate << " is not supported";
208
LOG(LS_INFO) << "Using " << i->name << "/" << i->clockrate;
215
// We're being asked to set an empty list of codecs. This will only happen when
216
// working with a buggy client; let's try PCMU.
217
LOG(LS_WARNING) << "Received empty list of codces; using PCMU/8000";
221
if (pt_ != -1 && profile_ && playport == PORT_UNUSED)
228
bool LinphoneVoiceChannel::SetRecvCodecs(const std::vector<AudioCodec>& codecs) {
230
std::vector<AudioCodec>::const_iterator i;
234
for (i = codecs.begin(); i < codecs.end(); i++) {
236
if (!engine_->FindAudioCodec(*i)) {
237
LOG(LS_INFO) << "Codec " << i->name << "/" << i->clockrate << " is not supported";
241
if (engine_->have_ilbc && stricmp(i->name.c_str(), payload_type_ilbc.mime_type) == 0)
196
242
rtp_profile_set_payload(&av_profile, i->id, &payload_type_ilbc);
197
} else if (engine_->have_speex && i->name == payload_type_speex_wb.mime_type && i->clockrate == payload_type_speex_wb.clock_rate) {
243
else if (engine_->have_speex && stricmp(i->name.c_str(), payload_type_speex_wb.mime_type) == 0 && i->clockrate == payload_type_speex_wb.clock_rate)
198
244
rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_wb);
199
} else if (engine_->have_speex && i->name == payload_type_speex_nb.mime_type && i->clockrate == payload_type_speex_nb.clock_rate) {
245
else if (engine_->have_speex && stricmp(i->name.c_str(), payload_type_speex_nb.mime_type) == 0 && i->clockrate == payload_type_speex_nb.clock_rate)
200
246
rtp_profile_set_payload(&av_profile, i->id, &payload_type_speex_nb);
201
} else if (engine_->have_gsm && i->name == payload_type_gsm.mime_type) {
247
else if (engine_->have_gsm && stricmp(i->name.c_str(), payload_type_gsm.mime_type) == 0)
202
248
rtp_profile_set_payload(&av_profile, i->id, &payload_type_gsm);
203
} else if (i->name == payload_type_telephone_event.mime_type) {
249
else if (stricmp(i->name.c_str(), payload_type_telephone_event.mime_type) == 0)
204
250
rtp_profile_set_payload(&av_profile, i->id, &payload_type_telephone_event);
205
} else if (i->id == 0)
206
252
rtp_profile_set_payload(&av_profile, 0, &payload_type_pcmu8000);
210
LOG(LS_INFO) << "Using " << i->name << "/" << i->clockrate;
212
audio_stream_ = audio_stream_start(&av_profile, -1, "localhost", port1, i->id, 250, 0); /* -1 means that function will choose some free port */
213
port2 = rtp_session_get_local_port(audio_stream_get_rtp_session(audio_stream_));
254
LOG(LS_INFO) << "Accepting " << i->name << "/" << i->clockrate;
220
260
// We're being asked to set an empty list of codecs. This will only happen when
221
261
// working with a buggy client; let's try PCMU.
222
LOG(LS_WARNING) << "Received empty list of codces; using PCMU/8000";
223
audio_stream_ = audio_stream_start(&av_profile, -1, "localhost", port1, 0, 250, 0); /* -1 means that function will choose some free port */
224
port2 = rtp_session_get_local_port(audio_stream_get_rtp_session(audio_stream_));
262
LOG(LS_WARNING) << "Received empty list of codces; accepting PCMU/8000";
263
rtp_profile_set_payload(&av_profile, 0, &payload_type_pcmu8000);
267
if (pt_ != -1 && profile_ && playport == PORT_UNUSED)
273
bool LinphoneVoiceChannel::StartCall()
277
MSSndCard *playcard = ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get());
281
MSSndCard *captcard = ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get());
285
if (audio_stream_start_now(audio_stream_, &av_profile, "localhost", captport, captport+1, pt_, 250, playcard, captcard, 0))
288
playport = rtp_session_get_local_port(audio_stream_get_rtp_session(audio_stream_));
290
#ifdef MEDIASTREAMER_LESS_2_9
291
playport2 = playport+1;
293
playport2 = rtp_session_get_local_rtcp_port(audio_stream_get_rtp_session(audio_stream_));
299
bool LinphoneVoiceChannel::AddSendStream(const cricket::StreamParams& st)
301
LOG(LS_INFO) << "linphone:: SET send stream ssrc: " << st.first_ssrc();
302
rtp_session_set_ssrc(audio_stream_get_rtp_session(audio_stream_), st.first_ssrc());
230
306
bool LinphoneVoiceChannel::SetSend(SendFlags flag) {
307
mute_ = (flag == SEND_NOTHING);
308
audio_stream_mute_rtp(audio_stream_, mute_);
312
bool LinphoneVoiceChannel::Mute(bool on) {
314
audio_stream_mute_rtp(audio_stream_, mute_);
235
318
void LinphoneVoiceChannel::OnPacketReceived(talk_base::Buffer* packet) {
236
const void* data = packet->data();
237
int len = packet->length();
239
memcpy(buf, data, len);
241
if (port2 == PORT_UNUSED)
319
if (playport == PORT_UNUSED)
244
322
/* We may receive packets with payload type 13: comfort noise. Linphone can't
245
323
* handle them, so let's ignore those packets.
247
int payloadtype = buf[1] & 0x7f;
325
int payloadtype = ((const uint8*)packet->data())[1] & 0x7f;
248
326
if (play_ && payloadtype != 13)
249
socket_->SendTo(buf, len, talk_base::SocketAddress("localhost",port2));
327
socket_->SendTo(packet->data(), packet->length(), talk_base::SocketAddress("localhost", playport));
330
void LinphoneVoiceChannel::OnRtcpReceived(talk_base::Buffer* packet) {
331
if (playport2 == PORT_UNUSED)
333
socketRtcp_->SendTo(packet->data(), packet->length(), talk_base::SocketAddress("localhost", playport2));
252
336
void LinphoneVoiceChannel::StartRing(bool bIncomingCall)