| /* |
| * 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 |