|  | /* | 
|  | *  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 | 
|  |  | 
|  | int16_t 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; | 
|  | } | 
|  |  | 
|  | int16_t WebRtcNetEQ_DtmfDecoderInit(dtmf_inst_t *DTMFdec_inst, uint16_t fs, | 
|  | int16_t 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; | 
|  | } | 
|  |  | 
|  | int16_t WebRtcNetEQ_DtmfInsertEvent(dtmf_inst_t *DTMFdec_inst, | 
|  | const int16_t *encoded, int16_t len, | 
|  | uint32_t timeStamp) | 
|  | { | 
|  |  | 
|  | int i; | 
|  | int16_t value; | 
|  | const int16_t *EventStart; | 
|  | int16_t endEvent; | 
|  | int16_t Volume; | 
|  | int16_t Duration; | 
|  | int16_t position = -1; | 
|  |  | 
|  | /* Extract event */ | 
|  | if (len == 4) | 
|  | { | 
|  | EventStart = encoded; | 
|  | #ifdef WEBRTC_ARCH_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 = (((((uint16_t) EventStart[1]) >> 8) & 0xFF) | 
|  | | (((uint16_t) (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; | 
|  | } | 
|  |  | 
|  | int16_t WebRtcNetEQ_DtmfDecode(dtmf_inst_t *DTMFdec_inst, int16_t *event, | 
|  | int16_t *volume, uint32_t 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 = (int16_t) (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 |