Skip to content
Snippets Groups Projects
muebreceiver.cc 2.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "muebreceiver.h"
    
    #include <QNetworkDatagram>
    #include <QUdpSocket>
    
    #include "configuration.h"
    
    class MuebReceiverPrivate {
      Q_DECLARE_PUBLIC(MuebReceiver)
      Q_DISABLE_COPY(MuebReceiverPrivate)
    
     public:
      explicit MuebReceiverPrivate(MuebReceiver *q)
          : frame(configuration.frame()), q_ptr(q) {
        socket.bind(configuration.broadcast_animation_port());
    
        QObject::connect(&socket, &QUdpSocket::readyRead, q,
                         &MuebReceiver::readPendingDatagrams);
    
        qInfo() << "[MuebReceiver] UDP Socket will receive packets on port"
                << configuration.broadcast_animation_port();
      }
    
      Configuration configuration;
      libmueb::Frame frame;
      QUdpSocket socket;
      MuebReceiver *q_ptr;
    };
    
    MuebReceiver::MuebReceiver(QObject *parent)
        : QObject(parent), d_ptr_(new MuebReceiverPrivate(this)) {}
    
    MuebReceiver::~MuebReceiver() { delete d_ptr_; }
    
    MuebReceiver &MuebReceiver::Instance() {
      static MuebReceiver instance;
    
      return instance;
    }
    
    libmueb::Frame MuebReceiver::frame() { return d_ptr_->frame; }
    
    inline void datagram_uncompress_error() {
      qWarning() << "[MuebReceiver] Processed packet is invalid! Check the header "
                    "or packet contents(size)";
    }
    
    void MuebReceiver::readPendingDatagrams() {
      while (d_ptr_->socket.hasPendingDatagrams()) {
        if (d_ptr_->socket.pendingDatagramSize() ==
            d_ptr_->configuration.packet_size()) {
          QNetworkDatagram datagram = d_ptr_->socket.receiveDatagram();
          QByteArray data = datagram.data();
    
          // Process datagram
          // Packet header check
          // Check protocol
          if (data[0] != d_ptr_->configuration.protocol_type()) {
            datagram_uncompress_error();
            return;
          }
    
          auto packet_number = data[1];
          if (packet_number >= d_ptr_->configuration.max_packet_number() ||
              packet_number < 0) {
            datagram_uncompress_error();
            return;
          }
    
          data.remove(0, d_ptr_->configuration.packet_header_size());
          auto frame_begin =
              d_ptr_->frame.bits() +
              packet_number * d_ptr_->configuration.max_pixel_per_datagram();
    
          // Uncompress 1 byte into 2 color components
          if (d_ptr_->configuration.color_depth() < 5) {
            for (auto i : data) {
              *frame_begin = i & 0xf0;
              frame_begin++;
              *frame_begin = (i & 0x0f) << d_ptr_->configuration.factor();
              frame_begin++;
            }
            // No compression
          } else {
            // FIXME use better copy method
            for (auto i : data) {
              *frame_begin = i;
              frame_begin++;
            }
          }
    
          emit(FrameChanged(d_ptr_->frame));
        }
        // Drop invalid packet
        else {
          qWarning() << "[MuebReceiver] Packet has invalid size!"
                     << d_ptr_->socket.pendingDatagramSize() << "bytes";
    
          d_ptr_->socket.receiveDatagram(0);
        }
      }
    }