AudioRtpSession.cpp 8.57 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
35
36
37
38
39
40
41
 *  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.
 */

#include "AudioRtpSession.h"
#include "AudioSymmetricRtpSession.h"

#include "sip/sdp.h"
#include "audio/audiolayer.h"
#include <ccrtp/rtp.h>
#include <ccrtp/oqueue.h>
42
#include "manager.h"
43

44
45
46
47
48
49
50
51
52
53
54
namespace sfl {
AudioRtpSession::AudioRtpSession(SIPCall * sipcall, RtpMethod type, ost::RTPDataQueue *queue, ost::Thread *thread) :
    AudioRtpRecordHandler(sipcall)
    , _ca(sipcall)
    , _type(type)
    , _timestamp(0)
    , _timestampIncrement(0)
    , _timestampCount(0)
    , _isStarted(false)
    , _queue(queue)
    , _thread(thread)
55
{
56
57
    assert(_ca);
    _queue->setTypeOfService(ost::RTPDataQueue::tosEnhanced);
58
59
60
61
}

AudioRtpSession::~AudioRtpSession()
{
Rafaël Carré's avatar
Rafaël Carré committed
62
    _queue->disableStack();
63
64
}

65
void AudioRtpSession::updateSessionMedia(AudioCodec *audioCodec)
66
{
67
    int lastSamplingRate = _audioRtpRecord._codecSampleRate;
68

69
    setSessionMedia(audioCodec);
70

71
    Manager::instance().audioSamplingRateChanged(_audioRtpRecord._codecSampleRate);
72

73
    if (lastSamplingRate != _audioRtpRecord._codecSampleRate) {
74
        _debug("AudioRtpSession: Update noise suppressor with sampling rate %d and frame size %d", getCodecSampleRate(), getCodecFrameSize());
75
        initNoiseSuppress();
76
77
78
79
    }

}

80
void AudioRtpSession::setSessionMedia(AudioCodec *audioCodec)
81
{
82
    setRtpMedia(audioCodec);
83
84
85
86
87
88
89

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

90
    // G722 requires timestamp to be incremented at 8kHz
91
92
93
94
95
    if (payloadType == g722PayloadType)
        _timestampIncrement = g722RtpTimeincrement;
    else
        _timestampIncrement = frameSize;

96
97
98
99
    _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);
100
101

    if (payloadType == g722PayloadType) {
102
103
        _debug("AudioSymmetricRtpSession: Setting G722 payload format");
        _queue->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, g722RtpClockRate));
104
105
    } else {
        if (dynamic) {
106
107
            _debug("AudioSymmetricRtpSession: Setting dynamic payload format");
            _queue->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, smplRate));
108
        } else {
109
110
            _debug("AudioSymmetricRtpSession: Setting static payload format");
            _queue->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) payloadType));
111
112
113
        }
    }

114
    if (_type != Zrtp)
115
        _ca->setRecordingSmplRate(getCodecSampleRate());
116
117
}

118
void AudioRtpSession::sendDtmfEvent()
119
{
120
    ost::RTPPacket::RFC2833Payload payload;
121

122
123
124
125
126
127
128
    payload.event = _audioRtpRecord._dtmfQueue.front();
    payload.ebit = false; // end of event bit
    payload.rbit = false; // reserved bit
    payload.duration = 1; // duration for this event

    _audioRtpRecord._dtmfQueue.pop_front();

129
    _debug("AudioRtpSession: Send RTP Dtmf (%d)", payload.event);
130
131

    _timestamp += (_type == Zrtp) ? 160 : _timestampIncrement;
132
133
134
135
136

    // discard equivalent size of audio
    processDataEncode();

    // change Payload type for DTMF payload
137
    _queue->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) getDtmfPayloadType(), 8000));
138

139
140
141
    _queue->setMark(true);
    _queue->sendImmediate(_timestamp, (const unsigned char *)(&payload), sizeof(payload));
    _queue->setMark(false);
142
143

    // get back the payload to audio
144
    _queue->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) getCodecPayloadType()));
145
146
147
}


148
void AudioRtpSession::receiveSpeakerData()
149
{
150
151
    const ost::AppDataUnit* adu = _queue->getData(_queue->getFirstTimestamp());

152
    if (!adu)
153
154
        return;

155
156
    unsigned char* spkrDataIn = (unsigned char*) adu->getData(); // data in char
    unsigned int size = adu->getSize(); // size in char
157
158

    // DTMF over RTP, size must be over 4 in order to process it as voice data
159
    if (size > 4)
160
        processDataDecode(spkrDataIn, size, adu->getType());
161
162
163
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
    _timestamp += _timestampIncrement;

    if (_type == Zrtp)
179
180
        _queue->putData(_timestamp, getMicDataEncoded(), compSize);

181
    // putData put the data on RTP queue, sendImmediate bypass this queue
182
    _queue->sendImmediate(_timestamp, getMicDataEncoded(), compSize);
183
184
185
}


186
void AudioRtpSession::setSessionTimeouts(void)
187
{
188
    _debug("AudioRtpSession: Set session scheduling timeout (%d) and expireTimeout (%d)", sfl::schedulingTimeout, sfl::expireTimeout);
189

190
191
    _queue->setSchedulingTimeout(sfl::schedulingTimeout);
    _queue->setExpireTimeout(sfl::expireTimeout);
192
193
}

194
void AudioRtpSession::setDestinationIpAddress(void)
195
{
196
    _info("AudioRtpSession: Setting IP address for the RTP session");
197
198

    // Store remote ip in case we would need to forget current destination
199
    _remote_ip = ost::InetHostAddress(_ca->getLocalSDP()->getRemoteIP().c_str());
200
201

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

    // Store remote port in case we would need to forget current destination
    _remote_port = (unsigned short) _ca->getLocalSDP()->getRemoteAudioPort();

210
211
    _info("AudioRtpSession: New remote address for session: %s:%d",
          _ca->getLocalSDP()->getRemoteIP().data(), _remote_port);
212

213
214
    if (!_queue->addDestination(_remote_ip, _remote_port)) {
        _warn("AudioRtpSession: Can't add new destination to session!");
215
216
217
218
        return;
    }
}

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

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

226
    if (!_queue->forgetDestination(_remote_ip, _remote_port, _remote_port+1))
227
        _debug("AudioRtpSession: Did not remove previous destination");
228
229
230
231
232
233
234

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


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

240
    _debug("AudioSymmetricRtpSession: Starting main thread");
241
242
243

    _isStarted = true;
    setSessionTimeouts();
244
    setSessionMedia(audiocodec);
245
246
247
248
249
    initBuffers();
    initNoiseSuppress();

    _queue->enableStack();
    int ret = _thread->start();
250
251
252

    if (_type == Zrtp)
        return ret;
253

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


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

}