1 /**
2 * Copyright (c) 2020 Filip Klembara (in2core)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #if RTC_ENABLE_MEDIA
20
21 #include "mediahandlerelement.hpp"
22
23 #include "impl/internals.hpp"
24
25 #include <cassert>
26
27 namespace rtc {
28
make_chained_messages_product()29 ChainedMessagesProduct make_chained_messages_product() {
30 return std::make_shared<std::vector<binary_ptr>>();
31 }
32
make_chained_messages_product(message_ptr msg)33 ChainedMessagesProduct make_chained_messages_product(message_ptr msg) {
34 std::vector<binary_ptr> msgs = {msg};
35 return std::make_shared<std::vector<binary_ptr>>(msgs);
36 }
37
ChainedOutgoingProduct(ChainedMessagesProduct messages,message_ptr control)38 ChainedOutgoingProduct::ChainedOutgoingProduct(ChainedMessagesProduct messages, message_ptr control)
39 : messages(messages), control(control) {}
40
ChainedIncomingProduct(ChainedMessagesProduct incoming,ChainedMessagesProduct outgoing)41 ChainedIncomingProduct::ChainedIncomingProduct(ChainedMessagesProduct incoming,
42 ChainedMessagesProduct outgoing)
43 : incoming(incoming), outgoing(outgoing) {}
44
ChainedIncomingControlProduct(message_ptr incoming,optional<ChainedOutgoingProduct> outgoing)45 ChainedIncomingControlProduct::ChainedIncomingControlProduct(
46 message_ptr incoming, optional<ChainedOutgoingProduct> outgoing)
47 : incoming(incoming), outgoing(outgoing) {}
48
MediaHandlerElement()49 MediaHandlerElement::MediaHandlerElement() {}
50
removeFromChain()51 void MediaHandlerElement::removeFromChain() {
52 if (upstream) {
53 upstream->downstream = downstream;
54 }
55 if (downstream) {
56 downstream->upstream = upstream;
57 }
58 upstream = nullptr;
59 downstream = nullptr;
60 }
61
recursiveRemoveChain()62 void MediaHandlerElement::recursiveRemoveChain() {
63 if (downstream) {
64 // `recursiveRemoveChain` removes last strong reference to downstream element
65 // we need to keep strong reference to prevent deallocation of downstream element
66 // during `recursiveRemoveChain`
67 auto strongDownstreamPtr = downstream;
68 downstream->recursiveRemoveChain();
69 }
70 removeFromChain();
71 }
72
73 optional<ChainedOutgoingProduct>
processOutgoingResponse(ChainedOutgoingProduct messages)74 MediaHandlerElement::processOutgoingResponse(ChainedOutgoingProduct messages) {
75 if (messages.messages) {
76 if (upstream) {
77 auto msgs = upstream->formOutgoingBinaryMessage(
78 ChainedOutgoingProduct(messages.messages, messages.control));
79 if (msgs.has_value()) {
80 return msgs.value();
81 } else {
82 LOG_ERROR << "Generating outgoing message failed";
83 return nullopt;
84 }
85 } else {
86 return messages;
87 }
88 } else if (messages.control) {
89 if (upstream) {
90 auto control = upstream->formOutgoingControlMessage(messages.control);
91 if (control) {
92 return ChainedOutgoingProduct(nullptr, control);
93 } else {
94 LOG_ERROR << "Generating outgoing control message failed";
95 return nullopt;
96 }
97 } else {
98 return messages;
99 }
100 } else {
101 return ChainedOutgoingProduct();
102 }
103 }
104
prepareAndSendResponse(optional<ChainedOutgoingProduct> outgoing,std::function<bool (ChainedOutgoingProduct)> send)105 void MediaHandlerElement::prepareAndSendResponse(optional<ChainedOutgoingProduct> outgoing,
106 std::function<bool(ChainedOutgoingProduct)> send) {
107 if (outgoing.has_value()) {
108 auto message = outgoing.value();
109 auto response = processOutgoingResponse(message);
110 if (response.has_value()) {
111 if (!send(response.value())) {
112 LOG_DEBUG << "Send failed";
113 }
114 } else {
115 LOG_DEBUG << "No response to send";
116 }
117 }
118 }
119
120 message_ptr
formIncomingControlMessage(message_ptr message,std::function<bool (ChainedOutgoingProduct)> send)121 MediaHandlerElement::formIncomingControlMessage(message_ptr message,
122 std::function<bool(ChainedOutgoingProduct)> send) {
123 assert(message);
124 auto product = processIncomingControlMessage(message);
125 prepareAndSendResponse(product.outgoing, send);
126 if (product.incoming) {
127 if (downstream) {
128 return downstream->formIncomingControlMessage(product.incoming, send);
129 } else {
130 return product.incoming;
131 }
132 } else {
133 return nullptr;
134 }
135 }
136
137 ChainedMessagesProduct
formIncomingBinaryMessage(ChainedMessagesProduct messages,std::function<bool (ChainedOutgoingProduct)> send)138 MediaHandlerElement::formIncomingBinaryMessage(ChainedMessagesProduct messages,
139 std::function<bool(ChainedOutgoingProduct)> send) {
140 assert(messages && !messages->empty());
141 auto product = processIncomingBinaryMessage(messages);
142 prepareAndSendResponse(product.outgoing, send);
143 if (product.incoming) {
144 if (downstream) {
145 return downstream->formIncomingBinaryMessage(product.incoming, send);
146 } else {
147 return product.incoming;
148 }
149 } else {
150 return nullptr;
151 }
152 }
153
formOutgoingControlMessage(message_ptr message)154 message_ptr MediaHandlerElement::formOutgoingControlMessage(message_ptr message) {
155 assert(message);
156 auto newMessage = processOutgoingControlMessage(message);
157 assert(newMessage);
158 if (!newMessage) {
159 LOG_ERROR << "Failed to generate outgoing message";
160 return nullptr;
161 }
162 if (upstream) {
163 return upstream->formOutgoingControlMessage(newMessage);
164 } else {
165 return newMessage;
166 }
167 }
168
169 optional<ChainedOutgoingProduct>
formOutgoingBinaryMessage(ChainedOutgoingProduct product)170 MediaHandlerElement::formOutgoingBinaryMessage(ChainedOutgoingProduct product) {
171 assert(product.messages && !product.messages->empty());
172 auto newProduct = processOutgoingBinaryMessage(product.messages, product.control);
173 assert(!product.control || newProduct.control);
174 assert(newProduct.messages && !newProduct.messages->empty());
175 if (product.control && !newProduct.control) {
176 LOG_ERROR << "Outgoing message must not remove control message";
177 return nullopt;
178 }
179 if (!newProduct.messages || newProduct.messages->empty()) {
180 LOG_ERROR << "Failed to generate message";
181 return nullopt;
182 }
183 if (upstream) {
184 return upstream->formOutgoingBinaryMessage(newProduct);
185 } else {
186 return newProduct;
187 }
188 }
189
190 ChainedIncomingControlProduct
processIncomingControlMessage(message_ptr messages)191 MediaHandlerElement::processIncomingControlMessage(message_ptr messages) {
192 return {messages};
193 }
194
processOutgoingControlMessage(message_ptr messages)195 message_ptr MediaHandlerElement::processOutgoingControlMessage(message_ptr messages) {
196 return messages;
197 }
198
199 ChainedIncomingProduct
processIncomingBinaryMessage(ChainedMessagesProduct messages)200 MediaHandlerElement::processIncomingBinaryMessage(ChainedMessagesProduct messages) {
201 return {messages};
202 }
203
204 ChainedOutgoingProduct
processOutgoingBinaryMessage(ChainedMessagesProduct messages,message_ptr control)205 MediaHandlerElement::processOutgoingBinaryMessage(ChainedMessagesProduct messages,
206 message_ptr control) {
207 return {messages, control};
208 }
209
210 shared_ptr<MediaHandlerElement>
chainWith(shared_ptr<MediaHandlerElement> upstream)211 MediaHandlerElement::chainWith(shared_ptr<MediaHandlerElement> upstream) {
212 assert(this->upstream == nullptr);
213 assert(upstream->downstream == nullptr);
214 this->upstream = upstream;
215 upstream->downstream = shared_from_this();
216 return upstream;
217 }
218
219 } // namespace rtc
220
221 #endif /* RTC_ENABLE_MEDIA */
222