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