audiortp.cpp 8.58 KB
Newer Older
savoirfairelinux's avatar
savoirfairelinux committed
1
2
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
/**
 *  Copyright (C) 2004 Savoir-Faire Linux inc.
 *  Author: Laurielle Lea <laurielle.lea@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 2 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.
 */

#include <cstdio>
#include <cstdlib>
#include <ccrtp/rtp.h>

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <qhostaddress.h>
#include <qstring.h>

#include "audiocodec.h"
#include "configuration.h"
#include "manager.h"
#include "audiortp.h"
#include "sip.h"
#include "../stund/stun.h"

37
#include <string>
savoirfairelinux's avatar
savoirfairelinux committed
38
using namespace ost;
39
using namespace std;
savoirfairelinux's avatar
savoirfairelinux committed
40
41
42
43
44

////////////////////////////////////////////////////////////////////////////////
// AudioRtp                                                          
////////////////////////////////////////////////////////////////////////////////
AudioRtp::AudioRtp (SIP *sip, Manager *manager) {
45
	string svr;
savoirfairelinux's avatar
savoirfairelinux committed
46
47
48
	this->sip = sip;
	this->manager = manager;
	RTXThread = NULL;
49
	if (!manager->useStun()) {
50
		if (Config::gets("Signalisations", "SIP.sipproxy") == "") {
51
52
53
54
55
			svr = Config::gets("Signalisations", "SIP.sipproxy");
		}
	} else {
		svr = Config::gets("Signalisations", "SIP.hostPart");
	}
savoirfairelinux's avatar
savoirfairelinux committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
}

AudioRtp::~AudioRtp (void) {
}

int 
AudioRtp::createNewSession (SipCall *ca) {
	// Start RTP Send/Receive threads
	ca->enable_audio = 1;
	if (!manager->useStun()) { 
		symetric = false;
	} else {
		symetric = true;
	}
70
	
llea's avatar
llea committed
71
72
#ifdef ALSA
	RTXThread = new AudioRtpRTX (ca, manager->audiodriver, 
73
				manager->audiodriverReadAlsa, manager, symetric);
llea's avatar
llea committed
74
75
#else
	RTXThread = new AudioRtpRTX (ca, manager->audiodriver, NULL, manager, 
76
			symetric);
llea's avatar
llea committed
77
#endif
78
	
llea's avatar
llea committed
79
80
81
	if (RTXThread->start() != 0) {
		return -1;
	}
llea's avatar
llea committed
82
		
savoirfairelinux's avatar
savoirfairelinux committed
83
84
85
86
87
88
89
90
91
	return 0;
}

	
void
AudioRtp::closeRtpSession (SipCall *ca) {
	// This will make RTP threads finish.
	ca->enable_audio = -1;

savoirfairelinux's avatar
savoirfairelinux committed
92
	if (RTXThread != NULL) {
llea's avatar
llea committed
93
		// Wait for them...and delete.
llea's avatar
llea committed
94
		//RTXThread->join();
llea's avatar
llea committed
95
		qDebug("DELETED");
savoirfairelinux's avatar
savoirfairelinux committed
96
97
98
99
100
101
102
103
104
105
106
107
		delete RTXThread;
		RTXThread = NULL;
	}

	// Flush audio read buffer
	manager->audiodriver->resetDevice();
}

////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class                                                          //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioDrivers *driver, 
108
		AudioDrivers *read_driver, Manager *mngr, bool sym) {
savoirfairelinux's avatar
savoirfairelinux committed
109
	this->manager = mngr;
110
	this->ca = sipcall;
savoirfairelinux's avatar
savoirfairelinux committed
111
	this->sym =sym;
112
	this->audioDevice = driver;
llea's avatar
llea committed
113
114
115
#ifdef ALSA
	this->audioDeviceRead = read_driver;
#endif
savoirfairelinux's avatar
savoirfairelinux committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

	// TODO: Change bind address according to user settings.
	InetHostAddress local_ip("0.0.0.0");

	if (!sym) {
		sessionRecv = new RTPSession (local_ip, ca->getLocalAudioPort());
		sessionSend = new RTPSession (local_ip);
	} else {
		int forcedPort = manager->getFirewallPort();
		qDebug("Forced port %d", forcedPort);
		session = new SymmetricRTPSession (local_ip, forcedPort);
	}
}

