/** * Copyright (c) 2020 Filip Klembara (in2core) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if RTC_ENABLE_MEDIA #include "mediahandlerelement.hpp" #include "impl/internals.hpp" #include namespace rtc { ChainedMessagesProduct make_chained_messages_product() { return std::make_shared>(); } ChainedMessagesProduct make_chained_messages_product(message_ptr msg) { std::vector msgs = {msg}; return std::make_shared>(msgs); } ChainedOutgoingProduct::ChainedOutgoingProduct(ChainedMessagesProduct messages, message_ptr control) : messages(messages), control(control) {} ChainedIncomingProduct::ChainedIncomingProduct(ChainedMessagesProduct incoming, ChainedMessagesProduct outgoing) : incoming(incoming), outgoing(outgoing) {} ChainedIncomingControlProduct::ChainedIncomingControlProduct( message_ptr incoming, optional outgoing) : incoming(incoming), outgoing(outgoing) {} MediaHandlerElement::MediaHandlerElement() {} void MediaHandlerElement::removeFromChain() { if (upstream) { upstream->downstream = downstream; } if (downstream) { downstream->upstream = upstream; } upstream = nullptr; downstream = nullptr; } void MediaHandlerElement::recursiveRemoveChain() { if (downstream) { // `recursiveRemoveChain` removes last strong reference to downstream element // we need to keep strong reference to prevent deallocation of downstream element // during `recursiveRemoveChain` auto strongDownstreamPtr = downstream; downstream->recursiveRemoveChain(); } removeFromChain(); } optional MediaHandlerElement::processOutgoingResponse(ChainedOutgoingProduct messages) { if (messages.messages) { if (upstream) { auto msgs = upstream->formOutgoingBinaryMessage( ChainedOutgoingProduct(messages.messages, messages.control)); if (msgs.has_value()) { return msgs.value(); } else { LOG_ERROR << "Generating outgoing message failed"; return nullopt; } } else { return messages; } } else if (messages.control) { if (upstream) { auto control = upstream->formOutgoingControlMessage(messages.control); if (control) { return ChainedOutgoingProduct(nullptr, control); } else { LOG_ERROR << "Generating outgoing control message failed"; return nullopt; } } else { return messages; } } else { return ChainedOutgoingProduct(); } } void MediaHandlerElement::prepareAndSendResponse(optional outgoing, std::function send) { if (outgoing.has_value()) { auto message = outgoing.value(); auto response = processOutgoingResponse(message); if (response.has_value()) { if (!send(response.value())) { LOG_DEBUG << "Send failed"; } } else { LOG_DEBUG << "No response to send"; } } } message_ptr MediaHandlerElement::formIncomingControlMessage(message_ptr message, std::function send) { assert(message); auto product = processIncomingControlMessage(message); prepareAndSendResponse(product.outgoing, send); if (product.incoming) { if (downstream) { return downstream->formIncomingControlMessage(product.incoming, send); } else { return product.incoming; } } else { return nullptr; } } ChainedMessagesProduct MediaHandlerElement::formIncomingBinaryMessage(ChainedMessagesProduct messages, std::function send) { assert(messages && !messages->empty()); auto product = processIncomingBinaryMessage(messages); prepareAndSendResponse(product.outgoing, send); if (product.incoming) { if (downstream) { return downstream->formIncomingBinaryMessage(product.incoming, send); } else { return product.incoming; } } else { return nullptr; } } message_ptr MediaHandlerElement::formOutgoingControlMessage(message_ptr message) { assert(message); auto newMessage = processOutgoingControlMessage(message); assert(newMessage); if (!newMessage) { LOG_ERROR << "Failed to generate outgoing message"; return nullptr; } if (upstream) { return upstream->formOutgoingControlMessage(newMessage); } else { return newMessage; } } optional MediaHandlerElement::formOutgoingBinaryMessage(ChainedOutgoingProduct product) { assert(product.messages && !product.messages->empty()); auto newProduct = processOutgoingBinaryMessage(product.messages, product.control); assert(!product.control || newProduct.control); assert(newProduct.messages && !newProduct.messages->empty()); if (product.control && !newProduct.control) { LOG_ERROR << "Outgoing message must not remove control message"; return nullopt; } if (!newProduct.messages || newProduct.messages->empty()) { LOG_ERROR << "Failed to generate message"; return nullopt; } if (upstream) { return upstream->formOutgoingBinaryMessage(newProduct); } else { return newProduct; } } ChainedIncomingControlProduct MediaHandlerElement::processIncomingControlMessage(message_ptr messages) { return {messages}; } message_ptr MediaHandlerElement::processOutgoingControlMessage(message_ptr messages) { return messages; } ChainedIncomingProduct MediaHandlerElement::processIncomingBinaryMessage(ChainedMessagesProduct messages) { return {messages}; } ChainedOutgoingProduct MediaHandlerElement::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) { return {messages, control}; } shared_ptr MediaHandlerElement::chainWith(shared_ptr upstream) { assert(this->upstream == nullptr); assert(upstream->downstream == nullptr); this->upstream = upstream; upstream->downstream = shared_from_this(); return upstream; } } // namespace rtc #endif /* RTC_ENABLE_MEDIA */