Fix being unable to restart session
This commit is contained in:
+2
-3
@@ -80,12 +80,11 @@ void encodeThread(packet_queue_t packets, sample_queue_t samples, config_t confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void capture(packet_queue_t packets, config_t config, void *channel_data) {
|
void capture(safe::signal_t *shutdown_event, packet_queue_t packets, config_t config, void *channel_data) {
|
||||||
auto samples = std::make_shared<sample_queue_t::element_type>();
|
auto samples = std::make_shared<sample_queue_t::element_type>();
|
||||||
std::thread thread { encodeThread, packets, samples, config, channel_data };
|
std::thread thread { encodeThread, packets, samples, config, channel_data };
|
||||||
|
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
packets->stop();
|
|
||||||
samples->stop();
|
samples->stop();
|
||||||
thread.join();
|
thread.join();
|
||||||
});
|
});
|
||||||
@@ -103,7 +102,7 @@ void capture(packet_queue_t packets, config_t config, void *channel_data) {
|
|||||||
auto frame_size = config.packetDuration * stream->sampleRate / 1000;
|
auto frame_size = config.packetDuration * stream->sampleRate / 1000;
|
||||||
int samples_per_frame = frame_size * stream->channelCount;
|
int samples_per_frame = frame_size * stream->channelCount;
|
||||||
|
|
||||||
while(packets->running()) {
|
while(!shutdown_event->peek()) {
|
||||||
std::vector<std::int16_t> sample_buffer;
|
std::vector<std::int16_t> sample_buffer;
|
||||||
sample_buffer.resize(samples_per_frame);
|
sample_buffer.resize(samples_per_frame);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ struct config_t {
|
|||||||
|
|
||||||
using packet_t = util::buffer_t<std::uint8_t>;
|
using packet_t = util::buffer_t<std::uint8_t>;
|
||||||
using packet_queue_t = std::shared_ptr<safe::queue_t<std::pair<void*, packet_t>>>;
|
using packet_queue_t = std::shared_ptr<safe::queue_t<std::pair<void*, packet_t>>>;
|
||||||
void capture(packet_queue_t packets, config_t config, void *channel_data);
|
void capture(safe::signal_t *shutdown_event, packet_queue_t packets, config_t config, void *channel_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -686,7 +686,7 @@ int create_creds(const std::string &pkey, const std::string &cert) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(std::shared_ptr<safe::event_t<bool>> shutdown_event) {
|
void start(std::shared_ptr<safe::signal_t> shutdown_event) {
|
||||||
if(!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) {
|
if(!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) {
|
||||||
if(create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
|
if(create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
|
||||||
shutdown_event->raise(true);
|
shutdown_event->raise(true);
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
|
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
|
||||||
|
|
||||||
namespace nvhttp {
|
namespace nvhttp {
|
||||||
void start(std::shared_ptr<safe::event_t<bool>> shutdown_event);
|
void start(std::shared_ptr<safe::signal_t> shutdown_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SUNSHINE_NVHTTP_H
|
#endif //SUNSHINE_NVHTTP_H
|
||||||
|
|||||||
+26
-12
@@ -46,6 +46,10 @@ public:
|
|||||||
|
|
||||||
explicit rtsp_server_t(std::uint16_t port) : _session_slots (config::stream.channels), _host {net::host_create(_addr, 1, port) } {}
|
explicit rtsp_server_t(std::uint16_t port) : _session_slots (config::stream.channels), _host {net::host_create(_addr, 1, port) } {}
|
||||||
|
|
||||||
|
~rtsp_server_t() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
template<class T, class X>
|
template<class T, class X>
|
||||||
void iterate(std::chrono::duration<T, X> timeout) {
|
void iterate(std::chrono::duration<T, X> timeout) {
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
@@ -114,22 +118,26 @@ public:
|
|||||||
_map_cmd_cb.emplace(type, std::move(cb));
|
_map_cmd_cb.emplace(type, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop(bool all = true) {
|
||||||
for(auto &slot : _session_slots) {
|
for(auto &slot : _session_slots) {
|
||||||
auto session = slot.lock();
|
if (slot && (all || session::state(*slot) == session::state_e::STOPPING)) {
|
||||||
|
session::stop(*slot);
|
||||||
|
session::join(*slot);
|
||||||
|
|
||||||
if (!session) {
|
slot.reset();
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::stream::stop(*session);
|
if(all) {
|
||||||
::stream::join(*session);
|
std::for_each(_host->peers, _host->peers + _host->peerCount, [](auto &peer) {
|
||||||
|
enet_peer_disconnect_now(&peer, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool accept(const std::shared_ptr<session_t> &session) {
|
bool accept(const std::shared_ptr<session_t> &session) {
|
||||||
for(auto &slot : _session_slots) {
|
for(auto &slot : _session_slots) {
|
||||||
if(slot.expired()) {
|
if(!slot) {
|
||||||
slot = session;
|
slot = session;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -150,7 +158,7 @@ private:
|
|||||||
|
|
||||||
std::unordered_map<std::string_view, cmd_func_t> _map_cmd_cb;
|
std::unordered_map<std::string_view, cmd_func_t> _map_cmd_cb;
|
||||||
|
|
||||||
std::vector<std::weak_ptr<session_t>> _session_slots;
|
std::vector<std::shared_ptr<session_t>> _session_slots;
|
||||||
|
|
||||||
ENetAddress _addr;
|
ENetAddress _addr;
|
||||||
net::host_t _host;
|
net::host_t _host;
|
||||||
@@ -367,7 +375,7 @@ void cmd_announce(rtsp_server_t *server, net::peer_t peer, msg_t &&req) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session = alloc_session(config, launch_session->gcm_key, launch_session->iv);
|
auto session = session::alloc(config, launch_session->gcm_key, launch_session->iv);
|
||||||
if(!server->accept(session)) {
|
if(!server->accept(session)) {
|
||||||
BOOST_LOG(info) << "Ran out of slots for client from ["sv << ']';
|
BOOST_LOG(info) << "Ran out of slots for client from ["sv << ']';
|
||||||
|
|
||||||
@@ -375,7 +383,7 @@ void cmd_announce(rtsp_server_t *server, net::peer_t peer, msg_t &&req) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_session(session, platf::from_sockaddr((sockaddr*)&peer->address.address));
|
session::start(*session, platf::from_sockaddr((sockaddr*)&peer->address.address));
|
||||||
|
|
||||||
respond(server->host(), peer, &option, 200, "OK", req->sequenceNumber, {});
|
respond(server->host(), peer, &option, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
@@ -392,7 +400,7 @@ void cmd_play(rtsp_server_t *server, net::peer_t peer, msg_t &&req) {
|
|||||||
respond(server->host(), peer, &option, 200, "OK", req->sequenceNumber, {});
|
respond(server->host(), peer, &option, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtpThread(std::shared_ptr<safe::event_t<bool>> shutdown_event) {
|
void rtpThread(std::shared_ptr<safe::signal_t> shutdown_event) {
|
||||||
input = std::make_shared<input::input_t>();
|
input = std::make_shared<input::input_t>();
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
input.reset();
|
input.reset();
|
||||||
@@ -409,9 +417,15 @@ void rtpThread(std::shared_ptr<safe::event_t<bool>> shutdown_event) {
|
|||||||
|
|
||||||
while(!shutdown_event->peek()) {
|
while(!shutdown_event->peek()) {
|
||||||
server.iterate(std::min(500ms, config::stream.ping_timeout));
|
server.iterate(std::min(500ms, config::stream.ping_timeout));
|
||||||
}
|
|
||||||
|
|
||||||
|
if(broadcast_shutdown_event.peek()) {
|
||||||
server.stop();
|
server.stop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// cleanup all stopped sessions
|
||||||
|
server.stop(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_msg(PRTSP_MESSAGE msg) {
|
void print_msg(PRTSP_MESSAGE msg) {
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ struct launch_session_t {
|
|||||||
|
|
||||||
extern safe::event_t<launch_session_t> launch_event;
|
extern safe::event_t<launch_session_t> launch_event;
|
||||||
|
|
||||||
void rtpThread(std::shared_ptr<safe::event_t<bool>> shutdown_event);
|
void rtpThread(std::shared_ptr<safe::signal_t> shutdown_event);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
-67
@@ -62,13 +62,6 @@ enum class socket_e : int {
|
|||||||
audio
|
audio
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class state_e : int {
|
|
||||||
STOPPED,
|
|
||||||
STOPPING,
|
|
||||||
STARTING,
|
|
||||||
RUNNING,
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct video_packet_raw_t {
|
struct video_packet_raw_t {
|
||||||
@@ -96,23 +89,20 @@ using audio_packet_t = util::c_ptr<audio_packet_raw_t>;
|
|||||||
|
|
||||||
using message_queue_t = std::shared_ptr<safe::queue_t<std::pair<std::uint16_t, std::string>>>;
|
using message_queue_t = std::shared_ptr<safe::queue_t<std::pair<std::uint16_t, std::string>>>;
|
||||||
using message_queue_queue_t = std::shared_ptr<safe::queue_t<std::tuple<socket_e, asio::ip::address, message_queue_t>>>;
|
using message_queue_queue_t = std::shared_ptr<safe::queue_t<std::tuple<socket_e, asio::ip::address, message_queue_t>>>;
|
||||||
using session_queue_t = std::shared_ptr<safe::queue_t<std::pair<std::string, std::shared_ptr<session_t>>>>;
|
using session_queue_t = std::shared_ptr<safe::queue_t<std::pair<std::string, session_t*>>>;
|
||||||
|
|
||||||
struct broadcast_ctx_t {
|
struct broadcast_ctx_t {
|
||||||
safe::event_t<bool> shutdown_event;
|
|
||||||
|
|
||||||
video::packet_queue_t video_packets;
|
video::packet_queue_t video_packets;
|
||||||
audio::packet_queue_t audio_packets;
|
audio::packet_queue_t audio_packets;
|
||||||
|
|
||||||
message_queue_queue_t message_queue_queue;
|
message_queue_queue_t message_queue_queue;
|
||||||
session_queue_t session_queue;
|
session_queue_t session_queue;
|
||||||
|
|
||||||
|
std::thread recv_thread;
|
||||||
std::thread video_thread;
|
std::thread video_thread;
|
||||||
std::thread audio_thread;
|
std::thread audio_thread;
|
||||||
std::thread control_thread;
|
std::thread control_thread;
|
||||||
|
|
||||||
std::thread recv_thread;
|
|
||||||
|
|
||||||
asio::io_service io;
|
asio::io_service io;
|
||||||
|
|
||||||
udp::socket video_sock { io, udp::endpoint(udp::v4(), VIDEO_STREAM_PORT) };
|
udp::socket video_sock { io, udp::endpoint(udp::v4(), VIDEO_STREAM_PORT) };
|
||||||
@@ -136,17 +126,17 @@ struct session_t {
|
|||||||
crypto::aes_t gcm_key;
|
crypto::aes_t gcm_key;
|
||||||
crypto::aes_t iv;
|
crypto::aes_t iv;
|
||||||
|
|
||||||
std::atomic<state_e> state;
|
safe::signal_t shutdown_event;
|
||||||
|
std::atomic<session::state_e> state;
|
||||||
};
|
};
|
||||||
|
|
||||||
void videoThread(std::shared_ptr<session_t> session, std::string addr_str);
|
|
||||||
void audioThread(std::shared_ptr<session_t> session, std::string addr_str);
|
|
||||||
|
|
||||||
int start_broadcast(broadcast_ctx_t &ctx);
|
int start_broadcast(broadcast_ctx_t &ctx);
|
||||||
void end_broadcast(broadcast_ctx_t &ctx);
|
void end_broadcast(broadcast_ctx_t &ctx);
|
||||||
|
|
||||||
std::shared_ptr<input::input_t> input;
|
std::shared_ptr<input::input_t> input;
|
||||||
|
|
||||||
static auto broadcast = safe::make_shared<broadcast_ctx_t>(start_broadcast, end_broadcast);
|
static auto broadcast = safe::make_shared<broadcast_ctx_t>(start_broadcast, end_broadcast);
|
||||||
|
safe::signal_t broadcast_shutdown_event;
|
||||||
|
|
||||||
class control_server_t {
|
class control_server_t {
|
||||||
public:
|
public:
|
||||||
@@ -155,27 +145,30 @@ public:
|
|||||||
|
|
||||||
explicit control_server_t(session_queue_t session_queue, std::uint16_t port) : session_queue { session_queue }, _host { net::host_create(_addr, config::stream.channels, port) } {}
|
explicit control_server_t(session_queue_t session_queue, std::uint16_t port) : session_queue { session_queue }, _host { net::host_create(_addr, config::stream.channels, port) } {}
|
||||||
|
|
||||||
template<class T, class X>
|
void populate_addr_to_session() {
|
||||||
void iterate(std::chrono::duration<T, X> timeout) {
|
|
||||||
ENetEvent event;
|
|
||||||
auto res = enet_host_service(_host.get(), &event, std::chrono::floor<std::chrono::milliseconds>(timeout).count());
|
|
||||||
|
|
||||||
if(res > 0) {
|
|
||||||
while(session_queue->peek()) {
|
while(session_queue->peek()) {
|
||||||
auto session_opt = session_queue->pop();
|
auto session_opt = session_queue->pop();
|
||||||
if(!session_opt) {
|
if(!session_opt) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TUPLE_2D_REF(addr_string, session, *session_opt);
|
TUPLE_2D_REF(addr_string, session, *session_opt);
|
||||||
|
|
||||||
if(session) {
|
if(session) {
|
||||||
_map_addr_session.try_emplace(addr_string, session);
|
_map_addr_session.try_emplace(addr_string, session).second;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_map_addr_session.erase(addr_string);
|
_map_addr_session.erase(addr_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class X>
|
||||||
|
void iterate(std::chrono::duration<T, X> timeout) {
|
||||||
|
ENetEvent event;
|
||||||
|
auto res = enet_host_service(_host.get(), &event, std::chrono::floor<std::chrono::milliseconds>(timeout).count());
|
||||||
|
|
||||||
|
populate_addr_to_session();
|
||||||
|
if(res > 0) {
|
||||||
auto addr_string = platf::from_sockaddr((sockaddr*)&event.peer->address.address);
|
auto addr_string = platf::from_sockaddr((sockaddr*)&event.peer->address.address);
|
||||||
|
|
||||||
auto it = _map_addr_session.find(addr_string);
|
auto it = _map_addr_session.find(addr_string);
|
||||||
@@ -206,7 +199,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
cb->second(session.get(), payload);
|
cb->second(session, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -216,8 +209,8 @@ public:
|
|||||||
case ENET_EVENT_TYPE_DISCONNECT:
|
case ENET_EVENT_TYPE_DISCONNECT:
|
||||||
BOOST_LOG(info) << "CLIENT DISCONNECTED"sv;
|
BOOST_LOG(info) << "CLIENT DISCONNECTED"sv;
|
||||||
// No more clients to send video data to ^_^
|
// No more clients to send video data to ^_^
|
||||||
if(session->state == state_e::RUNNING) {
|
if(session->state == session::state_e::RUNNING) {
|
||||||
stop(*session);
|
session::stop(*session);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ENET_EVENT_TYPE_NONE:
|
case ENET_EVENT_TYPE_NONE:
|
||||||
@@ -233,7 +226,7 @@ public:
|
|||||||
void send(const std::string_view &payload);
|
void send(const std::string_view &payload);
|
||||||
|
|
||||||
std::unordered_map<std::uint16_t, std::function<void(session_t *, const std::string_view&)>> _map_type_cb;
|
std::unordered_map<std::uint16_t, std::function<void(session_t *, const std::string_view&)>> _map_type_cb;
|
||||||
std::unordered_map<std::string, std::shared_ptr<session_t>> _map_addr_session;
|
std::unordered_map<std::string, session_t*> _map_addr_session;
|
||||||
|
|
||||||
session_queue_t session_queue;
|
session_queue_t session_queue;
|
||||||
|
|
||||||
@@ -356,7 +349,7 @@ void control_server_t::send(const std::string_view & payload) {
|
|||||||
enet_host_flush(_host.get());
|
enet_host_flush(_host.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void controlBroadcastThread(safe::event_t<bool> *shutdown_event, session_queue_t session_queue) {
|
void controlBroadcastThread(safe::signal_t *shutdown_event, session_queue_t session_queue) {
|
||||||
control_server_t server { session_queue, CONTROL_PORT };
|
control_server_t server { session_queue, CONTROL_PORT };
|
||||||
|
|
||||||
server.map(packetTypes[IDX_START_A], [&](session_t *session, const std::string_view &payload) {
|
server.map(packetTypes[IDX_START_A], [&](session_t *session, const std::string_view &payload) {
|
||||||
@@ -411,7 +404,7 @@ void controlBroadcastThread(safe::event_t<bool> *shutdown_event, session_queue_t
|
|||||||
|
|
||||||
BOOST_LOG(error) << "Failed to verify tag"sv;
|
BOOST_LOG(error) << "Failed to verify tag"sv;
|
||||||
|
|
||||||
stop(*session);
|
session::stop(*session);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tagged_cipher_length >= 16 + session->iv.size()) {
|
if(tagged_cipher_length >= 16 + session->iv.size()) {
|
||||||
@@ -427,7 +420,7 @@ void controlBroadcastThread(safe::event_t<bool> *shutdown_event, session_queue_t
|
|||||||
for(auto &[addr,session] : server._map_addr_session) {
|
for(auto &[addr,session] : server._map_addr_session) {
|
||||||
if(now > session->pingTimeout) {
|
if(now > session->pingTimeout) {
|
||||||
BOOST_LOG(info) << addr << ": Ping Timeout"sv;
|
BOOST_LOG(info) << addr << ": Ping Timeout"sv;
|
||||||
stop(*session);
|
session::stop(*session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +435,8 @@ void controlBroadcastThread(safe::event_t<bool> *shutdown_event, session_queue_t
|
|||||||
|
|
||||||
server.send(std::string_view {(char*)payload.data(), payload.size()});
|
server.send(std::string_view {(char*)payload.data(), payload.size()});
|
||||||
|
|
||||||
//TODO: Terminate session
|
shutdown_event->raise(true);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.iterate(500ms);
|
server.iterate(500ms);
|
||||||
@@ -519,12 +513,12 @@ void recvThread(broadcast_ctx_t &ctx) {
|
|||||||
video_sock.async_receive_from(asio::buffer(buf[0]), peer, 0, recv_func[0]);
|
video_sock.async_receive_from(asio::buffer(buf[0]), peer, 0, recv_func[0]);
|
||||||
audio_sock.async_receive_from(asio::buffer(buf[1]), peer, 0, recv_func[1]);
|
audio_sock.async_receive_from(asio::buffer(buf[1]), peer, 0, recv_func[1]);
|
||||||
|
|
||||||
while(!ctx.shutdown_event.peek()) {
|
while(!broadcast_shutdown_event.peek()) {
|
||||||
io.run();
|
io.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void videoBroadcastThread(safe::event_t<bool> *shutdown_event, udp::socket &sock, video::packet_queue_t packets) {
|
void videoBroadcastThread(safe::signal_t *shutdown_event, udp::socket &sock, video::packet_queue_t packets) {
|
||||||
int lowseq = 0;
|
int lowseq = 0;
|
||||||
while(auto packet = packets->pop()) {
|
while(auto packet = packets->pop()) {
|
||||||
if(shutdown_event->peek()) {
|
if(shutdown_event->peek()) {
|
||||||
@@ -626,7 +620,7 @@ void videoBroadcastThread(safe::event_t<bool> *shutdown_event, udp::socket &sock
|
|||||||
shutdown_event->raise(true);
|
shutdown_event->raise(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioBroadcastThread(safe::event_t<bool> *shutdown_event, udp::socket &sock, audio::packet_queue_t packets) {
|
void audioBroadcastThread(safe::signal_t *shutdown_event, udp::socket &sock, audio::packet_queue_t packets) {
|
||||||
uint16_t frame{1};
|
uint16_t frame{1};
|
||||||
|
|
||||||
while (auto packet = packets->pop()) {
|
while (auto packet = packets->pop()) {
|
||||||
@@ -658,9 +652,9 @@ int start_broadcast(broadcast_ctx_t &ctx) {
|
|||||||
ctx.message_queue_queue = std::make_shared<message_queue_queue_t::element_type>();
|
ctx.message_queue_queue = std::make_shared<message_queue_queue_t::element_type>();
|
||||||
ctx.session_queue = std::make_shared<session_queue_t::element_type>();
|
ctx.session_queue = std::make_shared<session_queue_t::element_type>();
|
||||||
|
|
||||||
ctx.video_thread = std::thread { videoBroadcastThread, &ctx.shutdown_event, std::ref(ctx.video_sock), ctx.video_packets };
|
ctx.video_thread = std::thread { videoBroadcastThread, &broadcast_shutdown_event, std::ref(ctx.video_sock), ctx.video_packets };
|
||||||
ctx.audio_thread = std::thread { audioBroadcastThread, &ctx.shutdown_event, std::ref(ctx.audio_sock), ctx.audio_packets };
|
ctx.audio_thread = std::thread { audioBroadcastThread, &broadcast_shutdown_event, std::ref(ctx.audio_sock), ctx.audio_packets };
|
||||||
ctx.control_thread = std::thread { controlBroadcastThread, &ctx.shutdown_event, ctx.session_queue };
|
ctx.control_thread = std::thread { controlBroadcastThread, &broadcast_shutdown_event, ctx.session_queue };
|
||||||
|
|
||||||
ctx.recv_thread = std::thread { recvThread, std::ref(ctx) };
|
ctx.recv_thread = std::thread { recvThread, std::ref(ctx) };
|
||||||
|
|
||||||
@@ -668,25 +662,32 @@ int start_broadcast(broadcast_ctx_t &ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void end_broadcast(broadcast_ctx_t &ctx) {
|
void end_broadcast(broadcast_ctx_t &ctx) {
|
||||||
ctx.shutdown_event.raise(true);
|
broadcast_shutdown_event.raise(true);
|
||||||
|
|
||||||
|
// Minimize delay stopping video/audio threads
|
||||||
ctx.video_packets->stop();
|
ctx.video_packets->stop();
|
||||||
ctx.audio_packets->stop();
|
ctx.audio_packets->stop();
|
||||||
|
|
||||||
ctx.message_queue_queue->stop();
|
ctx.message_queue_queue->stop();
|
||||||
ctx.io.stop();
|
ctx.io.stop();
|
||||||
|
|
||||||
ctx.video_sock.cancel();
|
ctx.video_sock.close();
|
||||||
ctx.audio_sock.cancel();
|
ctx.audio_sock.close();
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Waiting for video thread to end..."sv;
|
|
||||||
ctx.video_thread.join();
|
|
||||||
BOOST_LOG(debug) << "Waiting for audio thread to end..."sv;
|
|
||||||
ctx.audio_thread.join();
|
|
||||||
BOOST_LOG(debug) << "Waiting for control thread to end..."sv;
|
|
||||||
ctx.control_thread.join();
|
|
||||||
BOOST_LOG(debug) << "All broadcasting threads ended"sv;
|
|
||||||
|
|
||||||
ctx.video_packets.reset();
|
ctx.video_packets.reset();
|
||||||
ctx.audio_packets.reset();
|
ctx.audio_packets.reset();
|
||||||
|
|
||||||
|
BOOST_LOG(debug) << "Waiting for main listening thread to end..."sv;
|
||||||
|
ctx.recv_thread.join();
|
||||||
|
BOOST_LOG(debug) << "Waiting for main video thread to end..."sv;
|
||||||
|
ctx.video_thread.join();
|
||||||
|
BOOST_LOG(debug) << "Waiting for main audio thread to end..."sv;
|
||||||
|
ctx.audio_thread.join();
|
||||||
|
BOOST_LOG(debug) << "Waiting for main control thread to end..."sv;
|
||||||
|
ctx.control_thread.join();
|
||||||
|
BOOST_LOG(debug) << "All broadcasting threads ended"sv;
|
||||||
|
|
||||||
|
broadcast_shutdown_event.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, asio::ip::address &addr, std::chrono::milliseconds timeout) {
|
int recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, asio::ip::address &addr, std::chrono::milliseconds timeout) {
|
||||||
@@ -721,12 +722,12 @@ int recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, asio::ip::address &
|
|||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
void videoThread(std::shared_ptr<session_t> session, std::string addr_str) {
|
void videoThread(session_t *session, std::string addr_str) {
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
stop(*session);
|
session::stop(*session);
|
||||||
});
|
});
|
||||||
|
|
||||||
while(session->state == state_e::STARTING) {
|
while(session->state == session::state_e::STARTING) {
|
||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,15 +743,15 @@ void videoThread(std::shared_ptr<session_t> session, std::string addr_str) {
|
|||||||
session->video_peer.port(port);
|
session->video_peer.port(port);
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Start capturing Video"sv;
|
BOOST_LOG(debug) << "Start capturing Video"sv;
|
||||||
video::capture(ref->video_packets, session->idr_events, session->config.monitor, session.get());
|
video::capture(&session->shutdown_event, ref->video_packets, session->idr_events, session->config.monitor, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioThread(std::shared_ptr<session_t> session, std::string addr_str) {
|
void audioThread(session_t *session, std::string addr_str) {
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
stop(*session);
|
session::stop(*session);
|
||||||
});
|
});
|
||||||
|
|
||||||
while(session->state == state_e::STARTING) {
|
while(session->state == session::state_e::STARTING) {
|
||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,11 +767,17 @@ void audioThread(std::shared_ptr<session_t> session, std::string addr_str) {
|
|||||||
session->audio_peer.port(port);
|
session->audio_peer.port(port);
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Start capturing Audio"sv;
|
BOOST_LOG(debug) << "Start capturing Audio"sv;
|
||||||
audio::capture(ref->audio_packets, session->config.audio, session.get());
|
audio::capture(&session->shutdown_event, ref->audio_packets, session->config.audio, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace session {
|
||||||
|
state_e state(session_t &session) {
|
||||||
|
return session.state.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop(session_t &session) {
|
void stop(session_t &session) {
|
||||||
session.idr_events->stop();
|
session.broadcast_ref->session_queue->raise(session.video_peer.address().to_string(), nullptr);
|
||||||
|
session.shutdown_event.raise(true);
|
||||||
|
|
||||||
auto expected = state_e::RUNNING;
|
auto expected = state_e::RUNNING;
|
||||||
session.state.compare_exchange_strong(expected, state_e::STOPPING);
|
session.state.compare_exchange_strong(expected, state_e::STOPPING);
|
||||||
@@ -783,19 +790,19 @@ void join(session_t &session) {
|
|||||||
session.audioThread.join();
|
session.audioThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_session(std::shared_ptr<session_t> session, const std::string &addr_string) {
|
void start(session_t &session, const std::string &addr_string) {
|
||||||
session->broadcast_ref = broadcast.ref();
|
session.broadcast_ref = broadcast.ref();
|
||||||
session->broadcast_ref->session_queue->raise(addr_string, session);
|
session.broadcast_ref->session_queue->raise(addr_string, &session);
|
||||||
|
|
||||||
session->pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
|
session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
|
||||||
|
|
||||||
session->audioThread = std::thread {audioThread, session, addr_string};
|
session.audioThread = std::thread {audioThread, &session, addr_string};
|
||||||
session->videoThread = std::thread {videoThread, session, addr_string};
|
session.videoThread = std::thread {videoThread, &session, addr_string};
|
||||||
|
|
||||||
session->state.store(state_e::RUNNING, std::memory_order_relaxed);
|
session.state.store(state_e::RUNNING, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<session_t> alloc_session(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv) {
|
std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv) {
|
||||||
auto session = std::make_shared<session_t>();
|
auto session = std::make_shared<session_t>();
|
||||||
|
|
||||||
session->config = config;
|
session->config = config;
|
||||||
@@ -808,3 +815,4 @@ std::shared_ptr<session_t> alloc_session(config_t &config, crypto::aes_t &gcm_ke
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+12
-2
@@ -26,13 +26,23 @@ struct config_t {
|
|||||||
std::optional<int> gcmap;
|
std::optional<int> gcmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<session_t> alloc_session(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
namespace session {
|
||||||
void start_session(std::shared_ptr<session_t> session, const std::string &addr_string);
|
enum class state_e : int {
|
||||||
|
STOPPED,
|
||||||
|
STOPPING,
|
||||||
|
STARTING,
|
||||||
|
RUNNING,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
||||||
|
void start(session_t &session, const std::string &addr_string);
|
||||||
void stop(session_t &session);
|
void stop(session_t &session);
|
||||||
void join(session_t &session);
|
void join(session_t &session);
|
||||||
|
state_e state(session_t &session);
|
||||||
|
}
|
||||||
|
|
||||||
extern std::shared_ptr<input::input_t> input;
|
extern std::shared_ptr<input::input_t> input;
|
||||||
|
extern safe::signal_t broadcast_shutdown_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SUNSHINE_STREAM_H
|
#endif //SUNSHINE_STREAM_H
|
||||||
|
|||||||
+13
-3
@@ -93,7 +93,7 @@ public:
|
|||||||
bool peek() {
|
bool peek() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
return (bool)_status;
|
return _continue && (bool)_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
@@ -104,7 +104,15 @@ public:
|
|||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool running() const {
|
void reset() {
|
||||||
|
std::lock_guard lg{_lock};
|
||||||
|
|
||||||
|
_continue = true;
|
||||||
|
|
||||||
|
_status = util::false_v<status_t>;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool running() const {
|
||||||
return _continue;
|
return _continue;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -137,7 +145,7 @@ public:
|
|||||||
bool peek() {
|
bool peek() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
return !_queue.empty();
|
return _continue && !_queue.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Rep, class Period>
|
template<class Rep, class Period>
|
||||||
@@ -315,6 +323,8 @@ auto make_shared(F_Construct &&fc, F_Destruct &&fd) {
|
|||||||
std::forward<F_Construct>(fc), std::forward<F_Destruct>(fd)
|
std::forward<F_Construct>(fc), std::forward<F_Destruct>(fd)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using signal_t = event_t<bool>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SUNSHINE_THREAD_SAFE_H
|
#endif //SUNSHINE_THREAD_SAFE_H
|
||||||
|
|||||||
+2
-1
@@ -193,6 +193,7 @@ void end_capture(capture_thread_ctx_t &capture_thread_ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void capture(
|
void capture(
|
||||||
|
safe::signal_t *shutdown_event,
|
||||||
packet_queue_t packets,
|
packet_queue_t packets,
|
||||||
idr_event_t idr_events,
|
idr_event_t idr_events,
|
||||||
config_t config,
|
config_t config,
|
||||||
@@ -344,7 +345,7 @@ void capture(
|
|||||||
// Initiate scaling context with correct height and width
|
// Initiate scaling context with correct height and width
|
||||||
sws_t sws;
|
sws_t sws;
|
||||||
while(auto img = images->pop()) {
|
while(auto img = images->pop()) {
|
||||||
if(!idr_events->running()) {
|
if(shutdown_event->peek()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ struct config_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void capture(
|
void capture(
|
||||||
|
safe::signal_t *shutdown_event,
|
||||||
packet_queue_t packets,
|
packet_queue_t packets,
|
||||||
idr_event_t idr_events,
|
idr_event_t idr_events,
|
||||||
config_t config,
|
config_t config,
|
||||||
|
|||||||
Reference in New Issue
Block a user