diff --git a/.vscode/settings.json b/.vscode/settings.json
index cad09eb087a905316b6a64f97397395f62999098..5ade3be30bc98eaff91ee89c367e108180dc4476 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -62,6 +62,21 @@
         "xtr1common": "cpp",
         "xtree": "cpp",
         "xutility": "cpp",
-        "thread": "cpp"
+        "thread": "cpp",
+        "*.ipp": "cpp",
+        "clocale": "cpp",
+        "csignal": "cpp",
+        "cstdarg": "cpp",
+        "cwctype": "cpp",
+        "atomic": "cpp",
+        "*.tcc": "cpp",
+        "bitset": "cpp",
+        "codecvt": "cpp",
+        "complex": "cpp",
+        "condition_variable": "cpp",
+        "future": "cpp",
+        "mutex": "cpp",
+        "numeric": "cpp",
+        "typeindex": "cpp"
     }
 }
\ No newline at end of file
diff --git a/include/rew/common/tokenizer.h b/include/rew/common/tokenizer.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc499144a70c0f68accfa8fef9b59f5340d041d7
--- /dev/null
+++ b/include/rew/common/tokenizer.h
@@ -0,0 +1,79 @@
+#ifndef REW_COMMON_TOKENIZER_H
+#define REW_COMMON_TOKENIZER_H
+
+#include <string>
+#include <vector>
+#include "../config.h"
+
+REW_NAMESPACE {
+    template<class T, typename CharTrait = std::char_traits<T>, typename Allocator = std::allocator<T>>
+    class Tokenizer {
+    public:
+        Tokenizer(const std::basic_string<T, CharTrait, Allocator>& str, const std::basic_string<T, CharTrait, Allocator>& delim) :ptr(str), del(delim) {
+            pos = 0;
+            last = 0;
+        }
+
+        bool getNext(std::basic_string<T, CharTrait, Allocator>* str) {
+            // Loop until all tokens found
+            while (del.size() > 0 && (pos = ptr.find(del, pos)) != std::basic_string<T, CharTrait, Allocator>::npos) {
+                // Do we have non-empty token?
+                if (last < pos && pos - last > 0) {
+                    if (str != NULL)*str = ptr.substr(last, pos - last);
+                    pos += del.size();
+                    last = pos;
+                    return true;
+                }
+                pos += del.size();
+                last = pos;
+            }
+            // add the last token (will also include a whole string when no delim was found)
+            if (last < ptr.size()) {
+                if (str != NULL)*str = ptr.substr(last, ptr.size() - last);
+                last = ptr.size();
+                return true;
+            }
+            return false;
+        }
+
+        std::basic_string<T, CharTrait, Allocator> getNext() {
+            std::basic_string<T, CharTrait, Allocator> str;
+            getNext(&str);
+            return str;
+        }
+
+        bool skipNext() {
+            return getNext(NULL);
+        }
+
+        bool hasNext() {
+            size_t tempLast = last;
+            size_t tempPos = pos;
+            bool result = getNext(NULL);
+            last = tempLast;
+            pos = tempPos;
+            return result;
+        }
+
+        size_t getPos() {
+            return pos;
+        }
+
+    private:
+        const std::basic_string<T, CharTrait, Allocator>& ptr;
+        const std::basic_string<T, CharTrait, Allocator> del;
+        size_t pos = 0;
+        size_t last = 0;
+    };
+
+    inline std::vector<std::string> getTokens(const std::string& str, const std::string& delim) {
+        std::vector<std::string> tokens;
+        Tokenizer<char> tokenizer(str, delim);
+        while(tokenizer.hasNext()) {
+            tokens.push_back(tokenizer.getNext());
+        }
+        return tokens;
+    }
+}
+
+#endif
diff --git a/include/rew/decoder/http_connection.h b/include/rew/decoder/http_connection.h
new file mode 100644
index 0000000000000000000000000000000000000000..c76e62df515ffc9277582b55686a0ba7a90dc4e6
--- /dev/null
+++ b/include/rew/decoder/http_connection.h
@@ -0,0 +1,28 @@
+#ifndef REW_HTTP_CONNECTION_H
+#define REW_HTTP_CONNECTION_H
+
+#include "../config.h"
+
+REW_NAMESPACE {
+    class HttpServer;
+
+    /*!
+     * @ingroup decoder
+     */
+    class REW_API HttpConnection {
+    public:
+        HttpConnection(HttpServer& server);
+        virtual ~HttpConnection() = default;
+
+        virtual void start() = 0;
+        virtual void stop() = 0;
+        void send(const std::string& contentType, int status, const std::string& body);
+        virtual void sendRaw(std::shared_ptr<std::string> payload) = 0;
+    protected:
+        void receive(const std::string& payload);
+    private:
+        HttpServer& server;
+    };
+}
+
+#endif
diff --git a/include/rew/decoder/http_server.h b/include/rew/decoder/http_server.h
new file mode 100644
index 0000000000000000000000000000000000000000..30a0e8f90c16006097df1697cc57a0a08f2fcec4
--- /dev/null
+++ b/include/rew/decoder/http_server.h
@@ -0,0 +1,40 @@
+#ifndef REW_HTTP_SERVER_H
+#define REW_HTTP_SERVER_H
+
+#include <unordered_map>
+#include <mutex>
+#include <memory>
+#include <string>
+#include <vector>
+#include <list>
+#include "../common/input.h"
+#include "../common/named_raw_file.h"
+
+REW_NAMESPACE {
+    class HttpConnection;
+
+    /*!
+     * @ingroup decoder
+     */
+    class REW_API HttpServer: public Input<NamedRawFile> {
+    public:
+        HttpServer() = default;
+        virtual ~HttpServer() = default;
+
+        void process(const NamedRawFile* data, size_t length) override;
+        void serve(HttpConnection& con, const std::string& file);
+        void disconnect(const std::shared_ptr<HttpConnection>& connection);
+        virtual void start() = 0;
+        virtual void stop() = 0;
+
+    protected:
+        void accept(const std::shared_ptr<HttpConnection>& connection);
+
+    private:
+        std::unordered_map<std::string, std::string> files;
+        std::list<std::shared_ptr<HttpConnection>> connections;
+        std::mutex mutex;
+    };
+}
+
+#endif
diff --git a/include/rew/decoder/tcp_http_connection.h b/include/rew/decoder/tcp_http_connection.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd1d98b980320e58faf2a59a302df105a6393b0f
--- /dev/null
+++ b/include/rew/decoder/tcp_http_connection.h
@@ -0,0 +1,28 @@
+#ifndef REW_TCP_HTTP_CONNECTION_H
+#define REW_TCP_HTTP_CONNECTION_H
+
+#include "http_connection.h"
+
+REW_NAMESPACE {
+    class TcpHttpServer;
+
+    /*!
+     * @ingroup decoder
+     */
+    class REW_API TcpHttpConnection: public HttpConnection, public std::enable_shared_from_this<TcpHttpConnection> {
+    public:
+        TcpHttpConnection(TcpHttpServer& server, void* socket);
+        virtual ~TcpHttpConnection();
+
+        void start() override;
+        void stop() override;
+        void sendRaw(std::shared_ptr<std::string> payload) override;
+    private:
+        void doRead();
+
+        class Impl;
+        std::shared_ptr<Impl> pimpl;
+    };
+}
+
+#endif
diff --git a/include/rew/decoder/tcp_http_server.h b/include/rew/decoder/tcp_http_server.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a6e88711db010832d7c5d2872b97a92904e0e73
--- /dev/null
+++ b/include/rew/decoder/tcp_http_server.h
@@ -0,0 +1,24 @@
+#ifndef REW_TCP_HTTP_SERVER_H
+#define REW_TCP_HTTP_SERVER_H
+
+#include "http_server.h"
+
+REW_NAMESPACE {
+    /*!
+     * @ingroup decoder
+     */
+    class REW_API TcpHttpServer: public HttpServer {
+    public:
+        TcpHttpServer(const std::string& address, int port);
+        virtual ~TcpHttpServer();
+
+        void start() override;
+        void stop() override;
+
+    private:
+        class Impl;
+        std::unique_ptr<Impl> pimpl;
+    };
+}
+
+#endif
diff --git a/src/rew/decoder-cli/main.cpp b/src/rew/decoder-cli/main.cpp
index a54e11bf829d1c4f695fad4ec0c5f793b75b8d6a..8c1ebef7a34593e5f2c4e45c5ba945f120aecfcf 100644
--- a/src/rew/decoder-cli/main.cpp
+++ b/src/rew/decoder-cli/main.cpp
@@ -8,18 +8,16 @@
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <signal.h>
 #endif
 #include <argagg/argagg.hpp>
 #include <iostream>
