blob: f00f9c994fcad0439755e953827590f5eb0d4bd3 [file] [log] [blame]
/*
* Copyright (c) 2011 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.
*/
/*
* Implementation of packet buffer for DTMF messages.
*/
#include "dtmf_buffer.h"
#include "typedefs.h" /* to define endianness */
#include "signal_processing_library.h"
#include "neteq_error_codes.h"
#ifdef NETEQ_ATEVENT_DECODE
WebRtc_Word16 WebRtcNetEQ_DtmfRemoveEvent(dtmf_inst_t *DTMFdec_inst)
{
int i;
for (i = 0; i < 3; i++)
{
DTMFdec_inst->EventQueue[i] = DTMFdec_inst->EventQueue[i + 1];
DTMFdec_inst->EventQueueVolume[i] = DTMFdec_inst->EventQueueVolume[i + 1];
DTMFdec_inst->EventQueueEnded[i] = DTMFdec_inst->EventQueueEnded[i + 1];
DTMFdec_inst->EventQueueStartTime[i] = DTMFdec_inst->EventQueueStartTime[i + 1];
DTMFdec_inst->EventQueueEndTime[i] = DTMFdec_inst->EventQueueEndTime[i + 1];
}
DTMFdec_inst->EventBufferSize--;
DTMFdec_inst->EventQueue[3] = -1;
DTMFdec_inst->EventQueueVolume[3] = 0;
DTMFdec_inst->EventQueueEnded[3] = 0;
DTMFdec_inst->EventQueueStartTime[3] = 0;
DTMFdec_inst->EventQueueEndTime[3] = 0;
return 0;
}
WebRtc_Word16 WebRtcNetEQ_DtmfDecoderInit(dtmf_inst_t *DTMFdec_inst, WebRtc_UWord16 fs,
WebRtc_Word16 MaxPLCtime)
{
int i;
if (((fs != 8000) && (fs != 16000) && (fs != 32000) && (fs != 48000)) || (MaxPLCtime < 0))
{
return DTMF_DEC_PARAMETER_ERROR;
}
if (fs == 8000)
DTMFdec_inst->framelen = 80;
else if (fs == 16000)
DTMFdec_inst->framelen = 160;
else if (fs == 32000)
DTMFdec_inst->framelen = 320;
else
/* fs == 48000 */
DTMFdec_inst->framelen = 480;
DTMFdec_inst->MaxPLCtime = MaxPLCtime;
DTMFdec_inst->CurrentPLCtime = 0;
DTMFdec_inst->EventBufferSize = 0;
for (i = 0; i < 4; i++)
{
DTMFdec_inst->EventQueue[i] = -1;
DTMFdec_inst->EventQueueVolume[i] = 0;
DTMFdec_inst->EventQueueEnded[i] = 0;
DTMFdec_inst->EventQueueStartTime[i] = 0;
DTMFdec_inst->EventQueueEndTime[i] = 0;
}
return 0;
}
WebRtc_Word16 WebRtcNetEQ_DtmfInsertEvent(dtmf_inst_t *DTMFdec_inst,
const WebRtc_Word16 *encoded, WebRtc_Word16 len,
WebRtc_UWord32 timeStamp)
{
int i;
WebRtc_Word16 value;
const WebRtc_Word16 *EventStart;
WebRtc_Word16 endEvent;
WebRtc_Word16 Volume;
WebRtc_Word16 Duration;
WebRtc_Word16 position = -1;
/* Extract event */
if (len == 4)
{
EventStart = encoded;
#ifdef WEBRTC_BIG_ENDIAN
value=((*EventStart)>>8);
endEvent=((*EventStart)&0x80)>>7;
Volume=((*EventStart)&0x3F);
Duration=EventStart[1];
#else
value = ((*EventStart) & 0xFF);
endEvent = ((*EventStart) & 0x8000) >> 15;
Volume = ((*EventStart) & 0x3F00) >> 8;
Duration = (((((WebRtc_UWord16) EventStart[1]) >> 8) & 0xFF)
| (((WebRtc_UWord16) (EventStart[1] & 0xFF)) << 8));
#endif
/* Only events between 0-15 are supported (DTMF tones) */
if ((value < 0) || (value > 15))
{
return 0;
}
/* Discard all DTMF tones with really low volume (<-36dbm0) */
if (Volume > 36)
{
return 0;
}
/*Are there any unended events of the same type? */
for (i = 0; i < DTMFdec_inst->EventBufferSize; i++)
{
/* Going through the whole queue even when we have found a match will
ensure that we add to the latest applicable event */
if ((DTMFdec_inst->EventQueue[i] == value) && (!DTMFdec_inst->EventQueueEnded[i]
|| endEvent)) position = i;
}
if (position > -1)
{
DTMFdec_inst->EventQueueVolume[position] = Volume;
if ((timeStamp + Duration) > DTMFdec_inst->EventQueueEndTime[position]) DTMFdec_inst->EventQueueEndTime[position]
= DTMFdec_inst->EventQueueStartTime[position] + Duration;
if (endEvent) DTMFdec_inst->EventQueueEnded[position] = 1;
}
else
{
if (DTMFdec_inst->EventBufferSize == MAX_DTMF_QUEUE_SIZE)
{ /* Buffer full */
/* Remove one event */
DTMFdec_inst->EventBufferSize--;
}
/* Store data in the instance on a new position*/
DTMFdec_inst->EventQueue[DTMFdec_inst->EventBufferSize] = value;
DTMFdec_inst->EventQueueVolume[DTMFdec_inst->EventBufferSize] = Volume;
DTMFdec_inst->EventQueueEnded[DTMFdec_inst->EventBufferSize] = endEvent;
DTMFdec_inst->EventQueueStartTime[DTMFdec_inst->EventBufferSize] = timeStamp;
DTMFdec_inst->EventQueueEndTime[DTMFdec_inst->EventBufferSize] = timeStamp
+ Duration;
DTMFdec_inst->EventBufferSize++;
}
return 0;
}
return DTMF_INSERT_ERROR;
}
WebRtc_Word16 WebRtcNetEQ_DtmfDecode(dtmf_inst_t *DTMFdec_inst, WebRtc_Word16 *event,
WebRtc_Word16 *volume, WebRtc_UWord32 currTimeStamp)
{
if (DTMFdec_inst->EventBufferSize < 1) return 0; /* No events to play */
/* We have events, is it time to play them? */
if (currTimeStamp < DTMFdec_inst->EventQueueStartTime[0])
{
/*No, just return zero */
return 0;
}
/* Continue on the event that is currently ongoing */
*event = DTMFdec_inst->EventQueue[0];
*volume = DTMFdec_inst->EventQueueVolume[0];
if (DTMFdec_inst->EventQueueEndTime[0] >= (currTimeStamp + DTMFdec_inst->framelen))
{
/* Still at least framLen to play */
DTMFdec_inst->CurrentPLCtime = 0;
if ((DTMFdec_inst->EventQueueEndTime[0] == (currTimeStamp + DTMFdec_inst->framelen))
&& (DTMFdec_inst->EventQueueEnded[0]))
{ /* We are done */
/*Remove the event from Queue*/
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
}
return DTMFdec_inst->framelen;
}
else
{
if ((DTMFdec_inst->EventQueueEnded[0]) || (DTMFdec_inst->EventQueue[1] > -1))
{
/*
* Less than frameLen to play and end of event or already received next event.
* Give our a whole frame size of audio to simplify things.
*/
/*Remove the event from Queue*/
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
DTMFdec_inst->CurrentPLCtime = 0;
return DTMFdec_inst->framelen;
}
else
{
/* Less than frameLen to play and not end of event. */
DTMFdec_inst->CurrentPLCtime = (WebRtc_Word16) (currTimeStamp
- DTMFdec_inst->EventQueueEndTime[0]);
if ((DTMFdec_inst->CurrentPLCtime > DTMFdec_inst->MaxPLCtime)
|| (DTMFdec_inst->CurrentPLCtime < -DTMFdec_inst->MaxPLCtime))
{
/*Remove the event from queue*/
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
DTMFdec_inst->CurrentPLCtime = 0;
}
/* If we have a new event that it's time to play */
if ((DTMFdec_inst->EventQueue[1] > -1) && (DTMFdec_inst->EventQueueStartTime[1]
>= (currTimeStamp + DTMFdec_inst->framelen)))
{
/*Remove the event from queue*/
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
DTMFdec_inst->CurrentPLCtime = 0;
}
return DTMFdec_inst->framelen;
}
}
}
#endif