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/core/v8/ExceptionMessages.h" 30 #include "bindings/core/v8/ExceptionState.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/dom/ExecutionContext.h" 33 #include "modules/mediastream/MediaStreamTrack.h" 34 #include "modules/mediastream/RTCDTMFToneChangeEvent.h" 35 #include "public/platform/WebMediaStreamTrack.h" 36 #include "public/platform/WebRTCDTMFSenderHandler.h" 37 #include "public/platform/WebRTCPeerConnectionHandler.h" 38 39 namespace blink { 40 41 static const long minToneDurationMs = 70; 42 static const long defaultToneDurationMs = 100; 43 static const long maxToneDurationMs = 6000; 44 static const long minInterToneGapMs = 50; 45 static const long defaultInterToneGapMs = 50; 46 47 RTCDTMFSender* RTCDTMFSender::create(ExecutionContext* context, WebRTCPeerConnectionHandler* peerConnectionHandler, MediaStreamTrack* track, ExceptionState& exceptionState) 48 { 49 OwnPtr<WebRTCDTMFSenderHandler> handler = adoptPtr(peerConnectionHandler->createDTMFSender(track->component())); 50 if (!handler) { 51 exceptionState.throwDOMException(NotSupportedError, "The MediaStreamTrack provided is not an element of a MediaStream that's currently in the local streams set."); 52 return nullptr; 53 } 54 55 RTCDTMFSender* dtmfSender = adoptRefCountedGarbageCollectedWillBeNoop(new RTCDTMFSender(context, track, handler.release())); 56 dtmfSender->suspendIfNeeded(); 57 return dtmfSender; 58 } 59 60 RTCDTMFSender::RTCDTMFSender(ExecutionContext* context, MediaStreamTrack* track, PassOwnPtr<WebRTCDTMFSenderHandler> handler) 61 : ActiveDOMObject(context) 62 , m_track(track) 63 , m_duration(defaultToneDurationMs) 64 , m_interToneGap(defaultInterToneGapMs) 65 , m_handler(handler) 66 , m_stopped(false) 67 , m_scheduledEventTimer(this, &RTCDTMFSender::scheduledEventTimerFired) 68 { 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.throwDOMException(NotSupportedError, "The 'canInsertDTMF' attribute is false: this sender cannot send DTMF."); 105 return; 106 } 107 108 if (duration > maxToneDurationMs || duration < minToneDurationMs) { 109 exceptionState.throwDOMException(SyntaxError, ExceptionMessages::indexOutsideRange("duration", duration, minToneDurationMs, ExceptionMessages::ExclusiveBound, maxToneDurationMs, ExceptionMessages::ExclusiveBound)); 110 return; 111 } 112 113 if (interToneGap < minInterToneGapMs) { 114 exceptionState.throwDOMException(SyntaxError, ExceptionMessages::indexExceedsMinimumBound("intertone gap", interToneGap, minInterToneGapMs)); 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.throwDOMException(SyntaxError, "Could not send provided tones, '" + tones + "'."); 123 } 124 125 void RTCDTMFSender::didPlayTone(const WebString& 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(PassRefPtrWillBeRawPtr<Event> event) 147 { 148 m_scheduledEvents.append(event); 149 150 if (!m_scheduledEventTimer.isActive()) 151 m_scheduledEventTimer.startOneShot(0, FROM_HERE); 152 } 153 154 void RTCDTMFSender::scheduledEventTimerFired(Timer<RTCDTMFSender>*) 155 { 156 if (m_stopped) 157 return; 158 159 WillBeHeapVector<RefPtrWillBeMember<Event> > events; 160 events.swap(m_scheduledEvents); 161 162 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin(); 163 for (; it != events.end(); ++it) 164 dispatchEvent((*it).release()); 165 } 166 167 void RTCDTMFSender::trace(Visitor* visitor) 168 { 169 visitor->trace(m_track); 170 visitor->trace(m_scheduledEvents); 171 EventTargetWithInlineData::trace(visitor); 172 } 173 174 } // namespace blink 175