+#include <thread>
+#include <future>
 #include <rew/decoder/decoder.h>
 #include <rew/common/named_raw_file.h>
 #include <rew/decoder/physical_audio_source.h>
-#include <thread>
-#include "rew/encoder/audio_sink.h"
-#include "rew/encoder/wav_writer.h"
-#include <future>
-
-static rew::PhysicalAudioSource* gSource = nullptr;
+#include <rew/decoder/tcp_http_server.h>
 
 ///=====================================================================================================================
 std::string getFullPath(const std::string& path) {
@@ -36,25 +34,6 @@ std::string getFullPath(const std::string& path) {
     return std::string(&buffer[0]);
 }
 
-///=====================================================================================================================
-#ifdef _WIN32
-BOOL WINAPI ctrlHandler(const DWORD fdwCtrlType) {
-    switch (fdwCtrlType) {
-        case CTRL_C_EVENT:
-        case CTRL_CLOSE_EVENT:
-        case CTRL_BREAK_EVENT:
-        case CTRL_LOGOFF_EVENT:
-        case CTRL_SHUTDOWN_EVENT:
-            if (gSource) {
-                gSource->close();
-            }
-            return FALSE;
-        default:
-            return FALSE;
-    }
-}
-#endif
-
 ///=====================================================================================================================
 size_t getFileSize(const std::string& path) {
     struct stat info = { 0 };
@@ -102,6 +81,11 @@ argagg::parser argparser{ {
         "output",
         {"-o", "--output"},
         "The output folder", 1
+    },
+    {
+        "serve",
+        {"-s", "--serve"},
+        "Serve the files over http server", 0
     }
  } };
 
@@ -154,21 +138,45 @@ private:
 
 ///=====================================================================================================================
 int main (const int argc, char* argv[]) {
+    static bool terminate = false;
 #ifdef _WIN32
-    SetConsoleCtrlHandler(ctrlHandler, TRUE);
+    SetConsoleCtrlHandler([](const DWORD fdwCtrlType) -> BOOL {
+        switch (fdwCtrlType) {
+            case CTRL_C_EVENT:
+            case CTRL_CLOSE_EVENT:
+            case CTRL_BREAK_EVENT:
+            case CTRL_LOGOFF_EVENT:
+            case CTRL_SHUTDOWN_EVENT:
+                terminate = true;
+                return FALSE;
+            default:
+                return FALSE;
+        }
+    }, TRUE);
+#else
+    struct sigaction sigIntHandler;
+
+    sigIntHandler.sa_handler = [](int num) -> void {
+        (void)num;
+        terminate = true;
+    };
+    sigemptyset(&sigIntHandler.sa_mask);
+    sigIntHandler.sa_flags = 0;
+
+    sigaction(SIGINT, &sigIntHandler, NULL);
 #endif
 
     try {
         const auto args = argparser.parse(argc, argv);
+        std::shared_ptr<rew::Input<rew::NamedRawFile>> sink;
+        std::shared_ptr<rew::TcpHttpServer> server;
 
         if (args["help"]) {
             std::cerr << argparser << std::endl;
             return EXIT_SUCCESS;
         }
-        if (args["listen"]) {
-            if (!args["output"])
-                throw std::runtime_error("Output argument is required!");
 
+        if (args["output"]) {
             const auto outputPath = getFullPath(args["output"].as<std::string>());
 
             if (!pathIsValid(outputPath))
@@ -177,17 +185,37 @@ int main (const int argc, char* argv[]) {
             if (!folderIsValid(outputPath))
                 throw std::runtime_error("Output path: \"" + outputPath + "\" is not a folder!");
 
-            auto sink = std::make_shared<CustomSink>(outputPath);
+            sink = std::make_shared<CustomSink>(outputPath);
+        }
 
-            auto source = std::make_shared<rew::PhysicalAudioSource>();
-            gSource = source.get();
+        else if (args["serve"]) {
+            server = std::make_shared<rew::TcpHttpServer>("localhost", 80);
+            sink = server;
+            server->start();
+        }
 
-            auto decoder = std::make_shared<rew::Decoder>(source, sink, DEFAULT_LOW_TONE_FREQ, DEFAULT_HIGH_TONE_FREQ, DEFAULT_SAMPLE_LENGTH_MS);
+        else {
+            throw std::runtime_error("You need to specify either --output or --serve!");
+        }
+
+        if (args["listen"]) {
+            const auto audio = std::make_shared<rew::PhysicalAudioSource>();
 
-            source->start();
-            source->process();
-            source->close();
+            auto decoder = std::make_shared<rew::Decoder>(audio, sink, DEFAULT_LOW_TONE_FREQ, DEFAULT_HIGH_TONE_FREQ, DEFAULT_SAMPLE_LENGTH_MS);
 
+            auto t = std::thread([=]() -> void {
+                audio->start();
+                audio->process();
+            });
+
+            while(!terminate) {
+                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+            }
+            
+            audio->close();
+            t.join();
+
+            if (server) server->stop();
             return EXIT_SUCCESS;
         }
         else if (args["listen-devices"]) {
@@ -204,34 +232,33 @@ int main (const int argc, char* argv[]) {
             if (!found) {
                 std::cerr << "No devices found" << std::endl;
             }
+            
             return EXIT_SUCCESS;
         }
         else if (args["input"]) {
-            if (!args["output"])
-                throw std::runtime_error("Output argument is required!");
-
-            const auto outputPath = getFullPath(args["output"].as<std::string>());
             const auto inputPath = args["input"].as<std::string>();
 
             if (!pathIsValid(inputPath))
                 throw std::runtime_error("Input file: \"" + inputPath + "\" does not exist!");
 
-            if (!pathIsValid(outputPath))
-                throw std::runtime_error("Output path: \"" + outputPath + "\" does not exist!");
-
-            if (!folderIsValid(outputPath))
-                throw std::runtime_error("Output path: \"" + outputPath + "\" is not a folder!");
-
             auto wav = std::make_shared<rew::WavReader>();
             auto source = std::make_shared<rew::AudioSource>(wav);
-            auto sink = std::make_shared<CustomSink>(outputPath);
 
             auto decoder = std::make_shared<rew::Decoder>(source, sink, DEFAULT_LOW_TONE_FREQ, DEFAULT_HIGH_TONE_FREQ, DEFAULT_SAMPLE_LENGTH_MS);
 
-            source->open(inputPath);
-            source->process();
-            source->close();
+            auto t = std::thread([=]() -> void {
+                source->open(inputPath);
+                source->process();
+                source->close();
+            });
+
+            while(!terminate) {
+                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+            }
+
+            t.join();
 
+            if (server) server->stop();
             return EXIT_SUCCESS;
         } else {
             throw std::runtime_error("You need to specify either --input or --listen");
diff --git a/src/rew/decoder/http_connection.cpp b/src/rew/decoder/http_connection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5149579b4827310962ceb1888520f5be7d755166
--- /dev/null
+++ b/src/rew/decoder/http_connection.cpp
@@ -0,0 +1,44 @@
+#include <sstream>
+#include <rew/decoder/http_connection.h>
+#include <rew/decoder/http_server.h>
+#include <rew/common/tokenizer.h>
+
+///=====================================================================================================================
+rew::HttpConnection::HttpConnection(HttpServer& server)
+    :server(server) {
+
+}
+
+///=====================================================================================================================
+void rew::HttpConnection::send(const std::string& contentType, int status, const std::string& body) {
+    std::stringstream ss;
+    ss << "HTTP/1.1 200 OK\n";
+    ss << "Server: Decoder\n";
+    ss << "Accept-Ranges: bytes\n";
+    ss << "Content-Length: " << std::to_string(body.size()) << "\n";
+    ss << "Connection: close\n";
+    ss << "Content-Type: " << contentType << "\n";
+    ss << "\n";
+    ss << body;
+    sendRaw(std::make_shared<std::string>(ss.str()));
+}
+
+///=====================================================================================================================
+void rew::HttpConnection::receive(const std::string& payload) {
+    try {
+        const auto tokens = getTokens(payload, "\n");
+        if (tokens.size() < 1) {
+            send("text/plain", 400, "Bad request");
+        } else {
+            const auto words = getTokens(tokens[0], " ");
+            if (words.size() < 2 || words[0] != "GET") {
+                send("text/plain", 400, "Bad request");
+            } else {
+                server.serve(*this, words[1]);
+            }
+        }
+    } catch (std::exception& e) {
+        send("text/plain", 500, "Internal server error");
+    }
+}
+
diff --git a/src/rew/decoder/http_server.cpp b/src/rew/decoder/http_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1da8da76beac39a57fbefa6dfd4e91c062cba4ac
--- /dev/null
+++ b/src/rew/decoder/http_server.cpp
@@ -0,0 +1,58 @@
+#include <rew/decoder/http_server.h>
+#include <rew/decoder/http_connection.h>
+
+///=====================================================================================================================
+void rew::HttpServer::process(const NamedRawFile* data, size_t length) {
+    for (size_t i = 0; i < length; i++) {
+        const auto& namedFile = data[i];
+
+        auto terminator = namedFile.length;
+        for (size_t i = 0; i < namedFile.length; i++) {
+            if (namedFile.data[i] == '\0') {
+                terminator = i;
+                break;
+            }
+        }
+
+        if (terminator != namedFile.length) {
+            const auto sptr = reinterpret_cast<const char*>(namedFile.data.get());
+            const auto name = std::string(sptr, terminator);
+
+            const auto contents = reinterpret_cast<const char*>(namedFile.data.get() + terminator + 1);
+            const auto total = namedFile.length - terminator - 1;
+
+            std::cout << "Caching file: " << name << " of size: " << total << " bytes!" << std::endl;
+            std::string data;
+            data.resize(total);
+            std::memcpy(&data[0], contents, total);
+
+            std::lock_guard<std::mutex> guard{mutex};
+            files.insert(std::make_pair(name, std::move(data)));
+        }
+    }
+}
+
+///=====================================================================================================================
+void rew::HttpServer::serve(HttpConnection& con, const std::string& file) {
+    std::lock_guard<std::mutex> guard{mutex};
+    const auto it = files.find(file);
+    if (it == files.end()) {
+        con.send("text/plain", 404, "Not found");
+    } else {
+        con.send("text/plain", 200, it->second);
+    }
+}
+
+///=====================================================================================================================
+void rew::HttpServer::accept(const std::shared_ptr<HttpConnection>& connection){
+    std::lock_guard<std::mutex> guard{mutex};
+    connections.push_back(connection);
+    connection->start();
+}
+
+///=====================================================================================================================
+void rew::HttpServer::disconnect(const std::shared_ptr<HttpConnection>& connection){
+    std::lock_guard<std::mutex> guard{mutex};
+    connection->stop();
+    connections.remove(connection);
+}
diff --git a/src/rew/decoder/tcp_http_connection.cpp b/src/rew/decoder/tcp_http_connection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6615294226011447d5db7b3824e6e90570b06fa7
--- /dev/null
+++ b/src/rew/decoder/tcp_http_connection.cpp
@@ -0,0 +1,76 @@
+#define ASIO_STANDALONE
+#if defined(WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0601
+#endif
+#include <asio.hpp>
+#include <sstream>
+#include <rew/decoder/tcp_http_connection.h>
+#include <rew/decoder/tcp_http_server.h>
+
+///=====================================================================================================================
+class rew::TcpHttpConnection::Impl {
+public:
+    Impl(TcpHttpServer& server, asio::ip::tcp::socket socket)
+        : server(server),
+          socket(std::move(socket)) {
+
+    }
+
+    TcpHttpServer& server;
+    asio::ip::tcp::socket socket;
+    std::array<char, 8192> buffer;
+};
+
+///=====================================================================================================================
+rew::TcpHttpConnection::TcpHttpConnection(TcpHttpServer& server, void* socket)
+    : HttpConnection(server),
+      pimpl(new Impl(server, std::move(*reinterpret_cast<asio::ip::tcp::socket*>(socket)))) {
+
+}
+
+///=====================================================================================================================
+rew::TcpHttpConnection::~TcpHttpConnection(){
+    stop();
+}
+
+///=====================================================================================================================
+void rew::TcpHttpConnection::start(){
+    doRead();
+}
+
+///=====================================================================================================================
+void rew::TcpHttpConnection::stop(){
+    pimpl->socket.close();
+}
+
+///=====================================================================================================================
+void rew::TcpHttpConnection::doRead() {
+    auto self(shared_from_this());
+    pimpl->socket.async_read_some(asio::buffer(pimpl->buffer), [this, self](const std::error_code ec, const size_t length) {
+        if (!ec){
+            const auto payload = std::string(reinterpret_cast<const char*>(pimpl->buffer.data()), length);
+            self->receive(payload);
+        } else if (ec != asio::error::operation_aborted) {
+            pimpl->server.disconnect(shared_from_this());
+        }
+    });
+}
+
+///=====================================================================================================================
+void rew::TcpHttpConnection::sendRaw(std::shared_ptr<std::string> payload) {
+    auto self(shared_from_this());
+    auto buffer = asio::buffer(payload->data(), payload->size());
+    asio::async_write(pimpl->socket, buffer, [this, self, payload](const std::error_code ec, const size_t){
+        (void)payload; //Extend the life of the payload
+        
+        if (!ec) {
+            // Initiate graceful connection closure.
+            asio::error_code ignored_ec;
+            pimpl->socket.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec);
+        }
+
+        if (ec != asio::error::operation_aborted) {
+            pimpl->server.disconnect(shared_from_this());
+        }
+    });
+}
diff --git a/src/rew/decoder/tcp_http_server.cpp b/src/rew/decoder/tcp_http_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3c701c2a6b0ca419240ff02427005d23c23739e
--- /dev/null
+++ b/src/rew/decoder/tcp_http_server.cpp
@@ -0,0 +1,92 @@
+#define ASIO_STANDALONE
+#if defined(WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0601
+#endif
+#include <asio.hpp>
+#include <thread>
+#include <rew/decoder/tcp_http_server.h>
+#include <rew/decoder/tcp_http_connection.h>
+
+///=====================================================================================================================
+class rew::TcpHttpServer::Impl {
+public:
+    Impl(TcpHttpServer& server, const std::string& address, const int port)
+        : server(server),
+          acceptor(ioContext) {
+
+        // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
+        asio::ip::tcp::resolver resolver(ioContext);
+        asio::ip::tcp::endpoint endpoint = 
+            *resolver.resolve(address, std::to_string(port)).begin();
+        acceptor.open(endpoint.protocol());
+        acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
+        acceptor.bind(endpoint);
+        acceptor.listen();
+
+        doAccept();
+
+        std::cout << "Starting http server at " << endpoint.address().to_string() << ":" << endpoint.port() << std::endl;
+    }
+
+    ~Impl() {
+        stop();
+    }
+
+    void doAccept() {
+        acceptor.async_accept([this](const std::error_code ec, asio::ip::tcp::socket socket){
+            if (!acceptor.is_open()){
+                return;
+            }
+
+            if (!ec) {
+                std::shared_ptr<HttpConnection> connection 
+                    = std::make_shared<TcpHttpConnection>(server, reinterpret_cast<void*>(&socket));
+                server.accept(connection);
+            } else {
+                std::cerr << "Http server error: " << ec.message();
+            }
+
+            doAccept();
+        });
+    }
+
+    void start() {
+        thread = std::thread([this]() -> void {
+            ioContext.run();
+        });
+    }
+
+    void stop() {
+        if (thread.joinable()) {
+            ioContext.stop();
+            thread.join();
+        }
+    }
+
+    TcpHttpServer& server;
+    asio::io_context ioContext;
+    asio::ip::tcp::acceptor acceptor;
+    std::thread thread;
+};
+
+///=====================================================================================================================
+rew::TcpHttpServer::TcpHttpServer(const std::string& address, const int port)
+    :pimpl(new Impl(*this, address, port)) {
+
+}
+
+///=====================================================================================================================
+rew::TcpHttpServer::~TcpHttpServer() {
+
+}
+
+///=====================================================================================================================
+void rew::TcpHttpServer::start() {
+    pimpl->start();
+}
+
+///=====================================================================================================================
+void rew::TcpHttpServer::stop() {
+    pimpl->stop();
+}
+
diff --git a/src/rew/encoder/wav_writer.cpp b/src/rew/encoder/wav_writer.cpp
index 2cb3acee6ab9e11c265e6b0597c9ed1c3a895fa5..da7d0a5df48a1fc7f909f5a546bea2cdc1bcc18b 100644
--- a/src/rew/encoder/wav_writer.cpp
+++ b/src/rew/encoder/wav_writer.cpp
@@ -90,7 +90,6 @@ bool rew::WavWriter::write(const unsigned char* data, const size_t length) {
 
     output.write(reinterpret_cast<const char*>(data), length);
     size += length;
-    std::cout << "WavWriter size: " << size << std::endl;
 
     return true;
 }