Select Git revision
requestmanager.cpp
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
audiortp.cpp 8.69 KiB
/**
* 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 <iostream>
#include <string>
#include "audiortp.h"
#include "../configuration.h"
#include "../manager.h"
#include "../global.h"
#include "../user_cfg.h"
#include "../sipcall.h"
#include "../stund/stun.h"
using namespace ost;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// AudioRtp
////////////////////////////////////////////////////////////////////////////////
AudioRtp::AudioRtp (Manager *manager) {
string svr;
_manager = manager;
_RTXThread = NULL;
if (!manager->useStun()) {
if (get_config_fields_str(SIGNALISATION, PROXY).empty()) {
svr = get_config_fields_str(SIGNALISATION, PROXY);
}
} else {
svr = get_config_fields_str(SIGNALISATION, HOST_PART);
}
}
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;
}
_RTXThread = new AudioRtpRTX (ca, _manager->getAudioDriver(),
_manager, _symetric);
if (_RTXThread->start() != 0) {
return -1;
}
return 0;
}
void
AudioRtp::closeRtpSession (SipCall *ca) {
// This will make RTP threads finish.
if (ca->enable_audio > 0) {
ca->enable_audio = -1;
if (_RTXThread != NULL) {
delete _RTXThread;
_RTXThread = NULL;
}
// Flush audio read buffer
_manager->getAudioDriver()->stopStream();
}
}
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioDriversPortAudio* driver,
Manager *mngr, bool sym) {
time = new Time();
_manager = mngr;
_ca = sipcall;
_sym =sym;
_audioDevice = driver;
// TODO: Change bind address according to user settings.
InetHostAddress local_ip("0.0.0.0");
if (!_sym) {
_debug("Audiortp localport : %d\n", _ca->getLocalAudioPort());
_sessionRecv = new RTPSession (local_ip, _ca->getLocalAudioPort());
_sessionSend = new RTPSession (local_ip);
} else {
int forcedPort = _manager->getFirewallPort();
_session = new SymmetricRTPSession (local_ip, forcedPort);
}
}
AudioRtpRTX::~AudioRtpRTX () {
terminate();
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) {
unsigned char *data_to_send;
int16 *data_from_mic_int16;
float32 *data_mute;
float32 *data_from_mic;
float32 *data_from_mic_tmp;
int compSize,
timestamp;
int expandedSize;
int countTime = 0;
int16 *data_for_speakers = NULL;
float32 *data_for_speakers_float = NULL;
data_from_mic = new float32[1024];
data_from_mic_tmp = new float32[1024];
data_mute = new float32[1024];
data_to_send = new unsigned char[1024];
data_for_speakers = new int16[2048];
InetHostAddress remote_ip(_ca->getRemoteSdpAudioIp());
if (!remote_ip) {
_debug("RTX: IP address is not correct!\n");
exit();
} else {
_debug("RTX: Connected to %s : %d\n", _ca->getRemoteSdpAudioIp(),
_ca->getRemoteSdpAudioPort());
}
// Initialization
if (!_sym) {
_sessionRecv->setSchedulingTimeout (100000);
_sessionRecv->setExpireTimeout(1000000);
_sessionSend->setSchedulingTimeout(10000);
_sessionSend->setExpireTimeout(1000000);
} else {
_session->setSchedulingTimeout(10000);
_session->setExpireTimeout(1000000);
}
if (!_sym) {
if (!_sessionSend->addDestination (remote_ip,
(unsigned short) _ca->getRemoteSdpAudioPort())) {
_debug("RTX send: could not connect to port %d\n",
_ca->getRemoteSdpAudioPort());
exit();
} else {
_debug("RTP(Send): Added destination %s : %d\n",
remote_ip.getHostname(),
(unsigned short) _ca->getRemoteSdpAudioPort());
}
_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->getRemoteSdpAudioPort())) {
exit();
} else {
_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
////////////////////////////
int size = 320;
if (!_manager->getCall(_ca->getId())->isOnMute()) {
_manager->getAudioDriver()->mydata.dataIn = data_from_mic;
} else {
// When IP-phone user click on mute button, we read buffer of a
// temp buffer to avoid delay in sound.
_manager->getAudioDriver()->mydata.dataIn = data_mute;
}
for (int j = 0; j < size; j++) {
data_from_mic_tmp[j] = data_from_mic[j] *
_manager->getMicroVolume()/100;
}
// Convert float32 buffer to int16 to encode
data_from_mic_int16 = new int16[size];
_ca->getAudioCodec()->float32ToInt16 (data_from_mic_tmp,
data_from_mic_int16, size);
// Encode acquired audio sample
compSize = _ca->getAudioCodec()->codecEncode (data_to_send,
data_from_mic_int16,
size);
// Send encoded audio sample
if (!_sym) {
_sessionSend->putData(timestamp, data_to_send, compSize);
} else {
_session->putData(timestamp, data_to_send, compSize);
}
timestamp += MY_TIMESTAMP;
////////////////////////////
// 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
CodecDescriptor* cd = new CodecDescriptor (adu->getType());
AudioCodec* ac = cd->alloc(adu->getType(), "");
expandedSize = ac->codecDecode (data_for_speakers,
(unsigned char*) adu->getData(),
adu->getSize());
// To convert int16 to float32 after decoding
data_for_speakers_float = new float32[expandedSize];
ac->int16ToFloat32 (data_for_speakers, data_for_speakers_float,
expandedSize);
// Set decoded data to sound device
_manager->getAudioDriver()->mydata.dataOut = data_for_speakers_float;
// Notify (with a bip) an incoming call when there is already a call
countTime += time->getSecond();
if (_manager->getNumberOfCalls() > 0 and _manager->getbRingtone()) {
countTime = countTime % 2000;
if (countTime < 10 and countTime > 0) {
_manager->notificationIncomingCall();
}
}
delete cd;
delete adu;
// Let's wait for the next transmit cycle
Thread::sleep(TimerPort::getTimer());
TimerPort::incTimer(frameSize); // 'frameSize' ms
if (!_manager->getAudioDriver()->isStreamActive()) {
_manager->getAudioDriver()->mydata.dataToAddRem = 0;
_manager->getAudioDriver()->startStream();
}
}
delete[] data_for_speakers;
delete[] data_for_speakers_float;
delete[] data_from_mic;
delete[] data_from_mic_int16;
delete[] data_from_mic_tmp;
delete[] data_mute;
delete[] data_to_send;
exit();
}
// EOF