OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
qml_udp_outbound_socket.hpp
1#pragma once
2#include <ossia/network/context.hpp>
3#include <ossia/network/sockets/udp_socket.hpp>
4
5#include <ossia-qt/protocols/utils.hpp>
6
7#include <QJSValue>
8#include <QObject>
9#include <QQmlEngine>
10
11#include <nano_observer.hpp>
12
13#include <verdigris>
14
15namespace ossia::qt
16{
17
18class qml_udp_outbound_socket
19 : public QObject
20 , public Nano::Observer
21 , public protocols_sender
22{
23 W_OBJECT(qml_udp_outbound_socket)
24public:
25 struct state
26 {
27 ossia::net::udp_send_socket socket;
28 std::atomic_bool alive{true};
29 ossia::net::encoding enc{ossia::net::encoding::none};
30
31 state(
32 const ossia::net::outbound_socket_configuration& conf,
33 boost::asio::io_context& ctx,
34 ossia::net::encoding e = ossia::net::encoding::none)
35 : socket{conf, ctx}
36 {
37 enc = e;
38 }
39 };
40
41 ossia::net::udp_send_socket* socket = nullptr;
42
43 qml_udp_outbound_socket() { }
44
45 ~qml_udp_outbound_socket()
46 {
47 if(m_state)
48 {
49 m_state->alive = false;
50 close();
51 }
52 }
53
54 bool isOpen() const noexcept { return m_state != nullptr; }
55
56 void open(
57 const ossia::net::outbound_socket_configuration& conf,
58 boost::asio::io_context& ctx,
59 ossia::net::encoding e = ossia::net::encoding::none)
60 {
61 m_state = std::make_shared<state>(conf, ctx, e);
62 socket = &m_state->socket;
63
64 if(onClose.isCallable())
65 m_state->socket.on_close.connect<&qml_udp_outbound_socket::on_close>(*this);
66
67 m_state->socket.connect();
68
69 if(onOpen.isCallable())
70 onOpen.call({qjsEngine(this)->newQObject(this)});
71 }
72
73 void close()
74 {
75 if(!m_state)
76 return;
77 if(!m_state->socket.m_socket.is_open())
78 return;
79 auto st = m_state;
80 boost::asio::post(st->socket.m_context, [st] {
81 try
82 {
83 st->socket.m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_both);
84 }
85 catch(...)
86 {
87 }
88 st->socket.m_socket.close();
89 st->socket.on_close();
90 });
91 }
92 W_SLOT(close)
93
94 void on_close()
95 {
96 if(!m_state || !m_state->alive)
97 return;
98 ossia::qt::run_async(this, [=, this] { onClose.call(); }, Qt::AutoConnection);
99 }
100
101 void write(QByteArray buffer)
102 {
103 if(!m_state)
104 return;
105 auto st = m_state;
106 if(st->enc != ossia::net::encoding::none)
107 buffer = apply_encoding(st->enc, buffer);
108 boost::asio::dispatch(st->socket.m_context, [st, buffer = std::move(buffer)] {
109 if(st->alive)
110 st->socket.write(buffer.data(), buffer.size());
111 });
112 }
113 W_SLOT(write)
114
115 void osc(QByteArray address, QJSValueList values)
116 {
117 if(socket)
118 this->send_osc(address, values);
119 }
120 W_SLOT(osc)
121
122 QJSValue onOpen;
123 QJSValue onClose;
124 QJSValue onError;
125
126private:
127 std::shared_ptr<state> m_state;
128};
129}
Definition qml_device.cpp:43