/**
* Copyright (c) 2020 Filip Klembara (in2core)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see .
*/
#if RTC_ENABLE_MEDIA
#include "mediachainablehandler.hpp"
namespace rtc {
MediaChainableHandler::MediaChainableHandler(shared_ptr root): MediaHandler(), root(root), leaf(root) { }
MediaChainableHandler::~MediaChainableHandler() {
leaf->recursiveRemoveChain();
}
bool MediaChainableHandler::sendProduct(ChainedOutgoingProduct product) {
bool result = true;
if (product.control) {
assert(product.control->type == Message::Control);
auto sendResult = send(product.control);
if(!sendResult) {
LOG_DEBUG << "Failed to send control message";
}
result = result && sendResult;
}
if (product.messages) {
auto messages = product.messages;
for (unsigned i = 0; i < messages->size(); i++) {
auto message = messages->at(i);
if (!message) {
LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << messages->size();
}
auto sendResult = send(make_message(*message));
if(!sendResult) {
LOG_DEBUG << "Failed to send message " << i + 1 << "/" << messages->size();
}
result = result && sendResult;
}
}
return result;
}
message_ptr MediaChainableHandler::handleIncomingBinary(message_ptr msg) {
assert(msg->type == Message::Binary);
auto messages = root->split(msg);
auto incoming = leaf->formIncomingBinaryMessage(messages, [this](ChainedOutgoingProduct outgoing) {
return sendProduct(outgoing);
});
if (incoming) {
return root->reduce(incoming);
} else {
return nullptr;
}
}
message_ptr MediaChainableHandler::handleIncomingControl(message_ptr msg) {
assert(msg->type == Message::Control);
auto incoming = leaf->formIncomingControlMessage(msg, [this](ChainedOutgoingProduct outgoing) {
return sendProduct(outgoing);
});
assert(!incoming || incoming->type == Message::Control);
return incoming;
}
message_ptr MediaChainableHandler::handleOutgoingBinary(message_ptr msg) {
assert(msg->type == Message::Binary);
auto messages = make_chained_messages_product(msg);
auto optOutgoing = root->formOutgoingBinaryMessage(ChainedOutgoingProduct(messages));
if (!optOutgoing.has_value()) {
LOG_ERROR << "Generating outgoing message failed";
return nullptr;
}
auto outgoing = optOutgoing.value();
if (outgoing.control) {
if(!send(outgoing.control)) {
LOG_DEBUG << "Failed to send control message";
}
}
auto lastMessage = outgoing.messages->back();
if (!lastMessage) {
LOG_DEBUG << "Invalid message to send";
return nullptr;
}
for (unsigned i = 0; i < outgoing.messages->size() - 1; i++) {
auto message = outgoing.messages->at(i);
if (!message) {
LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << outgoing.messages->size();
}
if(!send(make_message(*message))) {
LOG_DEBUG << "Failed to send message " << i + 1 << "/" << outgoing.messages->size();
}
}
return make_message(*lastMessage);
}
message_ptr MediaChainableHandler::handleOutgoingControl(message_ptr msg) {
assert(msg->type == Message::Control);
auto outgoing = root->formOutgoingControlMessage(msg);
assert(!outgoing || outgoing->type == Message::Control);
if (!outgoing) {
LOG_ERROR << "Generating outgoing control message failed";
return nullptr;
}
return outgoing;
}
message_ptr MediaChainableHandler::outgoing(message_ptr ptr) {
assert(ptr);
if (!ptr) {
LOG_ERROR << "Outgoing message is nullptr, ignoring";
return nullptr;
}
std::lock_guard guard(inoutMutex);
if (ptr->type == Message::Binary) {
return handleOutgoingBinary(ptr);
} else if (ptr->type == Message::Control) {
return handleOutgoingControl(ptr);
}
return ptr;
}
message_ptr MediaChainableHandler::incoming(message_ptr ptr) {
if (!ptr) {
LOG_ERROR << "Incoming message is nullptr, ignoring";
return nullptr;
}
std::lock_guard guard(inoutMutex);
if (ptr->type == Message::Binary) {
return handleIncomingBinary(ptr);
} else if (ptr->type == Message::Control) {
return handleIncomingControl(ptr);
}
return ptr;
}
bool MediaChainableHandler::send(message_ptr msg) {
try {
outgoingCallback(std::move(msg));
return true;
} catch (const std::exception &e) {
LOG_DEBUG << "Send in RTCP chain handler failed: " << e.what();
}
return false;
}
void MediaChainableHandler::addToChain(shared_ptr chainable) {
assert(leaf);
leaf = leaf->chainWith(chainable);
}
} // namespace rtc
#endif /* RTC_ENABLE_MEDIA */