summaryrefslogtreecommitdiffstats
path: root/src/audio/dtmf_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/dtmf_player.cpp')
-rw-r--r--src/audio/dtmf_player.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/audio/dtmf_player.cpp b/src/audio/dtmf_player.cpp
new file mode 100644
index 0000000..d3d5909
--- /dev/null
+++ b/src/audio/dtmf_player.cpp
@@ -0,0 +1,183 @@
+/*
+ Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <cassert>
+#include <cstring>
+#include <sys/time.h>
+#include "dtmf_player.h"
+#include "audio_rx.h"
+#include "line.h"
+#include "rtp_telephone_event.h"
+#include "log.h"
+
+/////////////////////////////////////////
+// class t_dtmf_player
+/////////////////////////////////////////
+
+t_dtmf_player::t_dtmf_player(t_audio_rx *audio_rx, t_audio_encoder *audio_encoder,
+ t_user *user_config, uint8 dtmf_tone, uint32 dtmf_timestamp,
+ uint16 nsamples) :
+ _audio_rx(audio_rx),
+ _user_config(user_config),
+ _audio_encoder(audio_encoder),
+ _dtmf_pause(false),
+ _dtmf_stop(false),
+ _dtmf_current(dtmf_tone),
+ _dtmf_timestamp(dtmf_timestamp),
+ _dtmf_duration(0),
+ _nsamples(nsamples)
+{}
+
+uint32 t_dtmf_player::get_timestamp(void) {
+ return _dtmf_timestamp;
+}
+
+bool t_dtmf_player::finished(void) {
+ return _dtmf_stop;
+}
+
+/////////////////////////////////////////
+// class t_rtp_event_dtmf_player
+/////////////////////////////////////////
+
+t_rtp_event_dtmf_player::t_rtp_event_dtmf_player(t_audio_rx *audio_rx,
+ t_audio_encoder *audio_encoder, t_user *user_config,
+ uint8 dtmf_tone, uint32 dtmf_timestamp,
+ uint16 nsamples) :
+ t_dtmf_player(audio_rx, audio_encoder, user_config, dtmf_tone, dtmf_timestamp,
+ nsamples)
+{
+}
+
+uint16 t_rtp_event_dtmf_player::get_payload(uint8 *payload,
+ uint16 payload_size, uint32 timestamp, uint32 &rtp_timestamp)
+{
+ t_rtp_telephone_event *dtmf_payload = (t_rtp_telephone_event *)payload;
+ assert(sizeof(t_rtp_telephone_event) <= payload_size);
+
+ // RFC 2833 3.5, 3.6
+ dtmf_payload->set_event(_dtmf_current);
+ dtmf_payload->set_reserved(false);
+ dtmf_payload->set_volume(_user_config->get_dtmf_volume());
+
+ if (_dtmf_pause) {
+ // Trailing pause phase of a DTMF tone
+ // Repeat the last packet
+ dtmf_payload->set_end(true);
+
+ int pause_duration = timestamp - _dtmf_timestamp - _dtmf_duration +
+ _nsamples;
+ if (pause_duration / _nsamples * _audio_encoder->get_ptime() >=
+ _user_config->get_dtmf_pause())
+ {
+ // This is the last packet to be sent for the
+ // current DTMF tone.
+ _dtmf_stop = true;
+ log_file->write_header("t_rtp_event_dtmf_player::get_payload",
+ LOG_NORMAL);
+ log_file->write_raw("Audio rx line ");
+ log_file->write_raw(_audio_rx->get_line()->get_line_number()+1);
+ log_file->write_raw(": finish DTMF event - ");
+ log_file->write_raw(_dtmf_current);
+ log_file->write_endl();
+ log_file->write_footer();
+ }
+ } else {
+ // Play phase of a DTMF tone
+ // The duration counts from the start of the tone.
+ _dtmf_duration = timestamp - _dtmf_timestamp + _nsamples;
+
+ // Check if the tone must end
+ if (_dtmf_duration / _nsamples * _audio_encoder->get_ptime() >=
+ _user_config->get_dtmf_duration())
+ {
+ dtmf_payload->set_end(true);
+ _dtmf_pause = true;
+ } else {
+ dtmf_payload->set_end(false);
+ }
+ }
+
+ dtmf_payload->set_duration(_dtmf_duration);
+ rtp_timestamp = _dtmf_timestamp;
+ return sizeof(t_rtp_telephone_event);
+}
+
+
+/////////////////////////////////////////
+// class t_inband_dtmf_player
+/////////////////////////////////////////
+
+t_inband_dtmf_player::t_inband_dtmf_player(t_audio_rx *audio_rx,
+ t_audio_encoder *audio_encoder, t_user *user_config,
+ uint8 dtmf_tone, uint32 dtmf_timestamp,
+ uint16 nsamples) :
+ t_dtmf_player(audio_rx, audio_encoder, user_config, dtmf_tone, dtmf_timestamp,
+ nsamples),
+ _freq_gen(dtmf_tone, -(user_config->get_dtmf_volume()))
+{
+}
+
+uint16 t_inband_dtmf_player::get_payload(uint8 *payload,
+ uint16 payload_size, uint32 timestamp, uint32 &rtp_timestamp)
+{
+ int16 sample_buf[_nsamples];
+
+ if (_dtmf_pause) {
+ int pause_duration = timestamp - _dtmf_timestamp - _dtmf_duration +
+ _nsamples;
+
+ memset(sample_buf, 0, _nsamples * 2);
+
+ if (pause_duration / _nsamples * _audio_encoder->get_ptime() >=
+ _user_config->get_dtmf_pause())
+ {
+ // This is the last packet to be sent for the
+ // current DTMF tone.
+ _dtmf_stop = true;
+ log_file->write_header("t_inband_dtmf_player::get_payload", LOG_NORMAL);
+ log_file->write_raw("Audio rx line ");
+ log_file->write_raw(_audio_rx->get_line()->get_line_number()+1);
+ log_file->write_raw(": finish DTMF event - ");
+ log_file->write_raw(_dtmf_current);
+ log_file->write_endl();
+ log_file->write_footer();
+ }
+ } else {
+ // Timestamp and interval for _freq_gen must be in usec
+ uint32 ts_start = (timestamp - _dtmf_timestamp) * 1000000 /
+ _audio_encoder->get_sample_rate();
+ _freq_gen.get_samples(sample_buf, _nsamples, ts_start,
+ 1000000.0 / _audio_encoder->get_sample_rate());
+
+ // The duration counts from the start of the tone.
+ _dtmf_duration = timestamp - _dtmf_timestamp + _nsamples;
+
+ // Check if the tone must end
+ if (_dtmf_duration / _nsamples * _audio_encoder->get_ptime() >=
+ _user_config->get_dtmf_duration())
+ {
+ _dtmf_pause = true;
+ }
+ }
+
+ // Encode audio samples
+ bool silence;
+ rtp_timestamp = timestamp;
+ return _audio_encoder->encode(sample_buf, _nsamples, payload, payload_size, silence);
+}