audio_rtp_session.cpp 8.54 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */

35
36
#include "audio_rtp_session.h"
#include "audio_symmetric_rtp_session.h"
37
38

#include "sip/sdp.h"
39
#include "sip/sipcall.h"
40
41
42
#include "audio/audiolayer.h"
#include <ccrtp/rtp.h>
#include <ccrtp/oqueue.h>
43
#include "manager.h"
44

45
46
47
namespace sfl {
AudioRtpSession::AudioRtpSession(SIPCall * sipcall, RtpMethod type, ost::RTPDataQueue *queue, ost::Thread *thread) :
    AudioRtpRecordHandler(sipcall)
48
49
    , ca_(sipcall)
    , type_(type)
50
51
    , remote_ip_()
    , remote_port_(0)
52
53
54
55
56
57
    , timestamp_(0)
    , timestampIncrement_(0)
    , timestampCount_(0)
    , isStarted_(false)
    , queue_(queue)
    , thread_(thread)
58
{
59
60
    assert(ca_);
    queue_->setTypeOfService(ost::RTPDataQueue::tosEnhanced);
61
62
63
64
}

AudioRtpSession::~AudioRtpSession()
{
65
    queue_->disableStack();
66
67
}

68
void AudioRtpSession::updateSessionMedia(AudioCodec *audioCodec)
69
{
70
    int lastSamplingRate = audioRtpRecord_.codecSampleRate_;
71

72
    setSessionMedia(audioCodec);
73

74
    Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_);
75

76
    if (lastSamplingRate != audioRtpRecord_.codecSampleRate_) {
77
        DEBUG("AudioRtpSession: Update noise suppressor with sampling rate %d and frame size %d", getCodecSampleRate(), getCodecFrameSize());
78
        initNoiseSuppress();
79
80
81
82
    }

}

83
void AudioRtpSession::setSessionMedia(AudioCodec *audioCodec)
84
{
85
    setRtpMedia(audioCodec);
86
87
88
89
90
91
92

    // store codec info locally
    int payloadType = getCodecPayloadType();
    int frameSize = getCodecFrameSize();
    int smplRate = getCodecSampleRate();
    bool dynamic = getHasDynamicPayload();

93
    // G722 requires timestamp to be incremented at 8kHz
94
    if (payloadType == g722PayloadType)
95
        timestampIncrement_ = g722RtpTimeincrement;
96
    else
97
        timestampIncrement_ = frameSize;
98

99
100
101
102
    DEBUG("AudioRptSession: Codec payload: %d", payloadType);
    DEBUG("AudioSymmetricRtpSession: Codec sampling rate: %d", smplRate);
    DEBUG("AudioSymmetricRtpSession: Codec frame size: %d", frameSize);
    DEBUG("AudioSymmetricRtpSession: RTP timestamp increment: %d", timestampIncrement_);
103
104

    if (payloadType == g722PayloadType) {
105
        DEBUG("AudioSymmetricRtpSession: Setting G722 payload format");
106
        queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, g722RtpClockRate));
107
108
    } else {
        if (dynamic) {
109
            DEBUG("AudioSymmetricRtpSession: Setting dynamic payload format");
110
            queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, smplRate));
111
        } else {
112
            DEBUG("AudioSymmetricRtpSession: Setting static payload format");
113
            queue_->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) payloadType));
114
115
116
        }
    }

117
118
    if (type_ != Zrtp)
        ca_->setRecordingSmplRate(getCodecSampleRate());
119
120
}

121
void AudioRtpSession::sendDtmfEvent()
122
{
123
    ost::RTPPacket::RFC2833Payload payload;
124

125
    payload.event = audioRtpRecord_.dtmfQueue_.front();
126
127
128
129
    payload.ebit = false; // end of event bit
    payload.rbit = false; // reserved bit
    payload.duration = 1; // duration for this event

130
    audioRtpRecord_.dtmfQueue_.pop_front();
131

132
    DEBUG("AudioRtpSession: Send RTP Dtmf (%d)", payload.event);
133

134
    timestamp_ += (type_ == Zrtp) ? 160 : timestampIncrement_;
135
136
137
138
139

    // discard equivalent size of audio
    processDataEncode();

    // change Payload type for DTMF payload
140
    queue_->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) getDtmfPayloadType(), 8000));
141

