1/* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#if ENABLE(MEDIA_STREAM) 29 30#include "RTCDTMFSender.h" 31 32#include "ExceptionCode.h" 33#include "MediaStreamTrack.h" 34#include "RTCDTMFSenderHandler.h" 35#include "RTCDTMFToneChangeEvent.h" 36#include "RTCPeerConnectionHandler.h" 37#include "ScriptExecutionContext.h" 38 39namespace WebCore { 40 41static const long minToneDurationMs = 70; 42static const long defaultToneDurationMs = 100; 43static const long maxToneDurationMs = 6000; 44static const long minInterToneGapMs = 50; 45static const long defaultInterToneGapMs = 50; 46 47PassRefPtr<RTCDTMFSender> RTCDTMFSender::create(ScriptExecutionContext* context, RTCPeerConnectionHandler* peerConnectionHandler, PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) 48{ 49 RefPtr<MediaStreamTrack> track = prpTrack; 50 OwnPtr<RTCDTMFSenderHandler> handler = peerConnectionHandler->createDTMFSender(track->component()); 51 if (!handler) { 52 ec = NOT_SUPPORTED_ERR; 53 return 0; 54 } 55 56 RefPtr<RTCDTMFSender> dtmfSender = adoptRef(new RTCDTMFSender(context, track, handler.release())); 57 dtmfSender->suspendIfNeeded(); 58 return dtmfSender.release(); 59} 60 61RTCDTMFSender::RTCDTMFSender(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrack> track, PassOwnPtr<RTCDTMFSenderHandler> handler) 62 : ActiveDOMObject(context) 63 , m_track(track) 64 , m_duration(defaultToneDurationMs) 65 , m_interToneGap(defaultInterToneGapMs) 66 , m_handler(handler) 67 , m_stopped(false) 68 , m_scheduledEventTimer(this, &RTCDTMFSender::scheduledEventTimerFired) 69{ 70 m_handler->setClient(this); 71} 72 73RTCDTMFSender::~RTCDTMFSender() 74{ 75} 76 77bool RTCDTMFSender::canInsertDTMF() const 78{ 79 return m_handler->canInsertDTMF(); 80} 81 82MediaStreamTrack* RTCDTMFSender::track() const 83{ 84 return m_track.get(); 85} 86 87String RTCDTMFSender::toneBuffer() const 88{ 89 return m_handler->currentToneBuffer(); 90} 91 92void RTCDTMFSender::insertDTMF(const String& tones, ExceptionCode& ec) 93{ 94 insertDTMF(tones, defaultToneDurationMs, defaultInterToneGapMs, ec); 95} 96 97void RTCDTMFSender::insertDTMF(const String& tones, long duration, ExceptionCode& ec) 98{ 99 insertDTMF(tones, duration, defaultInterToneGapMs, ec); 100} 101 102void RTCDTMFSender::insertDTMF(const String& tones, long duration, long interToneGap, ExceptionCode& ec) 103{ 104 if (!canInsertDTMF()) { 105 ec = NOT_SUPPORTED_ERR; 106 return; 107 } 108 109 if (duration > maxToneDurationMs || duration < minToneDurationMs) { 110 ec = SYNTAX_ERR; 111 return; 112 } 113 114 if (interToneGap < minInterToneGapMs) { 115 ec = SYNTAX_ERR; 116 return; 117 } 118 119 m_duration = duration; 120 m_interToneGap = interToneGap; 121 122 if (!m_handler->insertDTMF(tones, m_duration, m_interToneGap)) 123 ec = SYNTAX_ERR; 124} 125 126void RTCDTMFSender::didPlayTone(const String& tone) 127{ 128 scheduleDispatchEvent(RTCDTMFToneChangeEvent::create(tone)); 129} 130 131const AtomicString& RTCDTMFSender::interfaceName() const 132{ 133 return eventNames().interfaceForRTCDTMFSender; 134} 135 136ScriptExecutionContext* RTCDTMFSender::scriptExecutionContext() const 137{ 138 return ActiveDOMObject::scriptExecutionContext(); 139} 140 141void RTCDTMFSender::stop() 142{ 143 m_stopped = true; 144 m_handler->setClient(0); 145} 146 147EventTargetData* RTCDTMFSender::eventTargetData() 148{ 149 return &m_eventTargetData; 150} 151 152EventTargetData* RTCDTMFSender::ensureEventTargetData() 153{ 154 return &m_eventTargetData; 155} 156 157void RTCDTMFSender::scheduleDispatchEvent(PassRefPtr<Event> event) 158{ 159 m_scheduledEvents.append(event); 160 161 if (!m_scheduledEventTimer.isActive()) 162 m_scheduledEventTimer.startOneShot(0); 163} 164 165void RTCDTMFSender::scheduledEventTimerFired(Timer<RTCDTMFSender>*) 166{ 167 if (m_stopped) 168 return; 169 170 Vector<RefPtr<Event> > events; 171 events.swap(m_scheduledEvents); 172 173 Vector<RefPtr<Event> >::iterator it = events.begin(); 174 for (; it != events.end(); ++it) 175 dispatchEvent((*it).release()); 176} 177 178} // namespace WebCore 179 180#endif // ENABLE(MEDIA_STREAM) 181