blob: c9fd3df09ce0ab3be500e0ca1fdbac00d3f837ab [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtp_receiver_audio.h"
#include <cassert> //assert
#include <cstring> // memcpy()
#include <math.h> // pow()
#include "critical_section_wrapper.h"
namespace webrtc {
RTPReceiverAudio::RTPReceiverAudio(const WebRtc_Word32 id):
_id(id),
_lastReceivedFrequency(8000),
_telephoneEvent(false),
_telephoneEventForwardToDecoder(false),
_telephoneEventDetectEndOfTone(false),
_telephoneEventPayloadType(-1),
_cngNBPayloadType(-1),
_cngWBPayloadType(-1),
_cngSWBPayloadType(-1),
_cngFBPayloadType(-1),
_cngPayloadType(-1),
_G722PayloadType(-1),
_lastReceivedG722(false),
_criticalSectionFeedback(CriticalSectionWrapper::CreateCriticalSection()),
_cbAudioFeedback(NULL)
{
}
RTPReceiverAudio::~RTPReceiverAudio()
{
delete _criticalSectionFeedback;
}
WebRtc_Word32
RTPReceiverAudio::RegisterIncomingAudioCallback(RtpAudioFeedback* incomingMessagesCallback)
{
CriticalSectionScoped lock(_criticalSectionFeedback);
_cbAudioFeedback = incomingMessagesCallback;
return 0;
}
WebRtc_UWord32
RTPReceiverAudio::AudioFrequency() const
{
if(_lastReceivedG722)
{
return 8000;
}
return _lastReceivedFrequency;
}
// Outband TelephoneEvent(DTMF) detection
WebRtc_Word32
RTPReceiverAudio::SetTelephoneEventStatus(const bool enable,
const bool forwardToDecoder,
const bool detectEndOfTone)
{
_telephoneEvent= enable;
_telephoneEventDetectEndOfTone = detectEndOfTone;
_telephoneEventForwardToDecoder = forwardToDecoder;
return 0;
}
// Is outband TelephoneEvent(DTMF) turned on/off?
bool
RTPReceiverAudio::TelephoneEvent() const
{
return _telephoneEvent;
}
// Is forwarding of outband telephone events turned on/off?
bool
RTPReceiverAudio::TelephoneEventForwardToDecoder() const
{
return _telephoneEventForwardToDecoder;
}
bool
RTPReceiverAudio::TelephoneEventPayloadType(const WebRtc_Word8 payloadType) const
{
return (_telephoneEventPayloadType == payloadType)?true:false;
}
bool
RTPReceiverAudio::CNGPayloadType(const WebRtc_Word8 payloadType,
WebRtc_UWord32& frequency)
{
// We can have four CNG on 8000Hz, 16000Hz, 32000Hz and 48000Hz.
if(_cngNBPayloadType == payloadType)
{
frequency = 8000;
if ((_cngPayloadType != -1) &&(_cngPayloadType !=_cngNBPayloadType))
{
ResetStatistics();
}
_cngPayloadType = _cngNBPayloadType;
return true;
} else if(_cngWBPayloadType == payloadType)
{
// if last received codec is G.722 we must use frequency 8000
if(_lastReceivedG722)
{
frequency = 8000;
} else
{
frequency = 16000;
}
if ((_cngPayloadType != -1) &&(_cngPayloadType !=_cngWBPayloadType))
{
ResetStatistics();
}
_cngPayloadType = _cngWBPayloadType;
return true;
}else if(_cngSWBPayloadType == payloadType)
{
frequency = 32000;
if ((_cngPayloadType != -1) &&(_cngPayloadType !=_cngSWBPayloadType))
{
ResetStatistics();
}
_cngPayloadType = _cngSWBPayloadType;
return true;
}else if(_cngFBPayloadType == payloadType)
{
frequency = 48000;
if ((_cngPayloadType != -1) &&(_cngPayloadType !=_cngFBPayloadType))
{
ResetStatistics();
}
_cngPayloadType = _cngFBPayloadType;
return true;
}else
{
// not CNG
if(_G722PayloadType == payloadType)
{
_lastReceivedG722 = true;
}else
{
_lastReceivedG722 = false;
}
}
return false;
}
/*
Sample based or frame based codecs based on RFC 3551
NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples.
The correct rate is 4 bits/sample.
name of sampling default
encoding sample/frame bits/sample rate ms/frame ms/packet
Sample based audio codecs
DVI4 sample 4 var. 20
G722 sample 4 16,000 20
G726-40 sample 5 8,000 20
G726-32 sample 4 8,000 20
G726-24 sample 3 8,000 20
G726-16 sample 2 8,000 20
L8 sample 8 var. 20
L16 sample 16 var. 20
PCMA sample 8 var. 20
PCMU sample 8 var. 20
Frame based audio codecs
G723 frame N/A 8,000 30 30
G728 frame N/A 8,000 2.5 20
G729 frame N/A 8,000 10 20
G729D frame N/A 8,000 10 20
G729E frame N/A 8,000 10 20
GSM frame N/A 8,000 20 20
GSM-EFR frame N/A 8,000 20 20
LPC frame N/A 8,000 20 20
MPA frame N/A var. var.
G7221 frame N/A
*/
ModuleRTPUtility::Payload* RTPReceiverAudio::RegisterReceiveAudioPayload(
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate) {
if (ModuleRTPUtility::StringCompare(payloadName, "telephone-event", 15)) {
_telephoneEventPayloadType = payloadType;
}
if (ModuleRTPUtility::StringCompare(payloadName, "cn", 2)) {
// we can have three CNG on 8000Hz, 16000Hz and 32000Hz
if(frequency == 8000){
_cngNBPayloadType = payloadType;
} else if(frequency == 16000) {
_cngWBPayloadType = payloadType;
} else if(frequency == 32000) {
_cngSWBPayloadType = payloadType;
} else if(frequency == 48000) {
_cngFBPayloadType = payloadType;
} else {
assert(false);
return NULL;
}
}
ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
payload->typeSpecific.Audio.frequency = frequency;
payload->typeSpecific.Audio.channels = channels;
payload->typeSpecific.Audio.rate = rate;
payload->audio = true;
return payload;
}
// we are not allowed to have any critsects when calling CallbackOfReceivedPayloadData
WebRtc_Word32
RTPReceiverAudio::ParseAudioCodecSpecific(WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadLength,
const ModuleRTPUtility::AudioPayload& audioSpecific,
const bool isRED)
{
WebRtc_UWord8 newEvents[MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS];
WebRtc_UWord8 removedEvents[MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS];
WebRtc_UWord8 numberOfNewEvents = 0;
WebRtc_UWord8 numberOfRemovedEvents = 0;
bool telephoneEventPacket = TelephoneEventPayloadType(rtpHeader->header.payloadType);
if(payloadLength == 0)
{
return 0;
}
{
CriticalSectionScoped lock(_criticalSectionFeedback);
if(telephoneEventPacket)
{
// RFC 4733 2.3
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| event |E|R| volume | duration |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
if(payloadLength % 4 != 0)
{
return -1;
}
WebRtc_UWord8 numberOfEvents = payloadLength / 4;
// sanity
if(numberOfEvents >= MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS)
{
numberOfEvents = MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS;
}
for (int n = 0; n < numberOfEvents; n++)
{
bool end = (payloadData[(4*n)+1] & 0x80)? true:false;
std::set<WebRtc_UWord8>::iterator event =
_telephoneEventReported.find(payloadData[4*n]);
if(event != _telephoneEventReported.end())
{
// we have already seen this event
if(end)
{
removedEvents[numberOfRemovedEvents]= payloadData[4*n];
numberOfRemovedEvents++;
_telephoneEventReported.erase(payloadData[4*n]);
}
}else
{
if(end)
{
// don't add if it's a end of a tone
}else
{
newEvents[numberOfNewEvents] = payloadData[4*n];
numberOfNewEvents++;
_telephoneEventReported.insert(payloadData[4*n]);
}
}
}
// RFC 4733 2.5.1.3 & 2.5.2.3 Long-Duration Events
// should not be a problem since we don't care about the duration
// RFC 4733 See 2.5.1.5. & 2.5.2.4. Multiple Events in a Packet
}
if(_telephoneEvent && _cbAudioFeedback)
{
for (int n = 0; n < numberOfNewEvents; n++)
{
_cbAudioFeedback->OnReceivedTelephoneEvent(_id, newEvents[n], false);
}
if(_telephoneEventDetectEndOfTone)
{
for (int n = 0; n < numberOfRemovedEvents; n++)
{
_cbAudioFeedback->OnReceivedTelephoneEvent(_id, removedEvents[n], true);
}
}
}
}
if(! telephoneEventPacket )
{
_lastReceivedFrequency = audioSpecific.frequency;
}
// Check if this is a CNG packet, receiver might want to know
WebRtc_UWord32 dummy;
if(CNGPayloadType(rtpHeader->header.payloadType, dummy))
{
rtpHeader->type.Audio.isCNG=true;
rtpHeader->frameType = kAudioFrameCN;
}else
{
rtpHeader->frameType = kAudioFrameSpeech;
rtpHeader->type.Audio.isCNG=false;
}
// check if it's a DTMF event, hence something we can playout
if(telephoneEventPacket)
{
if(!_telephoneEventForwardToDecoder)
{
// don't forward event to decoder
return 0;
}
std::set<WebRtc_UWord8>::iterator first =
_telephoneEventReported.begin();
if(first != _telephoneEventReported.end() && *first > 15)
{
// don't forward non DTMF events
return 0;
}
}
if(isRED && !(payloadData[0] & 0x80))
{
// we recive only one frame packed in a RED packet remove the RED wrapper
rtpHeader->header.payloadType = payloadData[0];
// only one frame in the RED strip the one byte to help NetEq
return CallbackOfReceivedPayloadData(payloadData+1,
payloadLength-1,
rtpHeader);
}
rtpHeader->type.Audio.channel = audioSpecific.channels;
return CallbackOfReceivedPayloadData(payloadData, payloadLength, rtpHeader);
}
} // namespace webrtc