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 #include "modules/mediastream/RTCDTMFSender.h" 28 29 #include "bindings/v8/ExceptionState.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "core/dom/ExecutionContext.h" 32 #include "core/platform/mediastream/RTCPeerConnectionHandler.h" 33 #include "modules/mediastream/MediaStreamTrack.h" 34 #include "modules/mediastream/RTCDTMFToneChangeEvent.h" 35 #include "platform/mediastream/RTCDTMFSenderHandler.h" 36 37 namespace WebCore { 38 39 static const long minToneDurationMs = 70; 40 static const long defaultToneDurationMs = 100; 41 static const long maxToneDurationMs = 6000; 42 static const long minInterToneGapMs = 50; 43 static const long defaultInterToneGapMs = 50; 44 45 PassRefPtr<RTCDTMFSender> RTCDTMFSender::create(ExecutionContext* context, RTCPeerConnectionHandler* peerConnectionHandler, PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState) 46 { 47 RefPtr<MediaStreamTrack> track = prpTrack; 48 OwnPtr<RTCDTMFSenderHandler> handler = peerConnectionHandler->createDTMFSender(track->component()); 49 if (!handler) { 50 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 51 return 0; 52 } 53 54 RefPtr<RTCDTMFSender> dtmfSender = adoptRef(new RTCDTMFSender(context, track, handler.release())); 55 dtmfSender->suspendIfNeeded(); 56 return dtmfSender.release(); 57 } 58 59 RTCDTMFSender::RTCDTMFSender(ExecutionContext* context, PassRefPtr<MediaStreamTrack> track, PassOwnPtr<RTCDTMFSenderHandler> handler) 60 : ActiveDOMObject(context) 61 , m_track(track) 62 , m_duration(defaultToneDurationMs) 63 , m_interToneGap(defaultInterToneGapMs) 64 , m_handler(handler) 65 , m_stopped(false) 66 , m_scheduledEventTimer(this, &RTCDTMFSender::scheduledEventTimerFired) 67 { 68 ScriptWrappable::init(this); 69 m_handler->setClient(this); 70 } 71 72 RTCDTMFSender::~RTCDTMFSender() 73 { 74 } 75 76 bool RTCDTMFSender::canInsertDTMF() const 77 { 78 return m_handler->canInsertDTMF(); 79 } 80 81 MediaStreamTrack* RTCDTMFSender::track() const 82 { 83 return m_track.get(); 84 } 85 86 String RTCDTMFSender::toneBuffer() const 87 { 88 return m_handler->currentToneBuffer(); 89 } 90 91 void RTCDTMFSender::insertDTMF(const String& tones, ExceptionState& exceptionState) 92 { 93 insertDTMF(tones, defaultToneDurationMs, defaultInterToneGapMs, exceptionState); 94 } 95 96 void RTCDTMFSender::insertDTMF(const String& tones, long duration, ExceptionState& exceptionState) 97 { 98 insertDTMF(tones, duration, defaultInterToneGapMs, exceptionState); 99 } 100 101 void RTCDTMFSender::insertDTMF(const String& tones, long duration, long interToneGap, ExceptionState& exceptionState) 102 { 103 if (!canInsertDTMF()) { 104 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError); 105 return; 106 } 107 108 if (duration > maxToneDurationMs || duration < minToneDurationMs) { 109 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError); 110 return; 111 } 112 113 if (interToneGap < minInterToneGapMs) { 114 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError); 115 return; 116 } 117 118 m_duration = duration; 119 m_interToneGap = interToneGap; 120 121 if (!m_handler->insertDTMF(tones, m_duration, m_interToneGap)) 122 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError); 123 } 124 125 void RTCDTMFSender::didPlayTone(const String& tone) 126 { 127 scheduleDispatchEvent(RTCDTMFToneChangeEvent::create(tone)); 128 } 129 130 const AtomicString& RTCDTMFSender::interfaceName() const 131 { 132 return EventTargetNames::RTCDTMFSender; 133 } 134 135 ExecutionContext* RTCDTMFSender::executionContext() const 136 { 137 return ActiveDOMObject::executionContext(); 138 } 139 140 void RTCDTMFSender::stop() 141 { 142 m_stopped = true; 143 m_handler->setClient(0); 144 } 145 146 void RTCDTMFSender::scheduleDispatchEvent(PassRefPtr<Event> event) 147 { 148 m_scheduledEvents.append(event); 149 150 if (!m_scheduledEventTimer.isActive()) 151 m_scheduledEventTimer.startOneShot(0); 152 } 153 154 void RTCDTMFSender::scheduledEventTimerFired(Timer<RTCDTMFSender>*) 155 { 156 if (m_stopped) 157 return; 158 159 Vector<RefPtr<Event> > events; 160 events.swap(m_scheduledEvents); 161 162 Vector<RefPtr<Event> >::iterator it = events.begin(); 163 for (; it != events.end(); ++it) 164 dispatchEvent((*it).release()); 165 } 166 167 } // namespace WebCore 168