AudioRtpRTX::~AudioRtpRTX () {
llea's avatar
llea committed
131
	this->terminate();
savoirfairelinux's avatar
savoirfairelinux committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
	if (!sym) {
		if (sessionRecv != NULL) {
			delete sessionRecv;	
			sessionRecv = NULL;
		}
		if (sessionSend != NULL) {
			delete sessionSend;	
			sessionSend = NULL;
		}
	} else {
		if (session != NULL) {
			delete session;
			session = NULL;
		}
	}
}

void
AudioRtpRTX::run (void) {
	AudioCodec 		 ac;
	unsigned char	*data_to_send;
	short			*data_mute;
	short			*data_from_mic;
155
	short			*data_from_mic_tmp;
savoirfairelinux's avatar
savoirfairelinux committed
156
157
158
159
160
161
162
163
	int				 i,
					 compSize, 
					 timestamp;
	int				 expandedSize;
	short			*data_for_speakers = NULL;
	
	data_for_speakers = new short[2048];
	data_from_mic = new short[1024];
164
	data_from_mic_tmp = new short[1024];
savoirfairelinux's avatar
savoirfairelinux committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	data_to_send = new unsigned char[1024];
	data_mute = new short[1024];

	InetHostAddress remote_ip(ca->remote_sdp_audio_ip);
	
	if (!remote_ip) {
	   qDebug("RTX: IP address is not correct!");
	   exit();
	} else {
		qDebug("RTX: Connected to %s:%d",
				ca->remote_sdp_audio_ip, ca->remote_sdp_audio_port);
	}
	
	// Initialization
	if (!sym) {
		sessionRecv->setSchedulingTimeout (100000);
		sessionRecv->setExpireTimeout(1000000);
		
		sessionSend->setSchedulingTimeout(10000);
		sessionSend->setExpireTimeout(1000000);
	} else {
		session->setSchedulingTimeout(10000);
		session->setExpireTimeout(1000000);
	}

#if 0 // Necessaire ?
    if (!sessionRecv->addDestination(remote_ip,
				(unsigned short) ca->remote_sdp_audio_port)) {
		qDebug("RTX recv: could not connect to port %d", 
				ca->remote_sdp_audio_port);
		this->exit();
	} else {
		qDebug("RTP(Recv): Added destination %s:%d",
				remote_ip.getHostname(),
llea's avatar
llea committed
199
				(unsigned short) ca->remote_sdp_audio_port);
savoirfairelinux's avatar
savoirfairelinux committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
	}
#endif

	if (!sym) {
		if (!sessionSend->addDestination (remote_ip, 
					(unsigned short) ca->remote_sdp_audio_port)) {
			qDebug("RTX send: could not connect to port %d", 
					ca->remote_sdp_audio_port);
			this->exit();
		} else {
			qDebug("RTP(Send): Added destination %s:%d",
					remote_ip.getHostname(),
					(unsigned short) ca->remote_sdp_audio_port);
		}

		sessionRecv->setPayloadFormat(StaticPayloadFormat(
				(StaticPayloadType) ca->payload));
		sessionSend->setPayloadFormat(StaticPayloadFormat(
				(StaticPayloadType) ca->payload));
		setCancel(cancelImmediate);
		sessionSend->setMark(true);

	} else {
		if (!session->addDestination (remote_ip, 
					(unsigned short) ca->remote_sdp_audio_port)) {
			qDebug("Symmetric: could not connect to port %d", 
					ca->remote_sdp_audio_port);
			this->exit();
		} else {
			qDebug("Symmetric: Connected to %s:%d",
					remote_ip.getHostname(),
					(unsigned short) ca->remote_sdp_audio_port);

			session->setPayloadFormat(StaticPayloadFormat(
				(StaticPayloadType) ca->payload));
			setCancel(cancelImmediate);
		}
	}
	
	timestamp = 0;

	// TODO: get frameSize from user config 
	int frameSize = 20; // 20ms frames
	TimerPort::setTimer(frameSize);
	
	// start running the packet queue scheduler.
	if (!sym) {
		sessionRecv->startRunning();
		sessionSend->startRunning();	
	} else {
		session->startRunning();
	}
	
	while (ca->enable_audio != -1) {
		////////////////////////////
		// Send session
		////////////////////////////
		if (!manager->mute) {
llea's avatar
llea committed
258
259
260
261
262
#ifdef ALSA
			i = audioDeviceRead->readBuffer (data_from_mic, 320);
#else
			i = audioDevice->readBuffer (data_from_mic, 320);
#endif
savoirfairelinux's avatar
savoirfairelinux committed
263
264
265
		} else {
			// When IP-phone user click on mute button, we read buffer of a
			// temp buffer to avoid delay in sound.
llea's avatar
llea committed
266
267
268
269
270
#ifdef
			i = audioDeviceRead->readBuffer (data_mute, 320);
#else
			i = audioDevice->readBuffer (data_mute, 320);
#endif
savoirfairelinux's avatar
savoirfairelinux committed
271
272
		}

273
274
275
276
		// TODO : return an error because no sound
		if (i < 0) {
			break;
		}
277
		for (int j = 0; j < i; j++)
llea's avatar
llea committed
278
			data_from_mic_tmp[j] = data_from_mic[j]*manager->getMicVolume()/100;
279

savoirfairelinux's avatar
savoirfairelinux committed
280
281
282
283
		// Encode acquired audio sample
		compSize = AudioCodec::codecEncode (
				ac.handleCodecs[0], 
				data_to_send,
284
				data_from_mic_tmp, i);
savoirfairelinux's avatar
savoirfairelinux committed
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

		// Send encoded audio sample
		if (!sym) {
			sessionSend->putData(timestamp, data_to_send, compSize);
		} else {
			session->putData(timestamp, data_to_send, compSize);
		}
		timestamp += compSize;

		////////////////////////////
		// Recv session
		////////////////////////////
		const AppDataUnit* adu = NULL;

		do {
			Thread::sleep(5); // in msec.
			if (!sym) {
				adu = sessionRecv->getData(sessionRecv->getFirstTimestamp());
			} else {
				adu = session->getData(session->getFirstTimestamp());
			}
		} while (adu == NULL);

		// Decode data with relevant codec
		expandedSize = AudioCodec::codecDecode (
				adu->getType(),
				data_for_speakers,
				(unsigned char*) adu->getData(),
				adu->getSize());
		
		// Write decoded data to sound device
llea's avatar
llea committed
316
317
318
		audioDevice->audio_buf.resize(expandedSize);
		audioDevice->audio_buf.setData (data_for_speakers, 
				manager->getSpkrVolume());
llea's avatar
llea committed
319
		i = audioDevice->writeBuffer ();
savoirfairelinux's avatar
savoirfairelinux committed
320
321
322
323
324
325
326
327
328
329
		delete adu;


		// Let's wait for the next transmit cycle
		Thread::sleep(TimerPort::getTimer());
		TimerPort::incTimer(frameSize); // 'frameSize' ms
	}
		 
	delete[] data_for_speakers;
	delete[] data_from_mic;
330
	delete[] data_from_mic_tmp;
savoirfairelinux's avatar
savoirfairelinux committed
331
332
333
334
335
336
337
	delete[] data_mute;
	delete[] data_to_send;
	this->exit();
}


// EOF