1/*
2 * Copyright (C) 2017 Apple Inc.
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 APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26#include "LibWebRTCDataChannelHandler.h"
27
28#if USE(LIBWEBRTC)
29
30#include "EventNames.h"
31#include "RTCDataChannel.h"
32#include "RTCDataChannelEvent.h"
33#include <wtf/MainThread.h>
34
35namespace WebCore {
36
37webrtc::DataChannelInit LibWebRTCDataChannelHandler::fromRTCDataChannelInit(const RTCDataChannelInit& options)
38{
39 webrtc::DataChannelInit init;
40 if (options.ordered)
41 init.ordered = *options.ordered;
42 if (options.maxPacketLifeTime)
43 init.maxRetransmitTime = *options.maxPacketLifeTime;
44 if (options.maxRetransmits)
45 init.maxRetransmits = *options.maxRetransmits;
46 init.protocol = options.protocol.utf8().data();
47 if (options.negotiated)
48 init.negotiated = *options.negotiated;
49 if (options.id)
50 init.id = *options.id;
51 return init;
52}
53
54static inline String fromStdString(const std::string& value)
55{
56 return String::fromUTF8(value.data(), value.length());
57}
58
59Ref<RTCDataChannelEvent> LibWebRTCDataChannelHandler::channelEvent(ScriptExecutionContext& context, rtc::scoped_refptr<webrtc::DataChannelInterface>&& dataChannel)
60{
61 auto protocol = dataChannel->protocol();
62 auto label = dataChannel->label();
63
64 RTCDataChannelInit init;
65 init.ordered = dataChannel->ordered();
66 init.maxPacketLifeTime = dataChannel->maxRetransmitTime();
67 init.maxRetransmits = dataChannel->maxRetransmits();
68 init.protocol = fromStdString(protocol);
69 init.negotiated = dataChannel->negotiated();
70 init.id = dataChannel->id();
71
72 auto handler = std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(dataChannel));
73 auto channel = RTCDataChannel::create(context, WTFMove(handler), fromStdString(label), WTFMove(init));
74
75 return RTCDataChannelEvent::create(eventNames().datachannelEvent, Event::CanBubble::No, Event::IsCancelable::No, WTFMove(channel));
76}
77
78LibWebRTCDataChannelHandler::~LibWebRTCDataChannelHandler()
79{
80 if (m_client)
81 m_channel->UnregisterObserver();
82}
83
84void LibWebRTCDataChannelHandler::setClient(RTCDataChannelHandlerClient& client)
85{
86 ASSERT(!m_client);
87 m_client = &client;
88 m_channel->RegisterObserver(this);
89 checkState();
90}
91
92bool LibWebRTCDataChannelHandler::sendStringData(const String& text)
93{
94 auto utf8Text = text.utf8();
95 return m_channel->Send({ rtc::CopyOnWriteBuffer(utf8Text.data(), utf8Text.length()), false });
96}
97
98bool LibWebRTCDataChannelHandler::sendRawData(const char* data, size_t length)
99{
100 return m_channel->Send({rtc::CopyOnWriteBuffer(data, length), true});
101}
102
103void LibWebRTCDataChannelHandler::close()
104{
105 if (m_client) {
106 m_channel->UnregisterObserver();
107 m_client = nullptr;
108 }
109 m_channel->Close();
110}
111
112void LibWebRTCDataChannelHandler::OnStateChange()
113{
114 if (!m_client)
115 return;
116 checkState();
117}
118
119void LibWebRTCDataChannelHandler::checkState()
120{
121 RTCDataChannelState state;
122 switch (m_channel->state()) {
123 case webrtc::DataChannelInterface::kConnecting:
124 state = RTCDataChannelState::Connecting;
125 break;
126 case webrtc::DataChannelInterface::kOpen:
127 state = RTCDataChannelState::Open;
128 break;
129 case webrtc::DataChannelInterface::kClosing:
130 state = RTCDataChannelState::Closing;
131 break;
132 case webrtc::DataChannelInterface::kClosed:
133 state = RTCDataChannelState::Closed;
134 break;
135 }
136 callOnMainThread([protectedClient = makeRef(*m_client), state] {
137 protectedClient->didChangeReadyState(state);
138 });
139}
140
141void LibWebRTCDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer)
142{
143 if (!m_client)
144 return;
145
146 std::unique_ptr<webrtc::DataBuffer> protectedBuffer(new webrtc::DataBuffer(buffer));
147 callOnMainThread([protectedClient = makeRef(*m_client), buffer = WTFMove(protectedBuffer)] {
148 const char* data = reinterpret_cast<const char*>(buffer->data.data<char>());
149 if (buffer->binary)
150 protectedClient->didReceiveRawData(data, buffer->size());
151 else
152 protectedClient->didReceiveStringData(String::fromUTF8(data, buffer->size()));
153 });
154}
155
156void LibWebRTCDataChannelHandler::OnBufferedAmountChange(uint64_t previousAmount)
157{
158 if (!m_client)
159 return;
160
161 if (previousAmount <= m_channel->buffered_amount())
162 return;
163
164 callOnMainThread([protectedClient = makeRef(*m_client), amount = m_channel->buffered_amount()] {
165 protectedClient->bufferedAmountIsDecreasing(static_cast<size_t>(amount));
166 });
167}
168
169} // namespace WebCore
170
171#endif // USE(LIBWEBRTC)
172