142
143
144
    queue_->setMark(true);
    queue_->sendImmediate(timestamp_, (const unsigned char *)(&payload), sizeof(payload));
    queue_->setMark(false);
145
146

    // get back the payload to audio
147
    queue_->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) getCodecPayloadType()));
148
149
150
}


151
void AudioRtpSession::receiveSpeakerData()
152
{
153
    const ost::AppDataUnit* adu = queue_->getData(queue_->getFirstTimestamp());
154

155
    if (!adu)
156
157
        return;

158
159
    unsigned char* spkrDataIn = (unsigned char*) adu->getData(); // data in char
    unsigned int size = adu->getSize(); // size in char
160
161

    // DTMF over RTP, size must be over 4 in order to process it as voice data
162
    if (size > 4)
163
        processDataDecode(spkrDataIn, size, adu->getType());
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

    delete adu;
}



void AudioRtpSession::sendMicData()
{
    int compSize = processDataEncode();

    // if no data return
    if (!compSize)
        return;

    // Increment timestamp for outgoing packet
179
    timestamp_ += timestampIncrement_;
180

181
182
    if (type_ == Zrtp)
        queue_->putData(timestamp_, getMicDataEncoded(), compSize);
183

184
    // putData put the data on RTP queue, sendImmediate bypass this queue
185
    queue_->sendImmediate(timestamp_, getMicDataEncoded(), compSize);
186
187
188
}


189
void AudioRtpSession::setSessionTimeouts()
190
{
191
    DEBUG("AudioRtpSession: Set session scheduling timeout (%d) and expireTimeout (%d)", sfl::schedulingTimeout, sfl::expireTimeout);
192

193
194
    queue_->setSchedulingTimeout(sfl::schedulingTimeout);
    queue_->setExpireTimeout(sfl::expireTimeout);
195
196
}

197
void AudioRtpSession::setDestinationIpAddress()
198
199
{
    // Store remote ip in case we would need to forget current destination
200
    remote_ip_ = ost::InetHostAddress(ca_->getLocalSDP()->getRemoteIP().c_str());
201

202
    if (!remote_ip_) {
203
        WARN("AudioRtpSession: Target IP address (%s) is not correct!",
204
              ca_->getLocalSDP()->getRemoteIP().data());
205
206
207
208
        return;
    }

    // Store remote port in case we would need to forget current destination
209
    remote_port_ = (unsigned short) ca_->getLocalSDP()->getRemoteAudioPort();
210

Tristan Matthews's avatar
Tristan Matthews committed
211
    DEBUG("AudioRtpSession: New remote address for session: %s:%d",
212
          ca_->getLocalSDP()->getRemoteIP().data(), remote_port_);
213

214
    if (!queue_->addDestination(remote_ip_, remote_port_)) {
215
        WARN("AudioRtpSession: Can't add new destination to session!");
216
217
218
219
        return;
    }
}

220
void AudioRtpSession::updateDestinationIpAddress()
221
{
222
    DEBUG("AudioRtpSession: Update destination ip address");
223
224
225
226

    // Destination address are stored in a list in ccrtp
    // This method remove the current destination entry

227
    if (!queue_->forgetDestination(remote_ip_, remote_port_, remote_port_ + 1))
228
        DEBUG("AudioRtpSession: Did not remove previous destination");
229
230
231
232
233
234
235

    // new destination is stored in call
    // we just need to recall this method
    setDestinationIpAddress();
}


236
int AudioRtpSession::startRtpThread(AudioCodec* audiocodec)
237
{
238
    if (isStarted_)
239
240
        return 0;

241
    DEBUG("AudioSymmetricRtpSession: Starting main thread");
242

243
    isStarted_ = true;
244
    setSessionTimeouts();
245
    setSessionMedia(audiocodec);
246
247
248
    initBuffers();
    initNoiseSuppress();

249
250
    queue_->enableStack();
    int ret = thread_->start();
251

252
    if (type_ == Zrtp)
253
        return ret;
254

255
256
257
    AudioSymmetricRtpSession *self = dynamic_cast<AudioSymmetricRtpSession*>(this);
    assert(self);
    return self->startSymmetricRtpThread();
258
259
260
}


261
bool AudioRtpSession::onRTPPacketRecv(ost::IncomingRTPPkt&)
262
263
264
265
266
267
{
    receiveSpeakerData();
    return true;
}

}