clang: adjust formatting rules (#1015)
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
AccessModifierOffset: -2
|
AccessModifierOffset: -2
|
||||||
AlignAfterOpenBracket: DontAlign
|
AlignAfterOpenBracket: DontAlign
|
||||||
AlignConsecutiveAssignments: Consecutive
|
AlignConsecutiveAssignments: false
|
||||||
AlignOperands: Align
|
AlignOperands: Align
|
||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: false
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
@@ -18,8 +18,9 @@ AllowShortFunctionsOnASingleLine: All
|
|||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
AllowShortLambdasOnASingleLine: All
|
AllowShortLambdasOnASingleLine: All
|
||||||
AllowShortLoopsOnASingleLine: true
|
AllowShortLoopsOnASingleLine: true
|
||||||
AlwaysBreakAfterReturnType: None
|
AlignTrailingComments: false
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakAfterReturnType: All
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterCaseLabel: false
|
AfterCaseLabel: false
|
||||||
@@ -37,32 +38,32 @@ BraceWrapping:
|
|||||||
SplitEmptyRecord: true
|
SplitEmptyRecord: true
|
||||||
BreakBeforeBinaryOperators: None
|
BreakBeforeBinaryOperators: None
|
||||||
BreakBeforeTernaryOperators: false
|
BreakBeforeTernaryOperators: false
|
||||||
BreakConstructorInitializers: BeforeColon
|
BreakConstructorInitializers: AfterColon
|
||||||
BreakInheritanceList: BeforeColon
|
BreakInheritanceList: AfterColon
|
||||||
ColumnLimit: 0
|
ColumnLimit: 0
|
||||||
CompactNamespaces: false
|
CompactNamespaces: false
|
||||||
ContinuationIndentWidth: 2
|
ContinuationIndentWidth: 2
|
||||||
IndentCaseLabels: false
|
IndentCaseLabels: true
|
||||||
IndentPPDirectives: None
|
IndentPPDirectives: BeforeHash
|
||||||
IndentWidth: 2
|
IndentWidth: 2
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
MaxEmptyLinesToKeep: 2
|
MaxEmptyLinesToKeep: 1
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: All
|
||||||
ObjCSpaceAfterProperty: false
|
ObjCSpaceAfterProperty: true
|
||||||
ObjCSpaceBeforeProtocolList: true
|
ObjCSpaceBeforeProtocolList: true
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: false
|
ReflowComments: false
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: true
|
||||||
SpaceAfterLogicalNot: false
|
SpaceAfterLogicalNot: false
|
||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: true
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeCpp11BracedList: true
|
SpaceBeforeCpp11BracedList: true
|
||||||
SpaceBeforeCtorInitializerColon: true
|
SpaceBeforeCtorInitializerColon: false
|
||||||
SpaceBeforeInheritanceColon: true
|
SpaceBeforeInheritanceColon: false
|
||||||
SpaceBeforeParens: Never
|
SpaceBeforeParens: ControlStatements
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
SpaceInEmptyParentheses: false
|
SpaceInEmptyParentheses: false
|
||||||
SpacesBeforeTrailingComments: 1
|
SpacesBeforeTrailingComments: 2
|
||||||
SpacesInAngles: Never
|
SpacesInAngles: Never
|
||||||
SpacesInCStyleCastParentheses: false
|
SpacesInCStyleCastParentheses: false
|
||||||
SpacesInContainerLiterals: false
|
SpacesInContainerLiterals: false
|
||||||
|
|||||||
40
scripts/update_clang_format.py
Normal file
40
scripts/update_clang_format.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# standard imports
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# variables
|
||||||
|
directories = [
|
||||||
|
'src',
|
||||||
|
'tools',
|
||||||
|
os.path.join('third-party', 'glad'),
|
||||||
|
os.path.join('third-party', 'nvfbc'),
|
||||||
|
os.path.join('third-party', 'wayland-protocols')
|
||||||
|
]
|
||||||
|
file_types = [
|
||||||
|
'cpp',
|
||||||
|
'h',
|
||||||
|
'm',
|
||||||
|
'mm'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def clang_format(file: str):
|
||||||
|
print(f'Formatting {file} ...')
|
||||||
|
subprocess.run(['clang-format', '-i', file])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Main entry point.
|
||||||
|
"""
|
||||||
|
# walk the directories
|
||||||
|
for directory in directories:
|
||||||
|
for root, dirs, files in os.walk(directory):
|
||||||
|
for file in files:
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
if os.path.isfile(file_path) and file.rsplit('.')[-1] in file_types:
|
||||||
|
clang_format(file=file_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -25,10 +25,13 @@ struct audio_ctx_t {
|
|||||||
platf::sink_t sink;
|
platf::sink_t sink;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int start_audio_control(audio_ctx_t &ctx);
|
static int
|
||||||
static void stop_audio_control(audio_ctx_t &);
|
start_audio_control(audio_ctx_t &ctx);
|
||||||
|
static void
|
||||||
|
stop_audio_control(audio_ctx_t &);
|
||||||
|
|
||||||
int map_stream(int channels, bool quality);
|
int
|
||||||
|
map_stream(int channels, bool quality);
|
||||||
|
|
||||||
constexpr auto SAMPLE_RATE = 48000;
|
constexpr auto SAMPLE_RATE = 48000;
|
||||||
|
|
||||||
@@ -85,7 +88,8 @@ opus_stream_config_t stream_configs[MAX_STREAM_CONFIG] {
|
|||||||
|
|
||||||
auto control_shared = safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control);
|
auto control_shared = safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control);
|
||||||
|
|
||||||
void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
void
|
||||||
|
encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
||||||
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
|
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
|
||||||
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
||||||
|
|
||||||
@@ -121,7 +125,8 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void capture(safe::mail_t mail, config_t config, void *channel_data) {
|
void
|
||||||
|
capture(safe::mail_t mail, config_t config, void *channel_data) {
|
||||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||||
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
auto stream = &stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
|
||||||
|
|
||||||
@@ -226,7 +231,8 @@ void capture(safe::mail_t mail, config_t config, void *channel_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int map_stream(int channels, bool quality) {
|
int
|
||||||
|
map_stream(int channels, bool quality) {
|
||||||
int shift = quality ? 1 : 0;
|
int shift = quality ? 1 : 0;
|
||||||
switch (channels) {
|
switch (channels) {
|
||||||
case 2:
|
case 2:
|
||||||
@@ -239,7 +245,8 @@ int map_stream(int channels, bool quality) {
|
|||||||
return STEREO;
|
return STEREO;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_audio_control(audio_ctx_t &ctx) {
|
int
|
||||||
|
start_audio_control(audio_ctx_t &ctx) {
|
||||||
auto fg = util::fail_guard([]() {
|
auto fg = util::fail_guard([]() {
|
||||||
BOOST_LOG(warning) << "There will be no audio"sv;
|
BOOST_LOG(warning) << "There will be no audio"sv;
|
||||||
});
|
});
|
||||||
@@ -266,7 +273,8 @@ int start_audio_control(audio_ctx_t &ctx) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_audio_control(audio_ctx_t &ctx) {
|
void
|
||||||
|
stop_audio_control(audio_ctx_t &ctx) {
|
||||||
// restore audio-sink if applicable
|
// restore audio-sink if applicable
|
||||||
if (!ctx.restore_sink) {
|
if (!ctx.restore_sink) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ struct config_t {
|
|||||||
|
|
||||||
using buffer_t = util::buffer_t<std::uint8_t>;
|
using buffer_t = util::buffer_t<std::uint8_t>;
|
||||||
using packet_t = std::pair<void *, buffer_t>;
|
using packet_t = std::pair<void *, buffer_t>;
|
||||||
void capture(safe::mail_t mail, config_t config, void *channel_data);
|
void
|
||||||
|
capture(safe::mail_t mail, config_t config, void *channel_data);
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
32
src/cbs.cpp
32
src/cbs.cpp
@@ -12,7 +12,8 @@ extern "C" {
|
|||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
namespace cbs {
|
namespace cbs {
|
||||||
void close(CodedBitstreamContext *c) {
|
void
|
||||||
|
close(CodedBitstreamContext *c) {
|
||||||
ff_cbs_close(&c);
|
ff_cbs_close(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +32,8 @@ public:
|
|||||||
std::fill_n((std::uint8_t *) this, sizeof(*this), 0);
|
std::fill_n((std::uint8_t *) this, sizeof(*this), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
frag_t &operator=(frag_t &&o) {
|
frag_t &
|
||||||
|
operator=(frag_t &&o) {
|
||||||
std::copy((std::uint8_t *) &o, (std::uint8_t *) (&o + 1), (std::uint8_t *) this);
|
std::copy((std::uint8_t *) &o, (std::uint8_t *) (&o + 1), (std::uint8_t *) this);
|
||||||
|
|
||||||
o.data = nullptr;
|
o.data = nullptr;
|
||||||
@@ -40,7 +42,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
~frag_t() {
|
~frag_t() {
|
||||||
if (data || units) {
|
if (data || units) {
|
||||||
ff_cbs_fragment_free(this);
|
ff_cbs_fragment_free(this);
|
||||||
@@ -48,7 +49,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> write(const cbs::ctx_t &cbs_ctx, std::uint8_t nal, void *uh, AVCodecID codec_id) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
write(const cbs::ctx_t &cbs_ctx, std::uint8_t nal, void *uh, AVCodecID codec_id) {
|
||||||
cbs::frag_t frag;
|
cbs::frag_t frag;
|
||||||
auto err = ff_cbs_insert_unit_content(&frag, -1, nal, uh, nullptr);
|
auto err = ff_cbs_insert_unit_content(&frag, -1, nal, uh, nullptr);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -73,14 +75,16 @@ util::buffer_t<std::uint8_t> write(const cbs::ctx_t &cbs_ctx, std::uint8_t nal,
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> write(std::uint8_t nal, void *uh, AVCodecID codec_id) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
write(std::uint8_t nal, void *uh, AVCodecID codec_id) {
|
||||||
cbs::ctx_t cbs_ctx;
|
cbs::ctx_t cbs_ctx;
|
||||||
ff_cbs_init(&cbs_ctx, codec_id, nullptr);
|
ff_cbs_init(&cbs_ctx, codec_id, nullptr);
|
||||||
|
|
||||||
return write(cbs_ctx, nal, uh, codec_id);
|
return write(cbs_ctx, nal, uh, codec_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> make_sps_h264(const AVCodecContext *ctx) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
make_sps_h264(const AVCodecContext *ctx) {
|
||||||
H264RawSPS sps {};
|
H264RawSPS sps {};
|
||||||
|
|
||||||
/* b_per_p == ctx->max_b_frames for h264 */
|
/* b_per_p == ctx->max_b_frames for h264 */
|
||||||
@@ -91,7 +95,6 @@ util::buffer_t<std::uint8_t> make_sps_h264(const AVCodecContext *ctx) {
|
|||||||
auto mb_width = (FFALIGN(ctx->width, 16) / 16) * 16;
|
auto mb_width = (FFALIGN(ctx->width, 16) / 16) * 16;
|
||||||
auto mb_height = (FFALIGN(ctx->height, 16) / 16) * 16;
|
auto mb_height = (FFALIGN(ctx->height, 16) / 16) * 16;
|
||||||
|
|
||||||
|
|
||||||
sps.nal_unit_header.nal_ref_idc = 3;
|
sps.nal_unit_header.nal_ref_idc = 3;
|
||||||
sps.nal_unit_header.nal_unit_type = H264_NAL_SPS;
|
sps.nal_unit_header.nal_unit_type = H264_NAL_SPS;
|
||||||
|
|
||||||
@@ -168,7 +171,8 @@ util::buffer_t<std::uint8_t> make_sps_h264(const AVCodecContext *ctx) {
|
|||||||
return write(sps.nal_unit_header.nal_unit_type, (void *) &sps.nal_unit_header, AV_CODEC_ID_H264);
|
return write(sps.nal_unit_header.nal_unit_type, (void *) &sps.nal_unit_header, AV_CODEC_ID_H264);
|
||||||
}
|
}
|
||||||
|
|
||||||
hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
hevc_t
|
||||||
|
make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
||||||
cbs::ctx_t ctx;
|
cbs::ctx_t ctx;
|
||||||
if (ff_cbs_init(&ctx, AV_CODEC_ID_H265, nullptr)) {
|
if (ff_cbs_init(&ctx, AV_CODEC_ID_H265, nullptr)) {
|
||||||
return {};
|
return {};
|
||||||
@@ -184,7 +188,6 @@ hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto vps_p = ((CodedBitstreamH265Context *) ctx->priv_data)->active_vps;
|
auto vps_p = ((CodedBitstreamH265Context *) ctx->priv_data)->active_vps;
|
||||||
auto sps_p = ((CodedBitstreamH265Context *) ctx->priv_data)->active_sps;
|
auto sps_p = ((CodedBitstreamH265Context *) ctx->priv_data)->active_sps;
|
||||||
|
|
||||||
@@ -209,7 +212,6 @@ hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
|||||||
vui.transfer_characteristics = avctx->color_trc;
|
vui.transfer_characteristics = avctx->color_trc;
|
||||||
vui.matrix_coefficients = avctx->colorspace;
|
vui.matrix_coefficients = avctx->colorspace;
|
||||||
|
|
||||||
|
|
||||||
vui.vui_timing_info_present_flag = vps.vps_timing_info_present_flag;
|
vui.vui_timing_info_present_flag = vps.vps_timing_info_present_flag;
|
||||||
vui.vui_num_units_in_tick = vps.vps_num_units_in_tick;
|
vui.vui_num_units_in_tick = vps.vps_num_units_in_tick;
|
||||||
vui.vui_time_scale = vps.vps_time_scale;
|
vui.vui_time_scale = vps.vps_time_scale;
|
||||||
@@ -228,7 +230,6 @@ hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
|||||||
cbs::ctx_t write_ctx;
|
cbs::ctx_t write_ctx;
|
||||||
ff_cbs_init(&write_ctx, AV_CODEC_ID_H265, nullptr);
|
ff_cbs_init(&write_ctx, AV_CODEC_ID_H265, nullptr);
|
||||||
|
|
||||||
|
|
||||||
return hevc_t {
|
return hevc_t {
|
||||||
nal_t {
|
nal_t {
|
||||||
write(write_ctx, vps.nal_unit_header.nal_unit_type, (void *) &vps.nal_unit_header, AV_CODEC_ID_H265),
|
write(write_ctx, vps.nal_unit_header.nal_unit_type, (void *) &vps.nal_unit_header, AV_CODEC_ID_H265),
|
||||||
@@ -242,7 +243,8 @@ hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> read_sps_h264(const AVPacket *packet) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
read_sps_h264(const AVPacket *packet) {
|
||||||
cbs::ctx_t ctx;
|
cbs::ctx_t ctx;
|
||||||
if (ff_cbs_init(&ctx, AV_CODEC_ID_H264, nullptr)) {
|
if (ff_cbs_init(&ctx, AV_CODEC_ID_H264, nullptr)) {
|
||||||
return {};
|
return {};
|
||||||
@@ -262,14 +264,16 @@ util::buffer_t<std::uint8_t> read_sps_h264(const AVPacket *packet) {
|
|||||||
return write(h264->nal_unit_type, (void *) h264, AV_CODEC_ID_H264);
|
return write(h264->nal_unit_type, (void *) h264, AV_CODEC_ID_H264);
|
||||||
}
|
}
|
||||||
|
|
||||||
h264_t make_sps_h264(const AVCodecContext *ctx, const AVPacket *packet) {
|
h264_t
|
||||||
|
make_sps_h264(const AVCodecContext *ctx, const AVPacket *packet) {
|
||||||
return h264_t {
|
return h264_t {
|
||||||
make_sps_h264(ctx),
|
make_sps_h264(ctx),
|
||||||
read_sps_h264(packet),
|
read_sps_h264(packet),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_sps(const AVPacket *packet, int codec_id) {
|
bool
|
||||||
|
validate_sps(const AVPacket *packet, int codec_id) {
|
||||||
cbs::ctx_t ctx;
|
cbs::ctx_t ctx;
|
||||||
if (ff_cbs_init(&ctx, (AVCodecID) codec_id, nullptr)) {
|
if (ff_cbs_init(&ctx, (AVCodecID) codec_id, nullptr)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -22,13 +22,16 @@ struct h264_t {
|
|||||||
nal_t sps;
|
nal_t sps;
|
||||||
};
|
};
|
||||||
|
|
||||||
hevc_t make_sps_hevc(const AVCodecContext *ctx, const AVPacket *packet);
|
hevc_t
|
||||||
h264_t make_sps_h264(const AVCodecContext *ctx, const AVPacket *packet);
|
make_sps_hevc(const AVCodecContext *ctx, const AVPacket *packet);
|
||||||
|
h264_t
|
||||||
|
make_sps_h264(const AVCodecContext *ctx, const AVPacket *packet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if SPS->VUI is present
|
* Check if SPS->VUI is present
|
||||||
*/
|
*/
|
||||||
bool validate_sps(const AVPacket *packet, int codec_id);
|
bool
|
||||||
|
validate_sps(const AVPacket *packet, int codec_id);
|
||||||
} // namespace cbs
|
} // namespace cbs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
120
src/config.cpp
120
src/config.cpp
@@ -71,7 +71,8 @@ enum coder_e : int {
|
|||||||
cavlc = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC,
|
cavlc = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<preset_e> preset_from_view(const std::string_view &preset) {
|
std::optional<preset_e>
|
||||||
|
preset_from_view(const std::string_view &preset) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (preset == #x##sv) return x
|
if (preset == #x##sv) return x
|
||||||
_CONVERT_(p1);
|
_CONVERT_(p1);
|
||||||
@@ -85,7 +86,8 @@ std::optional<preset_e> preset_from_view(const std::string_view &preset) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<tune_e> tune_from_view(const std::string_view &tune) {
|
std::optional<tune_e>
|
||||||
|
tune_from_view(const std::string_view &tune) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (tune == #x##sv) return x
|
if (tune == #x##sv) return x
|
||||||
_CONVERT_(hq);
|
_CONVERT_(hq);
|
||||||
@@ -96,7 +98,8 @@ std::optional<tune_e> tune_from_view(const std::string_view &tune) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<rc_e> rc_from_view(const std::string_view &rc) {
|
std::optional<rc_e>
|
||||||
|
rc_from_view(const std::string_view &rc) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (rc == #x##sv) return x
|
if (rc == #x##sv) return x
|
||||||
_CONVERT_(constqp);
|
_CONVERT_(constqp);
|
||||||
@@ -106,7 +109,8 @@ std::optional<rc_e> rc_from_view(const std::string_view &rc) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int coder_from_view(const std::string_view &coder) {
|
int
|
||||||
|
coder_from_view(const std::string_view &coder) {
|
||||||
if (coder == "auto"sv) return _auto;
|
if (coder == "auto"sv) return _auto;
|
||||||
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
||||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||||
@@ -194,7 +198,8 @@ enum coder_e : int {
|
|||||||
cavlc = AMF_VIDEO_ENCODER_CALV
|
cavlc = AMF_VIDEO_ENCODER_CALV
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<int> quality_from_view(const std::string_view &quality_type, int codec) {
|
std::optional<int>
|
||||||
|
quality_from_view(const std::string_view &quality_type, int codec) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (quality_type == #x##sv) return codec == 0 ? (int) quality_hevc_e::x : (int) quality_h264_e::x
|
if (quality_type == #x##sv) return codec == 0 ? (int) quality_hevc_e::x : (int) quality_h264_e::x
|
||||||
_CONVERT_(quality);
|
_CONVERT_(quality);
|
||||||
@@ -204,7 +209,8 @@ std::optional<int> quality_from_view(const std::string_view &quality_type, int c
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> rc_from_view(const std::string_view &rc, int codec) {
|
std::optional<int>
|
||||||
|
rc_from_view(const std::string_view &rc, int codec) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (rc == #x##sv) return codec == 0 ? (int) rc_hevc_e::x : (int) rc_h264_e::x
|
if (rc == #x##sv) return codec == 0 ? (int) rc_hevc_e::x : (int) rc_h264_e::x
|
||||||
_CONVERT_(cqp);
|
_CONVERT_(cqp);
|
||||||
@@ -215,7 +221,8 @@ std::optional<int> rc_from_view(const std::string_view &rc, int codec) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> usage_from_view(const std::string_view &rc, int codec) {
|
std::optional<int>
|
||||||
|
usage_from_view(const std::string_view &rc, int codec) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (rc == #x##sv) return codec == 0 ? (int) usage_hevc_e::x : (int) usage_h264_e::x
|
if (rc == #x##sv) return codec == 0 ? (int) usage_hevc_e::x : (int) usage_h264_e::x
|
||||||
_CONVERT_(transcoding);
|
_CONVERT_(transcoding);
|
||||||
@@ -226,7 +233,8 @@ std::optional<int> usage_from_view(const std::string_view &rc, int codec) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int coder_from_view(const std::string_view &coder) {
|
int
|
||||||
|
coder_from_view(const std::string_view &coder) {
|
||||||
if (coder == "auto"sv) return _auto;
|
if (coder == "auto"sv) return _auto;
|
||||||
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
||||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||||
@@ -252,7 +260,8 @@ enum cavlc_e : int {
|
|||||||
disabled = false
|
disabled = false
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<int> preset_from_view(const std::string_view &preset) {
|
std::optional<int>
|
||||||
|
preset_from_view(const std::string_view &preset) {
|
||||||
#define _CONVERT_(x) \
|
#define _CONVERT_(x) \
|
||||||
if (preset == #x##sv) return x
|
if (preset == #x##sv) return x
|
||||||
_CONVERT_(veryslow);
|
_CONVERT_(veryslow);
|
||||||
@@ -266,7 +275,8 @@ std::optional<int> preset_from_view(const std::string_view &preset) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> coder_from_view(const std::string_view &coder) {
|
std::optional<int>
|
||||||
|
coder_from_view(const std::string_view &coder) {
|
||||||
if (coder == "auto"sv) return _auto;
|
if (coder == "auto"sv) return _auto;
|
||||||
if (coder == "cabac"sv || coder == "ac"sv) return disabled;
|
if (coder == "cabac"sv || coder == "ac"sv) return disabled;
|
||||||
if (coder == "cavlc"sv || coder == "vlc"sv) return enabled;
|
if (coder == "cavlc"sv || coder == "vlc"sv) return enabled;
|
||||||
@@ -283,7 +293,8 @@ enum coder_e : int {
|
|||||||
cavlc
|
cavlc
|
||||||
};
|
};
|
||||||
|
|
||||||
int coder_from_view(const std::string_view &coder) {
|
int
|
||||||
|
coder_from_view(const std::string_view &coder) {
|
||||||
if (coder == "auto"sv) return _auto;
|
if (coder == "auto"sv) return _auto;
|
||||||
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
|
||||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||||
@@ -291,19 +302,22 @@ int coder_from_view(const std::string_view &coder) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int allow_software_from_view(const std::string_view &software) {
|
int
|
||||||
|
allow_software_from_view(const std::string_view &software) {
|
||||||
if (software == "allowed"sv || software == "forced") return 1;
|
if (software == "allowed"sv || software == "forced") return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int force_software_from_view(const std::string_view &software) {
|
int
|
||||||
|
force_software_from_view(const std::string_view &software) {
|
||||||
if (software == "forced") return 1;
|
if (software == "forced") return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rt_from_view(const std::string_view &rt) {
|
int
|
||||||
|
rt_from_view(const std::string_view &rt) {
|
||||||
if (rt == "disabled" || rt == "off" || rt == "0") return 0;
|
if (rt == "disabled" || rt == "off" || rt == "0") return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -431,19 +445,23 @@ sunshine_t sunshine {
|
|||||||
{}, // prep commands
|
{}, // prep commands
|
||||||
};
|
};
|
||||||
|
|
||||||
bool endline(char ch) {
|
bool
|
||||||
|
endline(char ch) {
|
||||||
return ch == '\r' || ch == '\n';
|
return ch == '\r' || ch == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool space_tab(char ch) {
|
bool
|
||||||
|
space_tab(char ch) {
|
||||||
return ch == ' ' || ch == '\t';
|
return ch == ' ' || ch == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool whitespace(char ch) {
|
bool
|
||||||
|
whitespace(char ch) {
|
||||||
return space_tab(ch) || endline(ch);
|
return space_tab(ch) || endline(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(const char *begin, const char *end) {
|
std::string
|
||||||
|
to_string(const char *begin, const char *end) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
KITTY_WHILE_LOOP(auto pos = begin, pos != end, {
|
KITTY_WHILE_LOOP(auto pos = begin, pos != end, {
|
||||||
@@ -459,7 +477,8 @@ std::string to_string(const char *begin, const char *end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class It>
|
template <class It>
|
||||||
It skip_list(It skipper, It end) {
|
It
|
||||||
|
skip_list(It skipper, It end) {
|
||||||
int stack = 1;
|
int stack = 1;
|
||||||
while (skipper != end && stack) {
|
while (skipper != end && stack) {
|
||||||
if (*skipper == '[') {
|
if (*skipper == '[') {
|
||||||
@@ -511,7 +530,8 @@ parse_option(std::string_view::const_iterator begin, std::string_view::const_ite
|
|||||||
std::make_pair(to_string(begin, end_name), to_string(begin_val, endl)));
|
std::make_pair(to_string(begin, end_name), to_string(begin_val, endl)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> parse_config(const std::string_view &file_content) {
|
std::unordered_map<std::string, std::string>
|
||||||
|
parse_config(const std::string_view &file_content) {
|
||||||
std::unordered_map<std::string, std::string> vars;
|
std::unordered_map<std::string, std::string> vars;
|
||||||
|
|
||||||
auto pos = std::begin(file_content);
|
auto pos = std::begin(file_content);
|
||||||
@@ -536,7 +556,8 @@ std::unordered_map<std::string, std::string> parse_config(const std::string_view
|
|||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input) {
|
void
|
||||||
|
string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
return;
|
return;
|
||||||
@@ -547,7 +568,8 @@ void string_f(std::unordered_map<std::string, std::string> &vars, const std::str
|
|||||||
vars.erase(it);
|
vars.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_restricted_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input, const std::vector<std::string_view> &allowed_vals) {
|
void
|
||||||
|
string_restricted_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input, const std::vector<std::string_view> &allowed_vals) {
|
||||||
std::string temp;
|
std::string temp;
|
||||||
string_f(vars, name, temp);
|
string_f(vars, name, temp);
|
||||||
|
|
||||||
@@ -559,7 +581,8 @@ void string_restricted_f(std::unordered_map<std::string, std::string> &vars, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, fs::path &input) {
|
void
|
||||||
|
path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, fs::path &input) {
|
||||||
// appdata needs to be retrieved once only
|
// appdata needs to be retrieved once only
|
||||||
static auto appdata = platf::appdata();
|
static auto appdata = platf::appdata();
|
||||||
|
|
||||||
@@ -583,7 +606,8 @@ void path_f(std::unordered_map<std::string, std::string> &vars, const std::strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input) {
|
void
|
||||||
|
path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input) {
|
||||||
fs::path temp = input;
|
fs::path temp = input;
|
||||||
|
|
||||||
path_f(vars, name, temp);
|
path_f(vars, name, temp);
|
||||||
@@ -591,7 +615,8 @@ void path_f(std::unordered_map<std::string, std::string> &vars, const std::strin
|
|||||||
input = temp.string();
|
input = temp.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input) {
|
void
|
||||||
|
int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
|
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
@@ -616,7 +641,8 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
|||||||
vars.erase(it);
|
vars.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &input) {
|
void
|
||||||
|
int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &input) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
|
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
@@ -642,7 +668,8 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input, F &&f) {
|
void
|
||||||
|
int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input, F &&f) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
if (!tmp.empty()) {
|
if (!tmp.empty()) {
|
||||||
@@ -651,7 +678,8 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &input, F &&f) {
|
void
|
||||||
|
int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &input, F &&f) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
if (!tmp.empty()) {
|
if (!tmp.empty()) {
|
||||||
@@ -659,7 +687,8 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void int_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input, const std::pair<int, int> &range) {
|
void
|
||||||
|
int_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input, const std::pair<int, int> &range) {
|
||||||
int temp = input;
|
int temp = input;
|
||||||
|
|
||||||
int_f(vars, name, temp);
|
int_f(vars, name, temp);
|
||||||
@@ -670,7 +699,8 @@ void int_between_f(std::unordered_map<std::string, std::string> &vars, const std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool to_bool(std::string &boolean) {
|
bool
|
||||||
|
to_bool(std::string &boolean) {
|
||||||
std::for_each(std::begin(boolean), std::end(boolean), [](char ch) { return (char) std::tolower(ch); });
|
std::for_each(std::begin(boolean), std::end(boolean), [](char ch) { return (char) std::tolower(ch); });
|
||||||
|
|
||||||
return boolean == "true"sv ||
|
return boolean == "true"sv ||
|
||||||
@@ -681,7 +711,8 @@ bool to_bool(std::string &boolean) {
|
|||||||
(std::find(std::begin(boolean), std::end(boolean), '1') != std::end(boolean));
|
(std::find(std::begin(boolean), std::end(boolean), '1') != std::end(boolean));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bool_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, bool &input) {
|
void
|
||||||
|
bool_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, bool &input) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
|
|
||||||
@@ -692,7 +723,8 @@ void bool_f(std::unordered_map<std::string, std::string> &vars, const std::strin
|
|||||||
input = to_bool(tmp);
|
input = to_bool(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void double_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &input) {
|
void
|
||||||
|
double_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &input) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
|
|
||||||
@@ -710,7 +742,8 @@ void double_f(std::unordered_map<std::string, std::string> &vars, const std::str
|
|||||||
input = val;
|
input = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void double_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &input, const std::pair<double, double> &range) {
|
void
|
||||||
|
double_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &input, const std::pair<double, double> &range) {
|
||||||
double temp = input;
|
double temp = input;
|
||||||
|
|
||||||
double_f(vars, name, temp);
|
double_f(vars, name, temp);
|
||||||
@@ -721,7 +754,8 @@ void double_between_f(std::unordered_map<std::string, std::string> &vars, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<std::string> &input) {
|
void
|
||||||
|
list_string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<std::string> &input) {
|
||||||
std::string string;
|
std::string string;
|
||||||
string_f(vars, name, string);
|
string_f(vars, name, string);
|
||||||
|
|
||||||
@@ -763,7 +797,8 @@ void list_string_f(std::unordered_map<std::string, std::string> &vars, const std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_prep_cmd_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<prep_cmd_t> &input) {
|
void
|
||||||
|
list_prep_cmd_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<prep_cmd_t> &input) {
|
||||||
std::string string;
|
std::string string;
|
||||||
string_f(vars, name, string);
|
string_f(vars, name, string);
|
||||||
|
|
||||||
@@ -790,7 +825,8 @@ void list_prep_cmd_f(std::unordered_map<std::string, std::string> &vars, const s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<int> &input) {
|
void
|
||||||
|
list_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<int> &input) {
|
||||||
std::vector<std::string> list;
|
std::vector<std::string> list;
|
||||||
list_string_f(vars, name, list);
|
list_string_f(vars, name, list);
|
||||||
|
|
||||||
@@ -815,7 +851,8 @@ void list_int_f(std::unordered_map<std::string, std::string> &vars, const std::s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_int_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::unordered_map<int, int> &input) {
|
void
|
||||||
|
map_int_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::unordered_map<int, int> &input) {
|
||||||
std::vector<int> list;
|
std::vector<int> list;
|
||||||
list_int_f(vars, name, list);
|
list_int_f(vars, name, list);
|
||||||
|
|
||||||
@@ -834,7 +871,8 @@ void map_int_int_f(std::unordered_map<std::string, std::string> &vars, const std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int apply_flags(const char *line) {
|
int
|
||||||
|
apply_flags(const char *line) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
while (*line != '\0') {
|
while (*line != '\0') {
|
||||||
switch (*line) {
|
switch (*line) {
|
||||||
@@ -861,7 +899,8 @@ int apply_flags(const char *line) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
void
|
||||||
|
apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||||
if (!fs::exists(stream.file_apps.c_str())) {
|
if (!fs::exists(stream.file_apps.c_str())) {
|
||||||
fs::copy_file(SUNSHINE_ASSETS_DIR "/apps.json", stream.file_apps);
|
fs::copy_file(SUNSHINE_ASSETS_DIR "/apps.json", stream.file_apps);
|
||||||
}
|
}
|
||||||
@@ -1047,7 +1086,8 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse(int argc, char *argv[]) {
|
int
|
||||||
|
parse(int argc, char *argv[]) {
|
||||||
std::unordered_map<std::string, std::string> cmd_vars;
|
std::unordered_map<std::string, std::string> cmd_vars;
|
||||||
|
|
||||||
for (auto x = 1; x < argc; ++x) {
|
for (auto x = 1; x < argc; ++x) {
|
||||||
|
|||||||
12
src/config.h
12
src/config.h
@@ -119,8 +119,10 @@ enum flag_e : std::size_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct prep_cmd_t {
|
struct prep_cmd_t {
|
||||||
prep_cmd_t(std::string &&do_cmd, std::string &&undo_cmd) : do_cmd(std::move(do_cmd)), undo_cmd(std::move(undo_cmd)) {}
|
prep_cmd_t(std::string &&do_cmd, std::string &&undo_cmd):
|
||||||
explicit prep_cmd_t(std::string &&do_cmd) : do_cmd(std::move(do_cmd)) {}
|
do_cmd(std::move(do_cmd)), undo_cmd(std::move(undo_cmd)) {}
|
||||||
|
explicit prep_cmd_t(std::string &&do_cmd):
|
||||||
|
do_cmd(std::move(do_cmd)) {}
|
||||||
std::string do_cmd;
|
std::string do_cmd;
|
||||||
std::string undo_cmd;
|
std::string undo_cmd;
|
||||||
};
|
};
|
||||||
@@ -155,7 +157,9 @@ extern nvhttp_t nvhttp;
|
|||||||
extern input_t input;
|
extern input_t input;
|
||||||
extern sunshine_t sunshine;
|
extern sunshine_t sunshine;
|
||||||
|
|
||||||
int parse(int argc, char *argv[]);
|
int
|
||||||
std::unordered_map<std::string, std::string> parse_config(const std::string_view &file_content);
|
parse(int argc, char *argv[]);
|
||||||
|
std::unordered_map<std::string, std::string>
|
||||||
|
parse_config(const std::string_view &file_content);
|
||||||
} // namespace config
|
} // namespace config
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ enum class op_e {
|
|||||||
REMOVE
|
REMOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
void print_req(const req_https_t &request) {
|
void
|
||||||
|
print_req(const req_https_t &request) {
|
||||||
BOOST_LOG(debug) << "METHOD :: "sv << request->method;
|
BOOST_LOG(debug) << "METHOD :: "sv << request->method;
|
||||||
BOOST_LOG(debug) << "DESTINATION :: "sv << request->path;
|
BOOST_LOG(debug) << "DESTINATION :: "sv << request->path;
|
||||||
|
|
||||||
@@ -69,7 +70,8 @@ void print_req(const req_https_t &request) {
|
|||||||
BOOST_LOG(debug) << " [--] "sv;
|
BOOST_LOG(debug) << " [--] "sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_unauthorized(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
send_unauthorized(resp_https_t response, req_https_t request) {
|
||||||
auto address = request->remote_endpoint().address().to_string();
|
auto address = request->remote_endpoint().address().to_string();
|
||||||
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
||||||
const SimpleWeb::CaseInsensitiveMultimap headers {
|
const SimpleWeb::CaseInsensitiveMultimap headers {
|
||||||
@@ -78,7 +80,8 @@ void send_unauthorized(resp_https_t response, req_https_t request) {
|
|||||||
response->write(SimpleWeb::StatusCode::client_error_unauthorized, headers);
|
response->write(SimpleWeb::StatusCode::client_error_unauthorized, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_redirect(resp_https_t response, req_https_t request, const char *path) {
|
void
|
||||||
|
send_redirect(resp_https_t response, req_https_t request, const char *path) {
|
||||||
auto address = request->remote_endpoint().address().to_string();
|
auto address = request->remote_endpoint().address().to_string();
|
||||||
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
||||||
const SimpleWeb::CaseInsensitiveMultimap headers {
|
const SimpleWeb::CaseInsensitiveMultimap headers {
|
||||||
@@ -87,7 +90,8 @@ void send_redirect(resp_https_t response, req_https_t request, const char *path)
|
|||||||
response->write(SimpleWeb::StatusCode::redirection_temporary_redirect, headers);
|
response->write(SimpleWeb::StatusCode::redirection_temporary_redirect, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool authenticate(resp_https_t response, req_https_t request) {
|
bool
|
||||||
|
authenticate(resp_https_t response, req_https_t request) {
|
||||||
auto address = request->remote_endpoint().address().to_string();
|
auto address = request->remote_endpoint().address().to_string();
|
||||||
auto ip_type = net::from_address(address);
|
auto ip_type = net::from_address(address);
|
||||||
|
|
||||||
@@ -132,7 +136,8 @@ bool authenticate(resp_https_t response, req_https_t request) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void not_found(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
not_found(resp_https_t response, req_https_t request) {
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
tree.put("root.<xmlattr>.status_code", 404);
|
tree.put("root.<xmlattr>.status_code", 404);
|
||||||
|
|
||||||
@@ -146,7 +151,8 @@ void not_found(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo - combine these functions into a single function that accepts the page, i.e "index", "pin", "apps"
|
// todo - combine these functions into a single function that accepts the page, i.e "index", "pin", "apps"
|
||||||
void getIndexPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getIndexPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -156,7 +162,8 @@ void getIndexPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getPinPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getPinPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -166,7 +173,8 @@ void getPinPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getAppsPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getAppsPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -179,7 +187,8 @@ void getAppsPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content, headers);
|
response->write(header + content, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getClientsPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getClientsPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -189,7 +198,8 @@ void getClientsPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getConfigPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getConfigPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -199,7 +209,8 @@ void getConfigPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getPasswordPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getPasswordPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -209,7 +220,8 @@ void getPasswordPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getWelcomePage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getWelcomePage(resp_https_t response, req_https_t request) {
|
||||||
print_req(request);
|
print_req(request);
|
||||||
if (!config::sunshine.username.empty()) {
|
if (!config::sunshine.username.empty()) {
|
||||||
send_redirect(response, request, "/");
|
send_redirect(response, request, "/");
|
||||||
@@ -220,7 +232,8 @@ void getWelcomePage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getTroubleshootingPage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getTroubleshootingPage(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -230,7 +243,8 @@ void getTroubleshootingPage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(header + content);
|
response->write(header + content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getFaviconImage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getFaviconImage(resp_https_t response, req_https_t request) {
|
||||||
// todo - combine function with getSunshineLogoImage and possibly getNodeModules
|
// todo - combine function with getSunshineLogoImage and possibly getNodeModules
|
||||||
// todo - use mime_types map
|
// todo - use mime_types map
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -241,7 +255,8 @@ void getFaviconImage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getSunshineLogoImage(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getSunshineLogoImage(resp_https_t response, req_https_t request) {
|
||||||
// todo - combine function with getFaviconImage and possibly getNodeModules
|
// todo - combine function with getFaviconImage and possibly getNodeModules
|
||||||
// todo - use mime_types map
|
// todo - use mime_types map
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -252,12 +267,14 @@ void getSunshineLogoImage(resp_https_t response, req_https_t request) {
|
|||||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isChildPath(fs::path const &base, fs::path const &query) {
|
bool
|
||||||
|
isChildPath(fs::path const &base, fs::path const &query) {
|
||||||
auto relPath = fs::relative(base, query);
|
auto relPath = fs::relative(base, query);
|
||||||
return *(relPath.begin()) != fs::path("..");
|
return *(relPath.begin()) != fs::path("..");
|
||||||
}
|
}
|
||||||
|
|
||||||
void getNodeModules(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getNodeModules(resp_https_t response, req_https_t request) {
|
||||||
print_req(request);
|
print_req(request);
|
||||||
fs::path webDirPath(WEB_DIR);
|
fs::path webDirPath(WEB_DIR);
|
||||||
fs::path nodeModulesPath(webDirPath / "node_modules");
|
fs::path nodeModulesPath(webDirPath / "node_modules");
|
||||||
@@ -290,7 +307,8 @@ void getNodeModules(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getApps(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getApps(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -299,7 +317,8 @@ void getApps(resp_https_t response, req_https_t request) {
|
|||||||
response->write(content);
|
response->write(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getLogs(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getLogs(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -310,7 +329,8 @@ void getLogs(resp_https_t response, req_https_t request) {
|
|||||||
response->write(SimpleWeb::StatusCode::success_ok, content, headers);
|
response->write(SimpleWeb::StatusCode::success_ok, content, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveApp(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
saveApp(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -380,7 +400,8 @@ void saveApp(resp_https_t response, req_https_t request) {
|
|||||||
proc::refresh(config::stream.file_apps);
|
proc::refresh(config::stream.file_apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteApp(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
deleteApp(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -428,7 +449,8 @@ void deleteApp(resp_https_t response, req_https_t request) {
|
|||||||
proc::refresh(config::stream.file_apps);
|
proc::refresh(config::stream.file_apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uploadCover(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
uploadCover(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@@ -489,7 +511,8 @@ void uploadCover(resp_https_t response, req_https_t request) {
|
|||||||
outputTree.put("path", path);
|
outputTree.put("path", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getConfig(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
getConfig(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -514,7 +537,8 @@ void getConfig(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveConfig(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
saveConfig(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -549,7 +573,8 @@ void saveConfig(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void restart(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
restart(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -580,7 +605,8 @@ void restart(resp_https_t response, req_https_t request) {
|
|||||||
outputTree.put("status", true);
|
outputTree.put("status", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePassword(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
savePassword(resp_https_t response, req_https_t request) {
|
||||||
if (!config::sunshine.username.empty() && !authenticate(response, request)) return;
|
if (!config::sunshine.username.empty() && !authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -637,7 +663,8 @@ void savePassword(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void savePin(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
savePin(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -667,7 +694,8 @@ void savePin(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unpairAll(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
unpairAll(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -683,7 +711,8 @@ void unpairAll(resp_https_t response, req_https_t request) {
|
|||||||
outputTree.put("status", true);
|
outputTree.put("status", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeApp(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
closeApp(resp_https_t response, req_https_t request) {
|
||||||
if (!authenticate(response, request)) return;
|
if (!authenticate(response, request)) return;
|
||||||
|
|
||||||
print_req(request);
|
print_req(request);
|
||||||
@@ -700,7 +729,8 @@ void closeApp(resp_https_t response, req_https_t request) {
|
|||||||
outputTree.put("status", true);
|
outputTree.put("status", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
void
|
||||||
|
start() {
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||||
|
|
||||||
auto port_https = map_port(PORT_HTTPS);
|
auto port_https = map_port(PORT_HTTPS);
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
#define WEB_DIR SUNSHINE_ASSETS_DIR "/web/"
|
#define WEB_DIR SUNSHINE_ASSETS_DIR "/web/"
|
||||||
|
|
||||||
|
|
||||||
namespace confighttp {
|
namespace confighttp {
|
||||||
constexpr auto PORT_HTTPS = 1;
|
constexpr auto PORT_HTTPS = 1;
|
||||||
void start();
|
void
|
||||||
|
start();
|
||||||
} // namespace confighttp
|
} // namespace confighttp
|
||||||
|
|
||||||
// mime types map
|
// mime types map
|
||||||
|
|||||||
@@ -6,15 +6,18 @@
|
|||||||
namespace crypto {
|
namespace crypto {
|
||||||
using asn1_string_t = util::safe_ptr<ASN1_STRING, ASN1_STRING_free>;
|
using asn1_string_t = util::safe_ptr<ASN1_STRING, ASN1_STRING_free>;
|
||||||
|
|
||||||
cert_chain_t::cert_chain_t() : _certs {}, _cert_ctx { X509_STORE_CTX_new() } {}
|
cert_chain_t::cert_chain_t():
|
||||||
void cert_chain_t::add(x509_t &&cert) {
|
_certs {}, _cert_ctx { X509_STORE_CTX_new() } {}
|
||||||
|
void
|
||||||
|
cert_chain_t::add(x509_t &&cert) {
|
||||||
x509_store_t x509_store { X509_STORE_new() };
|
x509_store_t x509_store { X509_STORE_new() };
|
||||||
|
|
||||||
X509_STORE_add_cert(x509_store.get(), cert.get());
|
X509_STORE_add_cert(x509_store.get(), cert.get());
|
||||||
_certs.emplace_back(std::make_pair(std::move(cert), std::move(x509_store)));
|
_certs.emplace_back(std::make_pair(std::move(cert), std::move(x509_store)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openssl_verify_cb(int ok, X509_STORE_CTX *ctx) {
|
static int
|
||||||
|
openssl_verify_cb(int ok, X509_STORE_CTX *ctx) {
|
||||||
int err_code = X509_STORE_CTX_get_error(ctx);
|
int err_code = X509_STORE_CTX_get_error(ctx);
|
||||||
|
|
||||||
switch (err_code) {
|
switch (err_code) {
|
||||||
@@ -39,7 +42,8 @@ static int openssl_verify_cb(int ok, X509_STORE_CTX *ctx) {
|
|||||||
*
|
*
|
||||||
* To circumvent this, x509_store_t instance will be created for each instance of the certificates.
|
* To circumvent this, x509_store_t instance will be created for each instance of the certificates.
|
||||||
*/
|
*/
|
||||||
const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
const char *
|
||||||
|
cert_chain_t::verify(x509_t::element_type *cert) {
|
||||||
int err_code = 0;
|
int err_code = 0;
|
||||||
for (auto &[_, x509_store] : _certs) {
|
for (auto &[_, x509_store] : _certs) {
|
||||||
auto fg = util::fail_guard([this]() {
|
auto fg = util::fail_guard([this]() {
|
||||||
@@ -72,7 +76,8 @@ const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
|||||||
|
|
||||||
namespace cipher {
|
namespace cipher {
|
||||||
|
|
||||||
static int init_decrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
static int
|
||||||
|
init_decrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
||||||
ctx.reset(EVP_CIPHER_CTX_new());
|
ctx.reset(EVP_CIPHER_CTX_new());
|
||||||
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
@@ -95,7 +100,8 @@ static int init_decrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool paddi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_encrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
static int
|
||||||
|
init_encrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
||||||
ctx.reset(EVP_CIPHER_CTX_new());
|
ctx.reset(EVP_CIPHER_CTX_new());
|
||||||
|
|
||||||
// Gen 7 servers use 128-bit AES ECB
|
// Gen 7 servers use 128-bit AES ECB
|
||||||
@@ -115,7 +121,8 @@ static int init_encrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool paddi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_encrypt_cbc(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
static int
|
||||||
|
init_encrypt_cbc(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
||||||
ctx.reset(EVP_CIPHER_CTX_new());
|
ctx.reset(EVP_CIPHER_CTX_new());
|
||||||
|
|
||||||
// Gen 7 servers use 128-bit AES ECB
|
// Gen 7 servers use 128-bit AES ECB
|
||||||
@@ -128,7 +135,8 @@ static int init_encrypt_cbc(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool paddi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gcm_t::decrypt(const std::string_view &tagged_cipher, std::vector<std::uint8_t> &plaintext, aes_t *iv) {
|
int
|
||||||
|
gcm_t::decrypt(const std::string_view &tagged_cipher, std::vector<std::uint8_t> &plaintext, aes_t *iv) {
|
||||||
if (!decrypt_ctx && init_decrypt_gcm(decrypt_ctx, &key, iv, padding)) {
|
if (!decrypt_ctx && init_decrypt_gcm(decrypt_ctx, &key, iv, padding)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -162,7 +170,8 @@ int gcm_t::decrypt(const std::string_view &tagged_cipher, std::vector<std::uint8
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gcm_t::encrypt(const std::string_view &plaintext, std::uint8_t *tagged_cipher, aes_t *iv) {
|
int
|
||||||
|
gcm_t::encrypt(const std::string_view &plaintext, std::uint8_t *tagged_cipher, aes_t *iv) {
|
||||||
if (!encrypt_ctx && init_encrypt_gcm(encrypt_ctx, &key, iv, padding)) {
|
if (!encrypt_ctx && init_encrypt_gcm(encrypt_ctx, &key, iv, padding)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -196,7 +205,8 @@ int gcm_t::encrypt(const std::string_view &plaintext, std::uint8_t *tagged_ciphe
|
|||||||
return len + size;
|
return len + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ecb_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
int
|
||||||
|
ecb_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
auto fg = util::fail_guard([this]() {
|
auto fg = util::fail_guard([this]() {
|
||||||
@@ -225,7 +235,8 @@ int ecb_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &pl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ecb_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher) {
|
int
|
||||||
|
ecb_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher) {
|
||||||
auto fg = util::fail_guard([this]() {
|
auto fg = util::fail_guard([this]() {
|
||||||
EVP_CIPHER_CTX_reset(encrypt_ctx.get());
|
EVP_CIPHER_CTX_reset(encrypt_ctx.get());
|
||||||
});
|
});
|
||||||
@@ -255,7 +266,8 @@ int ecb_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t>
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cbc_t::encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_t *iv) {
|
int
|
||||||
|
cbc_t::encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_t *iv) {
|
||||||
if (!encrypt_ctx && init_encrypt_cbc(encrypt_ctx, &key, iv, padding)) {
|
if (!encrypt_ctx && init_encrypt_cbc(encrypt_ctx, &key, iv, padding)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -282,18 +294,19 @@ int cbc_t::encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_
|
|||||||
return size + len;
|
return size + len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ecb_t::ecb_t(const aes_t &key, bool padding)
|
ecb_t::ecb_t(const aes_t &key, bool padding):
|
||||||
: cipher_t { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new(), key, padding } {}
|
cipher_t { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new(), key, padding } {}
|
||||||
|
|
||||||
cbc_t::cbc_t(const aes_t &key, bool padding)
|
cbc_t::cbc_t(const aes_t &key, bool padding):
|
||||||
: cipher_t { nullptr, nullptr, key, padding } {}
|
cipher_t { nullptr, nullptr, key, padding } {}
|
||||||
|
|
||||||
gcm_t::gcm_t(const crypto::aes_t &key, bool padding)
|
gcm_t::gcm_t(const crypto::aes_t &key, bool padding):
|
||||||
: cipher_t { nullptr, nullptr, key, padding } {}
|
cipher_t { nullptr, nullptr, key, padding } {}
|
||||||
|
|
||||||
} // namespace cipher
|
} // namespace cipher
|
||||||
|
|
||||||
aes_t gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &pin) {
|
aes_t
|
||||||
|
gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &pin) {
|
||||||
aes_t key;
|
aes_t key;
|
||||||
|
|
||||||
std::string salt_pin;
|
std::string salt_pin;
|
||||||
@@ -309,13 +322,15 @@ aes_t gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &p
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha256_t hash(const std::string_view &plaintext) {
|
sha256_t
|
||||||
|
hash(const std::string_view &plaintext) {
|
||||||
sha256_t hsh;
|
sha256_t hsh;
|
||||||
EVP_Digest(plaintext.data(), plaintext.size(), hsh.data(), nullptr, EVP_sha256(), nullptr);
|
EVP_Digest(plaintext.data(), plaintext.size(), hsh.data(), nullptr, EVP_sha256(), nullptr);
|
||||||
return hsh;
|
return hsh;
|
||||||
}
|
}
|
||||||
|
|
||||||
x509_t x509(const std::string_view &x) {
|
x509_t
|
||||||
|
x509(const std::string_view &x) {
|
||||||
bio_t io { BIO_new(BIO_s_mem()) };
|
bio_t io { BIO_new(BIO_s_mem()) };
|
||||||
|
|
||||||
BIO_write(io.get(), x.data(), x.size());
|
BIO_write(io.get(), x.data(), x.size());
|
||||||
@@ -326,7 +341,8 @@ x509_t x509(const std::string_view &x) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkey_t pkey(const std::string_view &k) {
|
pkey_t
|
||||||
|
pkey(const std::string_view &k) {
|
||||||
bio_t io { BIO_new(BIO_s_mem()) };
|
bio_t io { BIO_new(BIO_s_mem()) };
|
||||||
|
|
||||||
BIO_write(io.get(), k.data(), k.size());
|
BIO_write(io.get(), k.data(), k.size());
|
||||||
@@ -337,7 +353,8 @@ pkey_t pkey(const std::string_view &k) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pem(x509_t &x509) {
|
std::string
|
||||||
|
pem(x509_t &x509) {
|
||||||
bio_t bio { BIO_new(BIO_s_mem()) };
|
bio_t bio { BIO_new(BIO_s_mem()) };
|
||||||
|
|
||||||
PEM_write_bio_X509(bio.get(), x509.get());
|
PEM_write_bio_X509(bio.get(), x509.get());
|
||||||
@@ -347,7 +364,8 @@ std::string pem(x509_t &x509) {
|
|||||||
return { mem_ptr->data, mem_ptr->length };
|
return { mem_ptr->data, mem_ptr->length };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pem(pkey_t &pkey) {
|
std::string
|
||||||
|
pem(pkey_t &pkey) {
|
||||||
bio_t bio { BIO_new(BIO_s_mem()) };
|
bio_t bio { BIO_new(BIO_s_mem()) };
|
||||||
|
|
||||||
PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
|
PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
|
||||||
@@ -357,7 +375,8 @@ std::string pem(pkey_t &pkey) {
|
|||||||
return { mem_ptr->data, mem_ptr->length };
|
return { mem_ptr->data, mem_ptr->length };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view signature(const x509_t &x) {
|
std::string_view
|
||||||
|
signature(const x509_t &x) {
|
||||||
// X509_ALGOR *_ = nullptr;
|
// X509_ALGOR *_ = nullptr;
|
||||||
|
|
||||||
const ASN1_BIT_STRING *asn1 = nullptr;
|
const ASN1_BIT_STRING *asn1 = nullptr;
|
||||||
@@ -366,7 +385,8 @@ std::string_view signature(const x509_t &x) {
|
|||||||
return { (const char *) asn1->data, (std::size_t) asn1->length };
|
return { (const char *) asn1->data, (std::size_t) asn1->length };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rand(std::size_t bytes) {
|
std::string
|
||||||
|
rand(std::size_t bytes) {
|
||||||
std::string r;
|
std::string r;
|
||||||
r.resize(bytes);
|
r.resize(bytes);
|
||||||
|
|
||||||
@@ -375,7 +395,8 @@ std::string rand(std::size_t bytes) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> sign(const pkey_t &pkey, const std::string_view &data, const EVP_MD *md) {
|
std::vector<uint8_t>
|
||||||
|
sign(const pkey_t &pkey, const std::string_view &data, const EVP_MD *md) {
|
||||||
md_ctx_t ctx { EVP_MD_CTX_create() };
|
md_ctx_t ctx { EVP_MD_CTX_create() };
|
||||||
|
|
||||||
if (EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, pkey.get()) != 1) {
|
if (EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, pkey.get()) != 1) {
|
||||||
@@ -398,7 +419,8 @@ std::vector<uint8_t> sign(const pkey_t &pkey, const std::string_view &data, cons
|
|||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits) {
|
creds_t
|
||||||
|
gen_creds(const std::string_view &cn, std::uint32_t key_bits) {
|
||||||
x509_t x509 { X509_new() };
|
x509_t x509 { X509_new() };
|
||||||
pkey_ctx_t ctx { EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) };
|
pkey_ctx_t ctx { EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) };
|
||||||
pkey_t pkey;
|
pkey_t pkey;
|
||||||
@@ -443,11 +465,13 @@ creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits) {
|
|||||||
return { pem(x509), pem(pkey) };
|
return { pem(x509), pem(pkey) };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> sign256(const pkey_t &pkey, const std::string_view &data) {
|
std::vector<uint8_t>
|
||||||
|
sign256(const pkey_t &pkey, const std::string_view &data) {
|
||||||
return sign(pkey, data, EVP_sha256());
|
return sign(pkey, data, EVP_sha256());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify(const x509_t &x509, const std::string_view &data, const std::string_view &signature, const EVP_MD *md) {
|
bool
|
||||||
|
verify(const x509_t &x509, const std::string_view &data, const std::string_view &signature, const EVP_MD *md) {
|
||||||
auto pkey = X509_get_pubkey(x509.get());
|
auto pkey = X509_get_pubkey(x509.get());
|
||||||
|
|
||||||
md_ctx_t ctx { EVP_MD_CTX_create() };
|
md_ctx_t ctx { EVP_MD_CTX_create() };
|
||||||
@@ -467,15 +491,18 @@ bool verify(const x509_t &x509, const std::string_view &data, const std::string_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature) {
|
bool
|
||||||
|
verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature) {
|
||||||
return verify(x509, data, signature, EVP_sha256());
|
return verify(x509, data, signature, EVP_sha256());
|
||||||
}
|
}
|
||||||
|
|
||||||
void md_ctx_destroy(EVP_MD_CTX *ctx) {
|
void
|
||||||
|
md_ctx_destroy(EVP_MD_CTX *ctx) {
|
||||||
EVP_MD_CTX_destroy(ctx);
|
EVP_MD_CTX_destroy(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rand_alphabet(std::size_t bytes, const std::string_view &alphabet) {
|
std::string
|
||||||
|
rand_alphabet(std::size_t bytes, const std::string_view &alphabet) {
|
||||||
auto value = rand(bytes);
|
auto value = rand(bytes);
|
||||||
|
|
||||||
for (std::size_t i = 0; i != value.size(); ++i) {
|
for (std::size_t i = 0; i != value.size(); ++i) {
|
||||||
|
|||||||
72
src/crypto.h
72
src/crypto.h
@@ -18,7 +18,8 @@ struct creds_t {
|
|||||||
};
|
};
|
||||||
constexpr std::size_t digest_size = 256;
|
constexpr std::size_t digest_size = 256;
|
||||||
|
|
||||||
void md_ctx_destroy(EVP_MD_CTX *);
|
void
|
||||||
|
md_ctx_destroy(EVP_MD_CTX *);
|
||||||
|
|
||||||
using sha256_t = std::array<std::uint8_t, SHA256_DIGEST_LENGTH>;
|
using sha256_t = std::array<std::uint8_t, SHA256_DIGEST_LENGTH>;
|
||||||
|
|
||||||
@@ -33,33 +34,47 @@ using pkey_t = util::safe_ptr<EVP_PKEY, EVP_PKEY_free>;
|
|||||||
using pkey_ctx_t = util::safe_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
using pkey_ctx_t = util::safe_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||||
using bignum_t = util::safe_ptr<BIGNUM, BN_free>;
|
using bignum_t = util::safe_ptr<BIGNUM, BN_free>;
|
||||||
|
|
||||||
sha256_t hash(const std::string_view &plaintext);
|
sha256_t
|
||||||
|
hash(const std::string_view &plaintext);
|
||||||
|
|
||||||
aes_t gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &pin);
|
aes_t
|
||||||
|
gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &pin);
|
||||||
|
|
||||||
x509_t x509(const std::string_view &x);
|
x509_t
|
||||||
pkey_t pkey(const std::string_view &k);
|
x509(const std::string_view &x);
|
||||||
std::string pem(x509_t &x509);
|
pkey_t
|
||||||
std::string pem(pkey_t &pkey);
|
pkey(const std::string_view &k);
|
||||||
|
std::string
|
||||||
|
pem(x509_t &x509);
|
||||||
|
std::string
|
||||||
|
pem(pkey_t &pkey);
|
||||||
|
|
||||||
std::vector<uint8_t> sign256(const pkey_t &pkey, const std::string_view &data);
|
std::vector<uint8_t>
|
||||||
bool verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature);
|
sign256(const pkey_t &pkey, const std::string_view &data);
|
||||||
|
bool
|
||||||
|
verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature);
|
||||||
|
|
||||||
creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits);
|
creds_t
|
||||||
|
gen_creds(const std::string_view &cn, std::uint32_t key_bits);
|
||||||
|
|
||||||
std::string_view signature(const x509_t &x);
|
std::string_view
|
||||||
|
signature(const x509_t &x);
|
||||||
|
|
||||||
std::string rand(std::size_t bytes);
|
std::string
|
||||||
std::string rand_alphabet(std::size_t bytes,
|
rand(std::size_t bytes);
|
||||||
|
std::string
|
||||||
|
rand_alphabet(std::size_t bytes,
|
||||||
const std::string_view &alphabet = std::string_view { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!%&()=-" });
|
const std::string_view &alphabet = std::string_view { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!%&()=-" });
|
||||||
|
|
||||||
class cert_chain_t {
|
class cert_chain_t {
|
||||||
public:
|
public:
|
||||||
KITTY_DECL_CONSTR(cert_chain_t)
|
KITTY_DECL_CONSTR(cert_chain_t)
|
||||||
|
|
||||||
void add(x509_t &&cert);
|
void
|
||||||
|
add(x509_t &&cert);
|
||||||
|
|
||||||
const char *verify(x509_t::element_type *cert);
|
const char *
|
||||||
|
verify(x509_t::element_type *cert);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<x509_t, x509_store_t>> _certs;
|
std::vector<std::pair<x509_t, x509_store_t>> _certs;
|
||||||
@@ -68,7 +83,8 @@ private:
|
|||||||
|
|
||||||
namespace cipher {
|
namespace cipher {
|
||||||
constexpr std::size_t tag_size = 16;
|
constexpr std::size_t tag_size = 16;
|
||||||
constexpr std::size_t round_to_pkcs7_padded(std::size_t size) {
|
constexpr std::size_t
|
||||||
|
round_to_pkcs7_padded(std::size_t size) {
|
||||||
return ((size + 15) / 16) * 16;
|
return ((size + 15) / 16) * 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,19 +102,23 @@ class ecb_t : public cipher_t {
|
|||||||
public:
|
public:
|
||||||
ecb_t() = default;
|
ecb_t() = default;
|
||||||
ecb_t(ecb_t &&) noexcept = default;
|
ecb_t(ecb_t &&) noexcept = default;
|
||||||
ecb_t &operator=(ecb_t &&) noexcept = default;
|
ecb_t &
|
||||||
|
operator=(ecb_t &&) noexcept = default;
|
||||||
|
|
||||||
ecb_t(const aes_t &key, bool padding = true);
|
ecb_t(const aes_t &key, bool padding = true);
|
||||||
|
|
||||||
int encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher);
|
int
|
||||||
int decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher);
|
||||||
|
int
|
||||||
|
decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
||||||
};
|
};
|
||||||
|
|
||||||
class gcm_t: public cipher_t {
|
class gcm_t: public cipher_t {
|
||||||
public:
|
public:
|
||||||
gcm_t() = default;
|
gcm_t() = default;
|
||||||
gcm_t(gcm_t &&) noexcept = default;
|
gcm_t(gcm_t &&) noexcept = default;
|
||||||
gcm_t &operator=(gcm_t &&) noexcept = default;
|
gcm_t &
|
||||||
|
operator=(gcm_t &&) noexcept = default;
|
||||||
|
|
||||||
gcm_t(const crypto::aes_t &key, bool padding = true);
|
gcm_t(const crypto::aes_t &key, bool padding = true);
|
||||||
|
|
||||||
@@ -108,16 +128,19 @@ public:
|
|||||||
* return -1 on error
|
* return -1 on error
|
||||||
* return bytes written on success
|
* return bytes written on success
|
||||||
*/
|
*/
|
||||||
int encrypt(const std::string_view &plaintext, std::uint8_t *tagged_cipher, aes_t *iv);
|
int
|
||||||
|
encrypt(const std::string_view &plaintext, std::uint8_t *tagged_cipher, aes_t *iv);
|
||||||
|
|
||||||
int decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext, aes_t *iv);
|
int
|
||||||
|
decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext, aes_t *iv);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cbc_t: public cipher_t {
|
class cbc_t: public cipher_t {
|
||||||
public:
|
public:
|
||||||
cbc_t() = default;
|
cbc_t() = default;
|
||||||
cbc_t(cbc_t &&) noexcept = default;
|
cbc_t(cbc_t &&) noexcept = default;
|
||||||
cbc_t &operator=(cbc_t &&) noexcept = default;
|
cbc_t &
|
||||||
|
operator=(cbc_t &&) noexcept = default;
|
||||||
|
|
||||||
cbc_t(const crypto::aes_t &key, bool padding = true);
|
cbc_t(const crypto::aes_t &key, bool padding = true);
|
||||||
|
|
||||||
@@ -127,7 +150,8 @@ public:
|
|||||||
* return -1 on error
|
* return -1 on error
|
||||||
* return bytes written on success
|
* return bytes written on success
|
||||||
*/
|
*/
|
||||||
int encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_t *iv);
|
int
|
||||||
|
encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_t *iv);
|
||||||
};
|
};
|
||||||
} // namespace cipher
|
} // namespace cipher
|
||||||
} // namespace crypto
|
} // namespace crypto
|
||||||
|
|||||||
@@ -31,14 +31,17 @@ using namespace std::literals;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
namespace pt = boost::property_tree;
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
int reload_user_creds(const std::string &file);
|
int
|
||||||
bool user_creds_exist(const std::string &file);
|
reload_user_creds(const std::string &file);
|
||||||
|
bool
|
||||||
|
user_creds_exist(const std::string &file);
|
||||||
|
|
||||||
std::string unique_id;
|
std::string unique_id;
|
||||||
net::net_e origin_pin_allowed;
|
net::net_e origin_pin_allowed;
|
||||||
net::net_e origin_web_ui_allowed;
|
net::net_e origin_web_ui_allowed;
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE];
|
bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE];
|
||||||
origin_pin_allowed = net::from_enum_string(config::nvhttp.origin_pin_allowed);
|
origin_pin_allowed = net::from_enum_string(config::nvhttp.origin_pin_allowed);
|
||||||
origin_web_ui_allowed = net::from_enum_string(config::nvhttp.origin_web_ui_allowed);
|
origin_web_ui_allowed = net::from_enum_string(config::nvhttp.origin_web_ui_allowed);
|
||||||
@@ -64,7 +67,8 @@ int init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int save_user_creds(const std::string &file, const std::string &username, const std::string &password, bool run_our_mouth) {
|
int
|
||||||
|
save_user_creds(const std::string &file, const std::string &username, const std::string &password, bool run_our_mouth) {
|
||||||
pt::ptree outputTree;
|
pt::ptree outputTree;
|
||||||
|
|
||||||
if (fs::exists(file)) {
|
if (fs::exists(file)) {
|
||||||
@@ -93,7 +97,8 @@ int save_user_creds(const std::string &file, const std::string &username, const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool user_creds_exist(const std::string &file) {
|
bool
|
||||||
|
user_creds_exist(const std::string &file) {
|
||||||
if (!fs::exists(file)) {
|
if (!fs::exists(file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -112,7 +117,8 @@ bool user_creds_exist(const std::string &file) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reload_user_creds(const std::string &file) {
|
int
|
||||||
|
reload_user_creds(const std::string &file) {
|
||||||
pt::ptree inputTree;
|
pt::ptree inputTree;
|
||||||
try {
|
try {
|
||||||
pt::read_json(file, inputTree);
|
pt::read_json(file, inputTree);
|
||||||
@@ -127,7 +133,8 @@ int reload_user_creds(const std::string &file) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_creds(const std::string &pkey, const std::string &cert) {
|
int
|
||||||
|
create_creds(const std::string &pkey, const std::string &cert) {
|
||||||
fs::path pkey_path = pkey;
|
fs::path pkey_path = pkey;
|
||||||
fs::path cert_path = cert;
|
fs::path cert_path = cert;
|
||||||
|
|
||||||
@@ -182,7 +189,8 @@ int create_creds(const std::string &pkey, const std::string &cert) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool download_file(const std::string &url, const std::string &file) {
|
bool
|
||||||
|
download_file(const std::string &url, const std::string &file) {
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
if (!curl) {
|
if (!curl) {
|
||||||
BOOST_LOG(error) << "Couldn't create CURL instance";
|
BOOST_LOG(error) << "Couldn't create CURL instance";
|
||||||
@@ -209,7 +217,8 @@ bool download_file(const std::string &url, const std::string &file) {
|
|||||||
return result == CURLE_OK;
|
return result == CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url_escape(const std::string &url) {
|
std::string
|
||||||
|
url_escape(const std::string &url) {
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
char *string = curl_easy_escape(curl, url.c_str(), url.length());
|
char *string = curl_easy_escape(curl, url.c_str(), url.length());
|
||||||
std::string result(string);
|
std::string result(string);
|
||||||
@@ -218,7 +227,8 @@ std::string url_escape(const std::string &url) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url_get_host(const std::string &url) {
|
std::string
|
||||||
|
url_get_host(const std::string &url) {
|
||||||
CURLU *curlu = curl_url();
|
CURLU *curlu = curl_url();
|
||||||
curl_url_set(curlu, CURLUPART_URL, url.c_str(), url.length());
|
curl_url_set(curlu, CURLUPART_URL, url.c_str(), url.length());
|
||||||
char *host;
|
char *host;
|
||||||
|
|||||||
@@ -3,18 +3,25 @@
|
|||||||
|
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
int init();
|
int
|
||||||
int create_creds(const std::string &pkey, const std::string &cert);
|
init();
|
||||||
int save_user_creds(
|
int
|
||||||
|
create_creds(const std::string &pkey, const std::string &cert);
|
||||||
|
int
|
||||||
|
save_user_creds(
|
||||||
const std::string &file,
|
const std::string &file,
|
||||||
const std::string &username,
|
const std::string &username,
|
||||||
const std::string &password,
|
const std::string &password,
|
||||||
bool run_our_mouth = false);
|
bool run_our_mouth = false);
|
||||||
|
|
||||||
int reload_user_creds(const std::string &file);
|
int
|
||||||
bool download_file(const std::string &url, const std::string &file);
|
reload_user_creds(const std::string &file);
|
||||||
std::string url_escape(const std::string &url);
|
bool
|
||||||
std::string url_get_host(const std::string &url);
|
download_file(const std::string &url, const std::string &file);
|
||||||
|
std::string
|
||||||
|
url_escape(const std::string &url);
|
||||||
|
std::string
|
||||||
|
url_get_host(const std::string &url);
|
||||||
|
|
||||||
extern std::string unique_id;
|
extern std::string unique_id;
|
||||||
extern net::net_e origin_pin_allowed;
|
extern net::net_e origin_pin_allowed;
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ enum class button_state_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
int alloc_id(std::bitset<N> &gamepad_mask) {
|
int
|
||||||
|
alloc_id(std::bitset<N> &gamepad_mask) {
|
||||||
for (int x = 0; x < gamepad_mask.size(); ++x) {
|
for (int x = 0; x < gamepad_mask.size(); ++x) {
|
||||||
if (!gamepad_mask[x]) {
|
if (!gamepad_mask[x]) {
|
||||||
gamepad_mask[x] = true;
|
gamepad_mask[x] = true;
|
||||||
@@ -53,7 +54,8 @@ int alloc_id(std::bitset<N> &gamepad_mask) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
void free_id(std::bitset<N> &gamepad_mask, int id) {
|
void
|
||||||
|
free_id(std::bitset<N> &gamepad_mask, int id) {
|
||||||
gamepad_mask[id] = false;
|
gamepad_mask[id] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,14 +66,16 @@ static std::array<std::uint8_t, 5> mouse_press {};
|
|||||||
static platf::input_t platf_input;
|
static platf::input_t platf_input;
|
||||||
static std::bitset<platf::MAX_GAMEPADS> gamepadMask {};
|
static std::bitset<platf::MAX_GAMEPADS> gamepadMask {};
|
||||||
|
|
||||||
void free_gamepad(platf::input_t &platf_input, int id) {
|
void
|
||||||
|
free_gamepad(platf::input_t &platf_input, int id) {
|
||||||
platf::gamepad(platf_input, id, platf::gamepad_state_t {});
|
platf::gamepad(platf_input, id, platf::gamepad_state_t {});
|
||||||
platf::free_gamepad(platf_input, id);
|
platf::free_gamepad(platf_input, id);
|
||||||
|
|
||||||
free_id(gamepadMask, id);
|
free_id(gamepadMask, id);
|
||||||
}
|
}
|
||||||
struct gamepad_t {
|
struct gamepad_t {
|
||||||
gamepad_t() : gamepad_state {}, back_timeout_id {}, id { -1 }, back_button_state { button_state_e::NONE } {}
|
gamepad_t():
|
||||||
|
gamepad_state {}, back_timeout_id {}, id { -1 }, back_button_state { button_state_e::NONE } {}
|
||||||
~gamepad_t() {
|
~gamepad_t() {
|
||||||
if (id >= 0) {
|
if (id >= 0) {
|
||||||
task_pool.push([id = this->id]() {
|
task_pool.push([id = this->id]() {
|
||||||
@@ -105,8 +109,8 @@ struct input_t {
|
|||||||
|
|
||||||
input_t(
|
input_t(
|
||||||
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event,
|
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event,
|
||||||
platf::rumble_queue_t rumble_queue)
|
platf::rumble_queue_t rumble_queue):
|
||||||
: shortcutFlags {},
|
shortcutFlags {},
|
||||||
active_gamepad_state {},
|
active_gamepad_state {},
|
||||||
gamepads(MAX_GAMEPADS),
|
gamepads(MAX_GAMEPADS),
|
||||||
touch_port_event { std::move(touch_port_event) },
|
touch_port_event { std::move(touch_port_event) },
|
||||||
@@ -135,7 +139,8 @@ struct input_t {
|
|||||||
* On nothing
|
* On nothing
|
||||||
* return 0
|
* return 0
|
||||||
*/
|
*/
|
||||||
inline int apply_shortcut(short keyCode) {
|
inline int
|
||||||
|
apply_shortcut(short keyCode) {
|
||||||
constexpr auto VK_F1 = 0x70;
|
constexpr auto VK_F1 = 0x70;
|
||||||
constexpr auto VK_F13 = 0x7C;
|
constexpr auto VK_F13 = 0x7C;
|
||||||
|
|
||||||
@@ -155,7 +160,8 @@ inline int apply_shortcut(short keyCode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
void
|
||||||
|
print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin relative mouse move packet--"sv << std::endl
|
<< "--begin relative mouse move packet--"sv << std::endl
|
||||||
<< "deltaX ["sv << util::endian::big(packet->deltaX) << ']' << std::endl
|
<< "deltaX ["sv << util::endian::big(packet->deltaX) << ']' << std::endl
|
||||||
@@ -163,7 +169,8 @@ void print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
|||||||
<< "--end relative mouse move packet--"sv;
|
<< "--end relative mouse move packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
void
|
||||||
|
print(PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin absolute mouse move packet--"sv << std::endl
|
<< "--begin absolute mouse move packet--"sv << std::endl
|
||||||
<< "x ["sv << util::endian::big(packet->x) << ']' << std::endl
|
<< "x ["sv << util::endian::big(packet->x) << ']' << std::endl
|
||||||
@@ -173,7 +180,8 @@ void print(PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
|||||||
<< "--end absolute mouse move packet--"sv;
|
<< "--end absolute mouse move packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_MOUSE_BUTTON_PACKET packet) {
|
void
|
||||||
|
print(PNV_MOUSE_BUTTON_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin mouse button packet--"sv << std::endl
|
<< "--begin mouse button packet--"sv << std::endl
|
||||||
<< "action ["sv << util::hex(packet->header.magic).to_string_view() << ']' << std::endl
|
<< "action ["sv << util::hex(packet->header.magic).to_string_view() << ']' << std::endl
|
||||||
@@ -181,21 +189,24 @@ void print(PNV_MOUSE_BUTTON_PACKET packet) {
|
|||||||
<< "--end mouse button packet--"sv;
|
<< "--end mouse button packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_SCROLL_PACKET packet) {
|
void
|
||||||
|
print(PNV_SCROLL_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin mouse scroll packet--"sv << std::endl
|
<< "--begin mouse scroll packet--"sv << std::endl
|
||||||
<< "scrollAmt1 ["sv << util::endian::big(packet->scrollAmt1) << ']' << std::endl
|
<< "scrollAmt1 ["sv << util::endian::big(packet->scrollAmt1) << ']' << std::endl
|
||||||
<< "--end mouse scroll packet--"sv;
|
<< "--end mouse scroll packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PSS_HSCROLL_PACKET packet) {
|
void
|
||||||
|
print(PSS_HSCROLL_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin mouse hscroll packet--"sv << std::endl
|
<< "--begin mouse hscroll packet--"sv << std::endl
|
||||||
<< "scrollAmount ["sv << util::endian::big(packet->scrollAmount) << ']' << std::endl
|
<< "scrollAmount ["sv << util::endian::big(packet->scrollAmount) << ']' << std::endl
|
||||||
<< "--end mouse hscroll packet--"sv;
|
<< "--end mouse hscroll packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_KEYBOARD_PACKET packet) {
|
void
|
||||||
|
print(PNV_KEYBOARD_PACKET packet) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin keyboard packet--"sv << std::endl
|
<< "--begin keyboard packet--"sv << std::endl
|
||||||
<< "keyAction ["sv << util::hex(packet->header.magic).to_string_view() << ']' << std::endl
|
<< "keyAction ["sv << util::hex(packet->header.magic).to_string_view() << ']' << std::endl
|
||||||
@@ -205,7 +216,8 @@ void print(PNV_KEYBOARD_PACKET packet) {
|
|||||||
<< "--end keyboard packet--"sv;
|
<< "--end keyboard packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_UNICODE_PACKET packet) {
|
void
|
||||||
|
print(PNV_UNICODE_PACKET packet) {
|
||||||
std::string text(packet->text, util::endian::big(packet->header.size) - sizeof(packet->header.magic));
|
std::string text(packet->text, util::endian::big(packet->header.size) - sizeof(packet->header.magic));
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "--begin unicode packet--"sv << std::endl
|
<< "--begin unicode packet--"sv << std::endl
|
||||||
@@ -213,7 +225,8 @@ void print(PNV_UNICODE_PACKET packet) {
|
|||||||
<< "--end unicode packet--"sv;
|
<< "--end unicode packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(PNV_MULTI_CONTROLLER_PACKET packet) {
|
void
|
||||||
|
print(PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||||
// Moonlight spams controller packet even when not necessary
|
// Moonlight spams controller packet even when not necessary
|
||||||
BOOST_LOG(verbose)
|
BOOST_LOG(verbose)
|
||||||
<< "--begin controller packet--"sv << std::endl
|
<< "--begin controller packet--"sv << std::endl
|
||||||
@@ -229,7 +242,8 @@ void print(PNV_MULTI_CONTROLLER_PACKET packet) {
|
|||||||
<< "--end controller packet--"sv;
|
<< "--end controller packet--"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(void *payload) {
|
void
|
||||||
|
print(void *payload) {
|
||||||
auto header = (PNV_INPUT_HEADER) payload;
|
auto header = (PNV_INPUT_HEADER) payload;
|
||||||
|
|
||||||
switch (util::endian::little(header->magic)) {
|
switch (util::endian::little(header->magic)) {
|
||||||
@@ -262,7 +276,8 @@ void print(void *payload) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_REL_MOUSE_MOVE_PACKET packet) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||||
if (!config::input.mouse) {
|
if (!config::input.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -271,7 +286,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_REL_MOUSE_MOVE_PACKET pack
|
|||||||
platf::move_mouse(platf_input, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY));
|
platf::move_mouse(platf_input, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY));
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
||||||
if (!config::input.mouse) {
|
if (!config::input.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -320,7 +336,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_ABS_MOUSE_MOVE_PACKET pack
|
|||||||
platf::abs_mouse(platf_input, abs_port, (x - offsetX) * touch_port.scalar_inv, (y - offsetY) * touch_port.scalar_inv);
|
platf::abs_mouse(platf_input, abs_port, (x - offsetX) * touch_port.scalar_inv, (y - offsetY) * touch_port.scalar_inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet) {
|
||||||
if (!config::input.mouse) {
|
if (!config::input.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -382,7 +399,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet
|
|||||||
platf::button_mouse(platf_input, button, release);
|
platf::button_mouse(platf_input, button, release);
|
||||||
}
|
}
|
||||||
|
|
||||||
short map_keycode(short keycode) {
|
short
|
||||||
|
map_keycode(short keycode) {
|
||||||
auto it = config::input.keybindings.find(keycode);
|
auto it = config::input.keybindings.find(keycode);
|
||||||
if (it != std::end(config::input.keybindings)) {
|
if (it != std::end(config::input.keybindings)) {
|
||||||
return it->second;
|
return it->second;
|
||||||
@@ -394,7 +412,8 @@ short map_keycode(short keycode) {
|
|||||||
/**
|
/**
|
||||||
* Update flags for keyboard shortcut combo's
|
* Update flags for keyboard shortcut combo's
|
||||||
*/
|
*/
|
||||||
inline void update_shortcutFlags(int *flags, short keyCode, bool release) {
|
inline void
|
||||||
|
update_shortcutFlags(int *flags, short keyCode, bool release) {
|
||||||
switch (keyCode) {
|
switch (keyCode) {
|
||||||
case VKEY_SHIFT:
|
case VKEY_SHIFT:
|
||||||
case VKEY_LSHIFT:
|
case VKEY_LSHIFT:
|
||||||
@@ -429,7 +448,8 @@ inline void update_shortcutFlags(int *flags, short keyCode, bool release) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void repeat_key(short key_code) {
|
void
|
||||||
|
repeat_key(short key_code) {
|
||||||
// If key no longer pressed, stop repeating
|
// If key no longer pressed, stop repeating
|
||||||
if (!key_press[key_code]) {
|
if (!key_press[key_code]) {
|
||||||
key_press_repeat_id = nullptr;
|
key_press_repeat_id = nullptr;
|
||||||
@@ -441,7 +461,8 @@ void repeat_key(short key_code) {
|
|||||||
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
||||||
if (!config::input.keyboard) {
|
if (!config::input.keyboard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -482,7 +503,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
|||||||
platf::keyboard(platf_input, map_keycode(keyCode), release);
|
platf::keyboard(platf_input, map_keycode(keyCode), release);
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(PNV_SCROLL_PACKET packet) {
|
void
|
||||||
|
passthrough(PNV_SCROLL_PACKET packet) {
|
||||||
if (!config::input.mouse) {
|
if (!config::input.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -490,7 +512,8 @@ void passthrough(PNV_SCROLL_PACKET packet) {
|
|||||||
platf::scroll(platf_input, util::endian::big(packet->scrollAmt1));
|
platf::scroll(platf_input, util::endian::big(packet->scrollAmt1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(PSS_HSCROLL_PACKET packet) {
|
void
|
||||||
|
passthrough(PSS_HSCROLL_PACKET packet) {
|
||||||
if (!config::input.mouse) {
|
if (!config::input.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -498,7 +521,8 @@ void passthrough(PSS_HSCROLL_PACKET packet) {
|
|||||||
platf::hscroll(platf_input, util::endian::big(packet->scrollAmount));
|
platf::hscroll(platf_input, util::endian::big(packet->scrollAmount));
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(PNV_UNICODE_PACKET packet) {
|
void
|
||||||
|
passthrough(PNV_UNICODE_PACKET packet) {
|
||||||
if (!config::input.keyboard) {
|
if (!config::input.keyboard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -507,7 +531,8 @@ void passthrough(PNV_UNICODE_PACKET packet) {
|
|||||||
platf::unicode(platf_input, packet->text, size);
|
platf::unicode(platf_input, packet->text, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state, const platf::rumble_queue_t &rumble_queue) {
|
int
|
||||||
|
updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state, const platf::rumble_queue_t &rumble_queue) {
|
||||||
auto xorGamepadMask = old_state ^ new_state;
|
auto xorGamepadMask = old_state ^ new_state;
|
||||||
if (!xorGamepadMask) {
|
if (!xorGamepadMask) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -548,7 +573,8 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||||
if (!config::input.controller) {
|
if (!config::input.controller) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -650,7 +676,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET pa
|
|||||||
gamepad.gamepad_state = gamepad_state;
|
gamepad.gamepad_state = gamepad_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough_helper(std::shared_ptr<input_t> input, std::vector<std::uint8_t> &&input_data) {
|
void
|
||||||
|
passthrough_helper(std::shared_ptr<input_t> input, std::vector<std::uint8_t> &&input_data) {
|
||||||
void *payload = input_data.data();
|
void *payload = input_data.data();
|
||||||
auto header = (PNV_INPUT_HEADER) payload;
|
auto header = (PNV_INPUT_HEADER) payload;
|
||||||
|
|
||||||
@@ -684,11 +711,13 @@ void passthrough_helper(std::shared_ptr<input_t> input, std::vector<std::uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data) {
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data) {
|
||||||
task_pool.push(passthrough_helper, input, move_by_copy_util::cmove(input_data));
|
task_pool.push(passthrough_helper, input, move_by_copy_util::cmove(input_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(std::shared_ptr<input_t> &input) {
|
void
|
||||||
|
reset(std::shared_ptr<input_t> &input) {
|
||||||
task_pool.cancel(key_press_repeat_id);
|
task_pool.cancel(key_press_repeat_id);
|
||||||
task_pool.cancel(input->mouse_left_button_timeout);
|
task_pool.cancel(input->mouse_left_button_timeout);
|
||||||
|
|
||||||
@@ -715,13 +744,15 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> init() {
|
[[nodiscard]] std::unique_ptr<platf::deinit_t>
|
||||||
|
init() {
|
||||||
platf_input = platf::input();
|
platf_input = platf::input();
|
||||||
|
|
||||||
return std::make_unique<deinit_t>();
|
return std::make_unique<deinit_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<input_t> alloc(safe::mail_t mail) {
|
std::shared_ptr<input_t>
|
||||||
|
alloc(safe::mail_t mail) {
|
||||||
auto input = std::make_shared<input_t>(
|
auto input = std::make_shared<input_t>(
|
||||||
mail->event<input::touch_port_t>(mail::touch_port),
|
mail->event<input::touch_port_t>(mail::touch_port),
|
||||||
mail->queue<platf::rumble_t>(mail::rumble));
|
mail->queue<platf::rumble_t>(mail::rumble));
|
||||||
|
|||||||
16
src/input.h
16
src/input.h
@@ -11,14 +11,18 @@
|
|||||||
namespace input {
|
namespace input {
|
||||||
struct input_t;
|
struct input_t;
|
||||||
|
|
||||||
void print(void *input);
|
void
|
||||||
void reset(std::shared_ptr<input_t> &input);
|
print(void *input);
|
||||||
void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data);
|
void
|
||||||
|
reset(std::shared_ptr<input_t> &input);
|
||||||
|
void
|
||||||
|
passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data);
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<platf::deinit_t>
|
||||||
|
init();
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> init();
|
std::shared_ptr<input_t>
|
||||||
|
alloc(safe::mail_t mail);
|
||||||
std::shared_ptr<input_t> alloc(safe::mail_t mail);
|
|
||||||
|
|
||||||
struct touch_port_t: public platf::touch_port_t {
|
struct touch_port_t: public platf::touch_port_t {
|
||||||
int env_width, env_height;
|
int env_width, env_height;
|
||||||
|
|||||||
40
src/main.cpp
40
src/main.cpp
@@ -55,7 +55,8 @@ using text_sink = bl::sinks::asynchronous_sink<bl::sinks::text_ostream_backend>;
|
|||||||
boost::shared_ptr<text_sink> sink;
|
boost::shared_ptr<text_sink> sink;
|
||||||
|
|
||||||
struct NoDelete {
|
struct NoDelete {
|
||||||
void operator()(void *) {}
|
void
|
||||||
|
operator()(void *) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
||||||
@@ -69,7 +70,8 @@ BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
|||||||
* print_help("sunshine");
|
* print_help("sunshine");
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void print_help(const char *name) {
|
void
|
||||||
|
print_help(const char *name) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "Usage: "sv << name << " [options] [/path/to/configuration_file] [--cmd]"sv << std::endl
|
<< "Usage: "sv << name << " [options] [/path/to/configuration_file] [--cmd]"sv << std::endl
|
||||||
<< " Any configurable option can be overwritten with: \"name=value\""sv << std::endl
|
<< " Any configurable option can be overwritten with: \"name=value\""sv << std::endl
|
||||||
@@ -90,20 +92,21 @@ void print_help(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace help {
|
namespace help {
|
||||||
int entry(const char *name, int argc, char *argv[]) {
|
int
|
||||||
|
entry(const char *name, int argc, char *argv[]) {
|
||||||
print_help(name);
|
print_help(name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace help
|
} // namespace help
|
||||||
|
|
||||||
namespace version {
|
namespace version {
|
||||||
int entry(const char *name, int argc, char *argv[]) {
|
int
|
||||||
|
entry(const char *name, int argc, char *argv[]) {
|
||||||
std::cout << PROJECT_NAME << " version: v" << PROJECT_VER << std::endl;
|
std::cout << PROJECT_NAME << " version: v" << PROJECT_VER << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace version
|
} // namespace version
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flush the log.
|
* @brief Flush the log.
|
||||||
*
|
*
|
||||||
@@ -112,24 +115,28 @@ int entry(const char *name, int argc, char *argv[]) {
|
|||||||
* log_flush();
|
* log_flush();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void log_flush() {
|
void
|
||||||
|
log_flush() {
|
||||||
sink->flush();
|
sink->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, std::function<void()>> signal_handlers;
|
std::map<int, std::function<void()>> signal_handlers;
|
||||||
void on_signal_forwarder(int sig) {
|
void
|
||||||
|
on_signal_forwarder(int sig) {
|
||||||
signal_handlers.at(sig)();
|
signal_handlers.at(sig)();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FN>
|
template <class FN>
|
||||||
void on_signal(int sig, FN &&fn) {
|
void
|
||||||
|
on_signal(int sig, FN &&fn) {
|
||||||
signal_handlers.emplace(sig, std::forward<FN>(fn));
|
signal_handlers.emplace(sig, std::forward<FN>(fn));
|
||||||
|
|
||||||
std::signal(sig, on_signal_forwarder);
|
std::signal(sig, on_signal_forwarder);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gen_creds {
|
namespace gen_creds {
|
||||||
int entry(const char *name, int argc, char *argv[]) {
|
int
|
||||||
|
entry(const char *name, int argc, char *argv[]) {
|
||||||
if (argc < 2 || argv[0] == "help"sv || argv[1] == "help"sv) {
|
if (argc < 2 || argv[0] == "help"sv || argv[1] == "help"sv) {
|
||||||
print_help(name);
|
print_help(name);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -148,7 +155,8 @@ std::map<std::string_view, std::function<int(const char *name, int argc, char **
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LRESULT CALLBACK SessionMonitorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
LRESULT CALLBACK
|
||||||
|
SessionMonitorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
case WM_ENDSESSION: {
|
case WM_ENDSESSION: {
|
||||||
// Raise a SIGINT to trigger our cleanup logic and terminate ourselves
|
// Raise a SIGINT to trigger our cleanup logic and terminate ourselves
|
||||||
@@ -176,7 +184,8 @@ LRESULT CALLBACK SessionMonitorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, L
|
|||||||
* main(1, const char* args[] = {"sunshine", nullptr});
|
* main(1, const char* args[] = {"sunshine", nullptr});
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
task_pool_util::TaskPool::task_id_t force_shutdown = nullptr;
|
task_pool_util::TaskPool::task_id_t force_shutdown = nullptr;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -395,7 +404,8 @@ int main(int argc, char *argv[]) {
|
|||||||
* std::string contents = read_file("path/to/file");
|
* std::string contents = read_file("path/to/file");
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
std::string read_file(const char *path) {
|
std::string
|
||||||
|
read_file(const char *path) {
|
||||||
if (!std::filesystem::exists(path)) {
|
if (!std::filesystem::exists(path)) {
|
||||||
BOOST_LOG(debug) << "Missing file: " << path;
|
BOOST_LOG(debug) << "Missing file: " << path;
|
||||||
return {};
|
return {};
|
||||||
@@ -425,7 +435,8 @@ std::string read_file(const char *path) {
|
|||||||
* int write_status = write_file("path/to/file", "file contents");
|
* int write_status = write_file("path/to/file", "file contents");
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
int write_file(const char *path, const std::string_view &contents) {
|
int
|
||||||
|
write_file(const char *path, const std::string_view &contents) {
|
||||||
std::ofstream out(path);
|
std::ofstream out(path);
|
||||||
|
|
||||||
if (!out.is_open()) {
|
if (!out.is_open()) {
|
||||||
@@ -447,7 +458,8 @@ int write_file(const char *path, const std::string_view &contents) {
|
|||||||
* std::uint16_t mapped_port = map_port(1);
|
* std::uint16_t mapped_port = map_port(1);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
std::uint16_t map_port(int port) {
|
std::uint16_t
|
||||||
|
map_port(int port) {
|
||||||
// TODO: Ensure port is in the range of 21-65535
|
// TODO: Ensure port is in the range of 21-65535
|
||||||
// TODO: Ensure port is not already in use by another application
|
// TODO: Ensure port is not already in use by another application
|
||||||
return (std::uint16_t)((int) config::sunshine.port + port);
|
return (std::uint16_t)((int) config::sunshine.port + port);
|
||||||
|
|||||||
39
src/main.h
39
src/main.h
@@ -28,19 +28,32 @@ extern boost::log::sources::severity_logger<int> error;
|
|||||||
extern boost::log::sources::severity_logger<int> fatal;
|
extern boost::log::sources::severity_logger<int> fatal;
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
int main(int argc, char *argv[]);
|
int
|
||||||
void log_flush();
|
main(int argc, char *argv[]);
|
||||||
void open_url(const std::string &url);
|
void
|
||||||
void tray_open_ui_cb(struct tray_menu *item);
|
log_flush();
|
||||||
void tray_donate_github_cb(struct tray_menu *item);
|
void
|
||||||
void tray_donate_mee6_cb(struct tray_menu *item);
|
open_url(const std::string &url);
|
||||||
void tray_donate_patreon_cb(struct tray_menu *item);
|
void
|
||||||
void tray_donate_paypal_cb(struct tray_menu *item);
|
tray_open_ui_cb(struct tray_menu *item);
|
||||||
void tray_quit_cb(struct tray_menu *item);
|
void
|
||||||
void print_help(const char *name);
|
tray_donate_github_cb(struct tray_menu *item);
|
||||||
std::string read_file(const char *path);
|
void
|
||||||
int write_file(const char *path, const std::string_view &contents);
|
tray_donate_mee6_cb(struct tray_menu *item);
|
||||||
std::uint16_t map_port(int port);
|
void
|
||||||
|
tray_donate_patreon_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
tray_donate_paypal_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
tray_quit_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
print_help(const char *name);
|
||||||
|
std::string
|
||||||
|
read_file(const char *path);
|
||||||
|
int
|
||||||
|
write_file(const char *path, const std::string_view &contents);
|
||||||
|
std::uint16_t
|
||||||
|
map_port(int port);
|
||||||
|
|
||||||
// namespaces
|
// namespaces
|
||||||
namespace mail {
|
namespace mail {
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ private:
|
|||||||
move_type _to_move;
|
move_type _to_move;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MoveByCopy(move_type &&to_move) : _to_move(std::move(to_move)) {}
|
explicit MoveByCopy(move_type &&to_move):
|
||||||
|
_to_move(std::move(to_move)) {}
|
||||||
|
|
||||||
MoveByCopy(MoveByCopy &&other) = default;
|
MoveByCopy(MoveByCopy &&other) = default;
|
||||||
|
|
||||||
@@ -24,9 +25,11 @@ public:
|
|||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveByCopy &operator=(MoveByCopy &&other) = default;
|
MoveByCopy &
|
||||||
|
operator=(MoveByCopy &&other) = default;
|
||||||
|
|
||||||
MoveByCopy &operator=(const MoveByCopy &other) {
|
MoveByCopy &
|
||||||
|
operator=(const MoveByCopy &other) {
|
||||||
this->_to_move = std::move(const_cast<MoveByCopy &>(other)._to_move);
|
this->_to_move = std::move(const_cast<MoveByCopy &>(other)._to_move);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@@ -38,13 +41,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
MoveByCopy<T> cmove(T &movable) {
|
MoveByCopy<T>
|
||||||
|
cmove(T &movable) {
|
||||||
return MoveByCopy<T>(std::move(movable));
|
return MoveByCopy<T>(std::move(movable));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do NOT use this unless you are absolutely certain the object to be moved is no longer used by the caller
|
// Do NOT use this unless you are absolutely certain the object to be moved is no longer used by the caller
|
||||||
template <class T>
|
template <class T>
|
||||||
MoveByCopy<T> const_cmove(const T &movable) {
|
MoveByCopy<T>
|
||||||
|
const_cmove(const T &movable) {
|
||||||
return MoveByCopy<T>(std::move(const_cast<T &>(movable)));
|
return MoveByCopy<T>(std::move(const_cast<T &>(movable)));
|
||||||
}
|
}
|
||||||
} // namespace move_by_copy_util
|
} // namespace move_by_copy_util
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
namespace net {
|
namespace net {
|
||||||
// In the format "xxx.xxx.xxx.xxx/x"
|
// In the format "xxx.xxx.xxx.xxx/x"
|
||||||
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip);
|
std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
ip_block(const std::string_view &ip);
|
||||||
|
|
||||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> pc_ips {
|
std::vector<std::pair<std::uint32_t, std::uint32_t>> pc_ips {
|
||||||
ip_block("127.0.0.1/32"sv)
|
ip_block("127.0.0.1/32"sv)
|
||||||
@@ -18,7 +19,8 @@ std::vector<std::tuple<std::uint32_t, std::uint32_t>> lan_ips {
|
|||||||
ip_block("10.0.0.0/8"sv)
|
ip_block("10.0.0.0/8"sv)
|
||||||
};
|
};
|
||||||
|
|
||||||
std::uint32_t ip(const std::string_view &ip_str) {
|
std::uint32_t
|
||||||
|
ip(const std::string_view &ip_str) {
|
||||||
auto begin = std::begin(ip_str);
|
auto begin = std::begin(ip_str);
|
||||||
auto end = std::end(ip_str);
|
auto end = std::end(ip_str);
|
||||||
auto temp_end = std::find(begin, end, '.');
|
auto temp_end = std::find(begin, end, '.');
|
||||||
@@ -39,7 +41,8 @@ std::uint32_t ip(const std::string_view &ip_str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In the format "xxx.xxx.xxx.xxx/x"
|
// In the format "xxx.xxx.xxx.xxx/x"
|
||||||
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip_str) {
|
std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
ip_block(const std::string_view &ip_str) {
|
||||||
auto begin = std::begin(ip_str);
|
auto begin = std::begin(ip_str);
|
||||||
auto end = std::find(begin, std::end(ip_str), '/');
|
auto end = std::find(begin, std::end(ip_str), '/');
|
||||||
|
|
||||||
@@ -50,7 +53,8 @@ std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip_str)
|
|||||||
return { addr, addr + ((1 << bits) - 1) };
|
return { addr, addr + ((1 << bits) - 1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
net_e from_enum_string(const std::string_view &view) {
|
net_e
|
||||||
|
from_enum_string(const std::string_view &view) {
|
||||||
if (view == "wan") {
|
if (view == "wan") {
|
||||||
return WAN;
|
return WAN;
|
||||||
}
|
}
|
||||||
@@ -60,7 +64,8 @@ net_e from_enum_string(const std::string_view &view) {
|
|||||||
|
|
||||||
return PC;
|
return PC;
|
||||||
}
|
}
|
||||||
net_e from_address(const std::string_view &view) {
|
net_e
|
||||||
|
from_address(const std::string_view &view) {
|
||||||
auto addr = ip(view);
|
auto addr = ip(view);
|
||||||
|
|
||||||
for (auto [ip_low, ip_high] : pc_ips) {
|
for (auto [ip_low, ip_high] : pc_ips) {
|
||||||
@@ -78,7 +83,8 @@ net_e from_address(const std::string_view &view) {
|
|||||||
return WAN;
|
return WAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view to_enum_string(net_e net) {
|
std::string_view
|
||||||
|
to_enum_string(net_e net) {
|
||||||
switch (net) {
|
switch (net) {
|
||||||
case PC:
|
case PC:
|
||||||
return "pc"sv;
|
return "pc"sv;
|
||||||
@@ -92,14 +98,16 @@ std::string_view to_enum_string(net_e net) {
|
|||||||
return "wan"sv;
|
return "wan"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
host_t host_create(ENetAddress &addr, std::size_t peers, std::uint16_t port) {
|
host_t
|
||||||
|
host_create(ENetAddress &addr, std::size_t peers, std::uint16_t port) {
|
||||||
enet_address_set_host(&addr, "0.0.0.0");
|
enet_address_set_host(&addr, "0.0.0.0");
|
||||||
enet_address_set_port(&addr, port);
|
enet_address_set_port(&addr, port);
|
||||||
|
|
||||||
return host_t { enet_host_create(AF_INET, &addr, peers, 1, 0, 0) };
|
return host_t { enet_host_create(AF_INET, &addr, peers, 1, 0, 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_host(ENetHost *host) {
|
void
|
||||||
|
free_host(ENetHost *host) {
|
||||||
std::for_each(host->peers, host->peers + host->peerCount, [](ENetPeer &peer_ref) {
|
std::for_each(host->peers, host->peers + host->peerCount, [](ENetPeer &peer_ref) {
|
||||||
ENetPeer *peer = &peer_ref;
|
ENetPeer *peer = &peer_ref;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
void free_host(ENetHost *host);
|
void
|
||||||
|
free_host(ENetHost *host);
|
||||||
|
|
||||||
using host_t = util::safe_ptr<ENetHost, free_host>;
|
using host_t = util::safe_ptr<ENetHost, free_host>;
|
||||||
using peer_t = ENetPeer *;
|
using peer_t = ENetPeer *;
|
||||||
@@ -22,12 +23,16 @@ enum net_e : int {
|
|||||||
WAN
|
WAN
|
||||||
};
|
};
|
||||||
|
|
||||||
net_e from_enum_string(const std::string_view &view);
|
net_e
|
||||||
std::string_view to_enum_string(net_e net);
|
from_enum_string(const std::string_view &view);
|
||||||
|
std::string_view
|
||||||
|
to_enum_string(net_e net);
|
||||||
|
|
||||||
net_e from_address(const std::string_view &view);
|
net_e
|
||||||
|
from_address(const std::string_view &view);
|
||||||
|
|
||||||
host_t host_create(ENetAddress &addr, std::size_t peers, std::uint16_t port);
|
host_t
|
||||||
|
host_create(ENetAddress &addr, std::size_t peers, std::uint16_t port);
|
||||||
} // namespace net
|
} // namespace net
|
||||||
|
|
||||||
#endif // SUNSHINE_NETWORK_H
|
#endif // SUNSHINE_NETWORK_H
|
||||||
|
|||||||
@@ -38,14 +38,15 @@ namespace pt = boost::property_tree;
|
|||||||
|
|
||||||
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
||||||
public:
|
public:
|
||||||
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file)
|
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file):
|
||||||
: SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, private_key_file) {}
|
SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, private_key_file) {}
|
||||||
|
|
||||||
std::function<int(SSL *)> verify;
|
std::function<int(SSL *)> verify;
|
||||||
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
|
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void after_bind() override {
|
void
|
||||||
|
after_bind() override {
|
||||||
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();
|
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();
|
||||||
|
|
||||||
if (verify) {
|
if (verify) {
|
||||||
@@ -58,7 +59,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is Server<HTTPS>::accept() with SSL validation support added
|
// This is Server<HTTPS>::accept() with SSL validation support added
|
||||||
void accept() override {
|
void
|
||||||
|
accept() override {
|
||||||
auto connection = create_connection(*io_service, context);
|
auto connection = create_connection(*io_service, context);
|
||||||
|
|
||||||
acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const SimpleWeb::error_code &ec) {
|
acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const SimpleWeb::error_code &ec) {
|
||||||
@@ -147,7 +149,8 @@ enum class op_e {
|
|||||||
REMOVE
|
REMOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string get_arg(const args_t &args, const char *name) {
|
std::string
|
||||||
|
get_arg(const args_t &args, const char *name) {
|
||||||
auto it = args.find(name);
|
auto it = args.find(name);
|
||||||
if (it == std::end(args)) {
|
if (it == std::end(args)) {
|
||||||
throw std::out_of_range(name);
|
throw std::out_of_range(name);
|
||||||
@@ -155,7 +158,8 @@ std::string get_arg(const args_t &args, const char *name) {
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_state() {
|
void
|
||||||
|
save_state() {
|
||||||
pt::ptree root;
|
pt::ptree root;
|
||||||
|
|
||||||
if (fs::exists(config::nvhttp.file_state)) {
|
if (fs::exists(config::nvhttp.file_state)) {
|
||||||
@@ -197,7 +201,8 @@ void save_state() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_state() {
|
void
|
||||||
|
load_state() {
|
||||||
if (!fs::exists(config::nvhttp.file_state)) {
|
if (!fs::exists(config::nvhttp.file_state)) {
|
||||||
BOOST_LOG(info) << "File "sv << config::nvhttp.file_state << " doesn't exist"sv;
|
BOOST_LOG(info) << "File "sv << config::nvhttp.file_state << " doesn't exist"sv;
|
||||||
http::unique_id = uuid_util::uuid_t::generate().string();
|
http::unique_id = uuid_util::uuid_t::generate().string();
|
||||||
@@ -236,7 +241,8 @@ void load_state() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_id_client(const std::string &uniqueID, std::string &&cert, op_e op) {
|
void
|
||||||
|
update_id_client(const std::string &uniqueID, std::string &&cert, op_e op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case op_e::ADD: {
|
case op_e::ADD: {
|
||||||
auto &client = map_id_client[uniqueID];
|
auto &client = map_id_client[uniqueID];
|
||||||
@@ -253,7 +259,8 @@ void update_id_client(const std::string &uniqueID, std::string &&cert, op_e op)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtsp_stream::launch_session_t make_launch_session(bool host_audio, const args_t &args) {
|
rtsp_stream::launch_session_t
|
||||||
|
make_launch_session(bool host_audio, const args_t &args) {
|
||||||
rtsp_stream::launch_session_t launch_session;
|
rtsp_stream::launch_session_t launch_session;
|
||||||
|
|
||||||
launch_session.host_audio = host_audio;
|
launch_session.host_audio = host_audio;
|
||||||
@@ -267,7 +274,8 @@ rtsp_stream::launch_session_t make_launch_session(bool host_audio, const args_t
|
|||||||
return launch_session;
|
return launch_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getservercert(pair_session_t &sess, pt::ptree &tree, const std::string &pin) {
|
void
|
||||||
|
getservercert(pair_session_t &sess, pt::ptree &tree, const std::string &pin) {
|
||||||
if (sess.async_insert_pin.salt.size() < 32) {
|
if (sess.async_insert_pin.salt.size() < 32) {
|
||||||
tree.put("root.paired", 0);
|
tree.put("root.paired", 0);
|
||||||
tree.put("root.<xmlattr>.status_code", 400);
|
tree.put("root.<xmlattr>.status_code", 400);
|
||||||
@@ -285,7 +293,8 @@ void getservercert(pair_session_t &sess, pt::ptree &tree, const std::string &pin
|
|||||||
tree.put("root.plaincert", util::hex_vec(conf_intern.servercert, true));
|
tree.put("root.plaincert", util::hex_vec(conf_intern.servercert, true));
|
||||||
tree.put("root.<xmlattr>.status_code", 200);
|
tree.put("root.<xmlattr>.status_code", 200);
|
||||||
}
|
}
|
||||||
void serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
void
|
||||||
|
serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
||||||
auto encrypted_response = util::from_hex_vec(get_arg(args, "serverchallengeresp"), true);
|
auto encrypted_response = util::from_hex_vec(get_arg(args, "serverchallengeresp"), true);
|
||||||
|
|
||||||
std::vector<uint8_t> decrypted;
|
std::vector<uint8_t> decrypted;
|
||||||
@@ -305,7 +314,8 @@ void serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &ar
|
|||||||
tree.put("root.<xmlattr>.status_code", 200);
|
tree.put("root.<xmlattr>.status_code", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
void
|
||||||
|
clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
||||||
auto challenge = util::from_hex_vec(get_arg(args, "clientchallenge"), true);
|
auto challenge = util::from_hex_vec(get_arg(args, "clientchallenge"), true);
|
||||||
|
|
||||||
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
|
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
|
||||||
@@ -340,7 +350,8 @@ void clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args)
|
|||||||
tree.put("root.<xmlattr>.status_code", 200);
|
tree.put("root.<xmlattr>.status_code", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clientpairingsecret(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
void
|
||||||
|
clientpairingsecret(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
||||||
auto &client = sess.client;
|
auto &client = sess.client;
|
||||||
|
|
||||||
auto pairingsecret = util::from_hex_vec(get_arg(args, "clientpairingsecret"), true);
|
auto pairingsecret = util::from_hex_vec(get_arg(args, "clientpairingsecret"), true);
|
||||||
@@ -401,7 +412,8 @@ struct tunnel<SimpleWeb::HTTP> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void print_req(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void
|
||||||
|
print_req(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
BOOST_LOG(debug) << "TUNNEL :: "sv << tunnel<T>::to_string;
|
BOOST_LOG(debug) << "TUNNEL :: "sv << tunnel<T>::to_string;
|
||||||
|
|
||||||
BOOST_LOG(debug) << "METHOD :: "sv << request->method;
|
BOOST_LOG(debug) << "METHOD :: "sv << request->method;
|
||||||
@@ -421,7 +433,8 @@ void print_req(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void not_found(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void
|
||||||
|
not_found(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -440,7 +453,8 @@ void not_found(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void
|
||||||
|
pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -520,7 +534,8 @@ void pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_
|
|||||||
* bool pin_status = nvhttp::pin("1234");
|
* bool pin_status = nvhttp::pin("1234");
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
bool pin(std::string pin) {
|
bool
|
||||||
|
pin(std::string pin) {
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
if (map_id_sess.empty()) {
|
if (map_id_sess.empty()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -551,7 +566,8 @@ bool pin(std::string pin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void
|
||||||
|
pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
response->close_connection_after_response = true;
|
response->close_connection_after_response = true;
|
||||||
@@ -576,7 +592,8 @@ void pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void
|
||||||
|
serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
int pair_status = 0;
|
int pair_status = 0;
|
||||||
@@ -584,7 +601,6 @@ void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> res
|
|||||||
auto args = request->parse_query_string();
|
auto args = request->parse_query_string();
|
||||||
auto clientID = args.find("uniqueid"s);
|
auto clientID = args.find("uniqueid"s);
|
||||||
|
|
||||||
|
|
||||||
if (clientID != std::end(args)) {
|
if (clientID != std::end(args)) {
|
||||||
if (auto it = map_id_client.find(clientID->second); it != std::end(map_id_client)) {
|
if (auto it = map_id_client.find(clientID->second); it != std::end(map_id_client)) {
|
||||||
pair_status = 1;
|
pair_status = 1;
|
||||||
@@ -659,7 +675,8 @@ void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> res
|
|||||||
response->close_connection_after_response = true;
|
response->close_connection_after_response = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applist(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
applist(resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SimpleWeb::HTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -703,7 +720,8 @@ void applist(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
void
|
||||||
|
launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SimpleWeb::HTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -728,7 +746,6 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
args.find("rikeyid"s) == std::end(args) ||
|
args.find("rikeyid"s) == std::end(args) ||
|
||||||
args.find("localAudioPlayMode"s) == std::end(args) ||
|
args.find("localAudioPlayMode"s) == std::end(args) ||
|
||||||
args.find("appid"s) == std::end(args)) {
|
args.find("appid"s) == std::end(args)) {
|
||||||
|
|
||||||
tree.put("root.resume", 0);
|
tree.put("root.resume", 0);
|
||||||
tree.put("root.<xmlattr>.status_code", 400);
|
tree.put("root.<xmlattr>.status_code", 400);
|
||||||
|
|
||||||
@@ -763,7 +780,8 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
tree.put("root.gamesession", 1);
|
tree.put("root.gamesession", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
void
|
||||||
|
resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SimpleWeb::HTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -796,7 +814,6 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
if (
|
if (
|
||||||
args.find("rikey"s) == std::end(args) ||
|
args.find("rikey"s) == std::end(args) ||
|
||||||
args.find("rikeyid"s) == std::end(args)) {
|
args.find("rikeyid"s) == std::end(args)) {
|
||||||
|
|
||||||
tree.put("root.resume", 0);
|
tree.put("root.resume", 0);
|
||||||
tree.put("root.<xmlattr>.status_code", 400);
|
tree.put("root.<xmlattr>.status_code", 400);
|
||||||
|
|
||||||
@@ -810,7 +827,8 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
tree.put("root.resume", 1);
|
tree.put("root.resume", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancel(resp_https_t response, req_https_t request) {
|
void
|
||||||
|
cancel(resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SimpleWeb::HTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
@@ -839,8 +857,8 @@ void cancel(resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
void appasset(resp_https_t response, req_https_t request) {
|
appasset(resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SimpleWeb::HTTPS>(request);
|
||||||
|
|
||||||
auto args = request->parse_query_string();
|
auto args = request->parse_query_string();
|
||||||
@@ -861,7 +879,8 @@ void appasset(resp_https_t response, req_https_t request) {
|
|||||||
* nvhttp::start();
|
* nvhttp::start();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void start() {
|
void
|
||||||
|
start() {
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||||
|
|
||||||
auto port_http = map_port(PORT_HTTP);
|
auto port_http = map_port(PORT_HTTP);
|
||||||
@@ -905,7 +924,6 @@ void start() {
|
|||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
char subject_name[256];
|
char subject_name[256];
|
||||||
|
|
||||||
|
|
||||||
X509_NAME_oneline(X509_get_subject_name(x509), subject_name, sizeof(subject_name));
|
X509_NAME_oneline(X509_get_subject_name(x509), subject_name, sizeof(subject_name));
|
||||||
|
|
||||||
BOOST_LOG(debug) << subject_name << " -- "sv << (verified ? "verified"sv : "denied"sv);
|
BOOST_LOG(debug) << subject_name << " -- "sv << (verified ? "verified"sv : "denied"sv);
|
||||||
@@ -1007,7 +1025,8 @@ void start() {
|
|||||||
* nvhttp::erase_all_clients();
|
* nvhttp::erase_all_clients();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void erase_all_clients() {
|
void
|
||||||
|
erase_all_clients() {
|
||||||
map_id_client.clear();
|
map_id_client.clear();
|
||||||
save_state();
|
save_state();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,12 @@ constexpr auto PORT_HTTP = 0;
|
|||||||
constexpr auto PORT_HTTPS = -5;
|
constexpr auto PORT_HTTPS = -5;
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
void start();
|
void
|
||||||
bool pin(std::string pin);
|
start();
|
||||||
void erase_all_clients();
|
bool
|
||||||
|
pin(std::string pin);
|
||||||
|
void
|
||||||
|
erase_all_clients();
|
||||||
} // namespace nvhttp
|
} // namespace nvhttp
|
||||||
|
|
||||||
#endif // SUNSHINE_NVHTTP_H
|
#endif // SUNSHINE_NVHTTP_H
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ constexpr std::uint16_t Y = 0x8000;
|
|||||||
struct rumble_t {
|
struct rumble_t {
|
||||||
KITTY_DEFAULT_CONSTR(rumble_t)
|
KITTY_DEFAULT_CONSTR(rumble_t)
|
||||||
|
|
||||||
rumble_t(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq)
|
rumble_t(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq):
|
||||||
: id { id }, lowfreq { lowfreq }, highfreq { highfreq } {}
|
id { id }, lowfreq { lowfreq }, highfreq { highfreq } {}
|
||||||
|
|
||||||
std::uint16_t id;
|
std::uint16_t id;
|
||||||
std::uint16_t lowfreq;
|
std::uint16_t lowfreq;
|
||||||
@@ -130,7 +130,8 @@ enum class pix_fmt_e {
|
|||||||
unknown
|
unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string_view from_pix_fmt(pix_fmt_e pix_fmt) {
|
inline std::string_view
|
||||||
|
from_pix_fmt(pix_fmt_e pix_fmt) {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
#define _CONVERT(x) \
|
#define _CONVERT(x) \
|
||||||
case pix_fmt_e::x: \
|
case pix_fmt_e::x: \
|
||||||
@@ -174,8 +175,10 @@ public:
|
|||||||
|
|
||||||
img_t(img_t &&) = delete;
|
img_t(img_t &&) = delete;
|
||||||
img_t(const img_t &) = delete;
|
img_t(const img_t &) = delete;
|
||||||
img_t &operator=(img_t &&) = delete;
|
img_t &
|
||||||
img_t &operator=(const img_t &) = delete;
|
operator=(img_t &&) = delete;
|
||||||
|
img_t &
|
||||||
|
operator=(const img_t &) = delete;
|
||||||
|
|
||||||
std::uint8_t *data {};
|
std::uint8_t *data {};
|
||||||
std::int32_t width {};
|
std::int32_t width {};
|
||||||
@@ -204,29 +207,34 @@ struct hwdevice_t {
|
|||||||
void *data {};
|
void *data {};
|
||||||
AVFrame *frame {};
|
AVFrame *frame {};
|
||||||
|
|
||||||
virtual int convert(platf::img_t &img) {
|
virtual int
|
||||||
|
convert(platf::img_t &img) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* implementations must take ownership of 'frame'
|
* implementations must take ownership of 'frame'
|
||||||
*/
|
*/
|
||||||
virtual int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
virtual int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||||
BOOST_LOG(error) << "Illegal call to hwdevice_t::set_frame(). Did you forget to override it?";
|
BOOST_LOG(error) << "Illegal call to hwdevice_t::set_frame(). Did you forget to override it?";
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {};
|
virtual void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations may set parameters during initialization of the hwframes context
|
* Implementations may set parameters during initialization of the hwframes context
|
||||||
*/
|
*/
|
||||||
virtual void init_hwframes(AVHWFramesContext *frames) {};
|
virtual void
|
||||||
|
init_hwframes(AVHWFramesContext *frames) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations may make modifications required before context derivation
|
* Implementations may make modifications required before context derivation
|
||||||
*/
|
*/
|
||||||
virtual int prepare_to_derive_context(int hw_device_type) {
|
virtual int
|
||||||
|
prepare_to_derive_context(int hw_device_type) {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -255,7 +263,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
using snapshot_cb_t = std::function<std::shared_ptr<img_t>(std::shared_ptr<img_t> &img, bool frame_captured)>;
|
using snapshot_cb_t = std::function<std::shared_ptr<img_t>(std::shared_ptr<img_t> &img, bool frame_captured)>;
|
||||||
|
|
||||||
display_t() noexcept : offset_x { 0 }, offset_y { 0 } {}
|
display_t() noexcept:
|
||||||
|
offset_x { 0 }, offset_y { 0 } {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snapshot_cb --> the callback
|
* snapshot_cb --> the callback
|
||||||
@@ -267,21 +276,27 @@ public:
|
|||||||
* capture_e::error on error
|
* capture_e::error on error
|
||||||
* capture_e::reinit when need of reinitialization
|
* capture_e::reinit when need of reinitialization
|
||||||
*/
|
*/
|
||||||
virtual capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) = 0;
|
virtual capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) = 0;
|
||||||
|
|
||||||
virtual std::shared_ptr<img_t> alloc_img() = 0;
|
virtual std::shared_ptr<img_t>
|
||||||
|
alloc_img() = 0;
|
||||||
|
|
||||||
virtual int dummy_img(img_t *img) = 0;
|
virtual int
|
||||||
|
dummy_img(img_t *img) = 0;
|
||||||
|
|
||||||
virtual std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) {
|
virtual std::shared_ptr<hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) {
|
||||||
return std::make_shared<hwdevice_t>();
|
return std::make_shared<hwdevice_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool is_hdr() {
|
virtual bool
|
||||||
|
is_hdr() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
virtual bool
|
||||||
|
get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
||||||
std::memset(&metadata, 0, sizeof(metadata));
|
std::memset(&metadata, 0, sizeof(metadata));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -297,34 +312,44 @@ public:
|
|||||||
|
|
||||||
class mic_t {
|
class mic_t {
|
||||||
public:
|
public:
|
||||||
virtual capture_e sample(std::vector<std::int16_t> &frame_buffer) = 0;
|
virtual capture_e
|
||||||
|
sample(std::vector<std::int16_t> &frame_buffer) = 0;
|
||||||
|
|
||||||
virtual ~mic_t() = default;
|
virtual ~mic_t() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class audio_control_t {
|
class audio_control_t {
|
||||||
public:
|
public:
|
||||||
virtual int set_sink(const std::string &sink) = 0;
|
virtual int
|
||||||
|
set_sink(const std::string &sink) = 0;
|
||||||
|
|
||||||
virtual std::unique_ptr<mic_t> microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) = 0;
|
virtual std::unique_ptr<mic_t>
|
||||||
|
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) = 0;
|
||||||
|
|
||||||
virtual std::optional<sink_t> sink_info() = 0;
|
virtual std::optional<sink_t>
|
||||||
|
sink_info() = 0;
|
||||||
|
|
||||||
virtual ~audio_control_t() = default;
|
virtual ~audio_control_t() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeInput(void *);
|
void
|
||||||
|
freeInput(void *);
|
||||||
|
|
||||||
using input_t = util::safe_ptr<void, freeInput>;
|
using input_t = util::safe_ptr<void, freeInput>;
|
||||||
|
|
||||||
std::filesystem::path appdata();
|
std::filesystem::path
|
||||||
|
appdata();
|
||||||
|
|
||||||
std::string get_mac_address(const std::string_view &address);
|
std::string
|
||||||
|
get_mac_address(const std::string_view &address);
|
||||||
|
|
||||||
std::string from_sockaddr(const sockaddr *const);
|
std::string
|
||||||
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const);
|
from_sockaddr(const sockaddr *const);
|
||||||
|
std::pair<std::uint16_t, std::string>
|
||||||
|
from_sockaddr_ex(const sockaddr *const);
|
||||||
|
|
||||||
std::unique_ptr<audio_control_t> audio_control();
|
std::unique_ptr<audio_control_t>
|
||||||
|
audio_control();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* display_name --> The name of the monitor that SHOULD be displayed
|
* display_name --> The name of the monitor that SHOULD be displayed
|
||||||
@@ -335,12 +360,15 @@ std::unique_ptr<audio_control_t> audio_control();
|
|||||||
*
|
*
|
||||||
* Returns display_t based on hwdevice_type
|
* Returns display_t based on hwdevice_type
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
std::shared_ptr<display_t>
|
||||||
|
display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
||||||
|
|
||||||
// A list of names of displays accepted as display_name with the mem_type_e
|
// A list of names of displays accepted as display_name with the mem_type_e
|
||||||
std::vector<std::string> display_names(mem_type_e hwdevice_type);
|
std::vector<std::string>
|
||||||
|
display_names(mem_type_e hwdevice_type);
|
||||||
|
|
||||||
boost::process::child run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, boost::process::environment &env, FILE *file, std::error_code &ec, boost::process::group *group);
|
boost::process::child
|
||||||
|
run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, boost::process::environment &env, FILE *file, std::error_code &ec, boost::process::group *group);
|
||||||
|
|
||||||
enum class thread_priority_e : int {
|
enum class thread_priority_e : int {
|
||||||
low,
|
low,
|
||||||
@@ -348,14 +376,19 @@ enum class thread_priority_e : int {
|
|||||||
high,
|
high,
|
||||||
critical
|
critical
|
||||||
};
|
};
|
||||||
void adjust_thread_priority(thread_priority_e priority);
|
void
|
||||||
|
adjust_thread_priority(thread_priority_e priority);
|
||||||
|
|
||||||
// Allow OS-specific actions to be taken to prepare for streaming
|
// Allow OS-specific actions to be taken to prepare for streaming
|
||||||
void streaming_will_start();
|
void
|
||||||
void streaming_will_stop();
|
streaming_will_start();
|
||||||
|
void
|
||||||
|
streaming_will_stop();
|
||||||
|
|
||||||
bool restart_supported();
|
bool
|
||||||
bool restart();
|
restart_supported();
|
||||||
|
bool
|
||||||
|
restart();
|
||||||
|
|
||||||
struct batched_send_info_t {
|
struct batched_send_info_t {
|
||||||
const char *buffer;
|
const char *buffer;
|
||||||
@@ -366,37 +399,53 @@ struct batched_send_info_t {
|
|||||||
boost::asio::ip::address &target_address;
|
boost::asio::ip::address &target_address;
|
||||||
uint16_t target_port;
|
uint16_t target_port;
|
||||||
};
|
};
|
||||||
bool send_batch(batched_send_info_t &send_info);
|
bool
|
||||||
|
send_batch(batched_send_info_t &send_info);
|
||||||
|
|
||||||
enum class qos_data_type_e : int {
|
enum class qos_data_type_e : int {
|
||||||
audio,
|
audio,
|
||||||
video
|
video
|
||||||
};
|
};
|
||||||
std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type);
|
std::unique_ptr<deinit_t>
|
||||||
|
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type);
|
||||||
|
|
||||||
input_t input();
|
input_t
|
||||||
void move_mouse(input_t &input, int deltaX, int deltaY);
|
input();
|
||||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);
|
void
|
||||||
void button_mouse(input_t &input, int button, bool release);
|
move_mouse(input_t &input, int deltaX, int deltaY);
|
||||||
void scroll(input_t &input, int distance);
|
void
|
||||||
void hscroll(input_t &input, int distance);
|
abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);
|
||||||
void keyboard(input_t &input, uint16_t modcode, bool release);
|
void
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
|
button_mouse(input_t &input, int button, bool release);
|
||||||
void unicode(input_t &input, char *utf8, int size);
|
void
|
||||||
|
scroll(input_t &input, int distance);
|
||||||
|
void
|
||||||
|
hscroll(input_t &input, int distance);
|
||||||
|
void
|
||||||
|
keyboard(input_t &input, uint16_t modcode, bool release);
|
||||||
|
void
|
||||||
|
gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
|
||||||
|
void
|
||||||
|
unicode(input_t &input, char *utf8, int size);
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue);
|
int
|
||||||
void free_gamepad(input_t &input, int nr);
|
alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue);
|
||||||
|
void
|
||||||
|
free_gamepad(input_t &input, int nr);
|
||||||
|
|
||||||
#define SERVICE_NAME "Sunshine"
|
#define SERVICE_NAME "Sunshine"
|
||||||
#define SERVICE_TYPE "_nvstream._tcp"
|
#define SERVICE_TYPE "_nvstream._tcp"
|
||||||
|
|
||||||
namespace publish {
|
namespace publish {
|
||||||
[[nodiscard]] std::unique_ptr<deinit_t> start();
|
[[nodiscard]] std::unique_ptr<deinit_t>
|
||||||
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<deinit_t> init();
|
[[nodiscard]] std::unique_ptr<deinit_t>
|
||||||
|
init();
|
||||||
|
|
||||||
std::vector<std::string_view> &supported_gamepads();
|
std::vector<std::string_view> &
|
||||||
|
supported_gamepads();
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|
||||||
#endif //SUNSHINE_COMMON_H
|
#endif //SUNSHINE_COMMON_H
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ constexpr pa_channel_position_t position_mapping[] {
|
|||||||
PA_CHANNEL_POSITION_SIDE_RIGHT,
|
PA_CHANNEL_POSITION_SIDE_RIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string to_string(const char *name, const std::uint8_t *mapping, int channels) {
|
std::string
|
||||||
|
to_string(const char *name, const std::uint8_t *mapping, int channels) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << "rate=48000 sink_name="sv << name << " format=s16le channels="sv << channels << " channel_map="sv;
|
ss << "rate=48000 sink_name="sv << name << " format=s16le channels="sv << channels << " channel_map="sv;
|
||||||
@@ -50,7 +51,8 @@ std::string to_string(const char *name, const std::uint8_t *mapping, int channel
|
|||||||
struct mic_attr_t: public mic_t {
|
struct mic_attr_t: public mic_t {
|
||||||
util::safe_ptr<pa_simple, pa_simple_free> mic;
|
util::safe_ptr<pa_simple, pa_simple_free> mic;
|
||||||
|
|
||||||
capture_e sample(std::vector<std::int16_t> &sample_buf) override {
|
capture_e
|
||||||
|
sample(std::vector<std::int16_t> &sample_buf) override {
|
||||||
auto sample_size = sample_buf.size();
|
auto sample_size = sample_buf.size();
|
||||||
|
|
||||||
auto buf = sample_buf.data();
|
auto buf = sample_buf.data();
|
||||||
@@ -65,7 +67,8 @@ struct mic_attr_t : public mic_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<mic_t> microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size, std::string source_name) {
|
std::unique_ptr<mic_t>
|
||||||
|
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size, std::string source_name) {
|
||||||
auto mic = std::make_unique<mic_attr_t>();
|
auto mic = std::make_unique<mic_attr_t>();
|
||||||
|
|
||||||
pa_sample_spec ss { PA_SAMPLE_S16LE, sample_rate, (std::uint8_t) channels };
|
pa_sample_spec ss { PA_SAMPLE_S16LE, sample_rate, (std::uint8_t) channels };
|
||||||
@@ -113,7 +116,8 @@ template<class T>
|
|||||||
using add_const_t = typename add_const_helper<std::is_pointer_v<T>, T>::type;
|
using add_const_t = typename add_const_helper<std::is_pointer_v<T>, T>::type;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void pa_free(T *p) {
|
void
|
||||||
|
pa_free(T *p) {
|
||||||
pa_xfree(p);
|
pa_xfree(p);
|
||||||
}
|
}
|
||||||
using ctx_t = util::safe_ptr<pa_context, pa_context_unref>;
|
using ctx_t = util::safe_ptr<pa_context, pa_context_unref>;
|
||||||
@@ -125,7 +129,8 @@ template<class T>
|
|||||||
using cb_simple_t = std::function<void(ctx_t::pointer, add_const_t<T> i)>;
|
using cb_simple_t = std::function<void(ctx_t::pointer, add_const_t<T> i)>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void cb(ctx_t::pointer ctx, add_const_t<T> i, void *userdata) {
|
void
|
||||||
|
cb(ctx_t::pointer ctx, add_const_t<T> i, void *userdata) {
|
||||||
auto &f = *(cb_simple_t<T> *) userdata;
|
auto &f = *(cb_simple_t<T> *) userdata;
|
||||||
|
|
||||||
// Cannot similarly filter on eol here. Unless reported otherwise assume
|
// Cannot similarly filter on eol here. Unless reported otherwise assume
|
||||||
@@ -137,7 +142,8 @@ template<class T>
|
|||||||
using cb_t = std::function<void(ctx_t::pointer, add_const_t<T> i, int eol)>;
|
using cb_t = std::function<void(ctx_t::pointer, add_const_t<T> i, int eol)>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void cb(ctx_t::pointer ctx, add_const_t<T> i, int eol, void *userdata) {
|
void
|
||||||
|
cb(ctx_t::pointer ctx, add_const_t<T> i, int eol, void *userdata) {
|
||||||
auto &f = *(cb_t<T> *) userdata;
|
auto &f = *(cb_t<T> *) userdata;
|
||||||
|
|
||||||
// For some reason, pulseaudio calls this callback after disconnecting
|
// For some reason, pulseaudio calls this callback after disconnecting
|
||||||
@@ -148,19 +154,22 @@ void cb(ctx_t::pointer ctx, add_const_t<T> i, int eol, void *userdata) {
|
|||||||
f(ctx, i, eol);
|
f(ctx, i, eol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cb_i(ctx_t::pointer ctx, std::uint32_t i, void *userdata) {
|
void
|
||||||
|
cb_i(ctx_t::pointer ctx, std::uint32_t i, void *userdata) {
|
||||||
auto alarm = (safe::alarm_raw_t<int> *) userdata;
|
auto alarm = (safe::alarm_raw_t<int> *) userdata;
|
||||||
|
|
||||||
alarm->ring(i);
|
alarm->ring(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctx_state_cb(ctx_t::pointer ctx, void *userdata) {
|
void
|
||||||
|
ctx_state_cb(ctx_t::pointer ctx, void *userdata) {
|
||||||
auto &f = *(std::function<void(ctx_t::pointer)> *) userdata;
|
auto &f = *(std::function<void(ctx_t::pointer)> *) userdata;
|
||||||
|
|
||||||
f(ctx);
|
f(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void success_cb(ctx_t::pointer ctx, int status, void *userdata) {
|
void
|
||||||
|
success_cb(ctx_t::pointer ctx, int status, void *userdata) {
|
||||||
assert(userdata != nullptr);
|
assert(userdata != nullptr);
|
||||||
|
|
||||||
auto alarm = (safe::alarm_raw_t<int> *) userdata;
|
auto alarm = (safe::alarm_raw_t<int> *) userdata;
|
||||||
@@ -189,7 +198,8 @@ public:
|
|||||||
std::unique_ptr<std::function<void(ctx_t::pointer)>> events_cb;
|
std::unique_ptr<std::function<void(ctx_t::pointer)>> events_cb;
|
||||||
|
|
||||||
std::thread worker;
|
std::thread worker;
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
events = std::make_unique<safe::event_t<ctx_event_e>>();
|
events = std::make_unique<safe::event_t<ctx_event_e>>();
|
||||||
loop.reset(pa_mainloop_new());
|
loop.reset(pa_mainloop_new());
|
||||||
ctx.reset(pa_context_new(pa_mainloop_get_api(loop.get()), "sunshine"));
|
ctx.reset(pa_context_new(pa_mainloop_get_api(loop.get()), "sunshine"));
|
||||||
@@ -245,7 +255,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_null(const char *name, const std::uint8_t *channel_mapping, int channels) {
|
int
|
||||||
|
load_null(const char *name, const std::uint8_t *channel_mapping, int channels) {
|
||||||
auto alarm = safe::make_alarm<int>();
|
auto alarm = safe::make_alarm<int>();
|
||||||
|
|
||||||
op_t op {
|
op_t op {
|
||||||
@@ -261,7 +272,8 @@ public:
|
|||||||
return *alarm->status();
|
return *alarm->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
int unload_null(std::uint32_t i) {
|
int
|
||||||
|
unload_null(std::uint32_t i) {
|
||||||
if (i == PA_INVALID_INDEX) {
|
if (i == PA_INVALID_INDEX) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -282,7 +294,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sink_t> sink_info() override {
|
std::optional<sink_t>
|
||||||
|
sink_info() override {
|
||||||
constexpr auto stereo = "sink-sunshine-stereo";
|
constexpr auto stereo = "sink-sunshine-stereo";
|
||||||
constexpr auto surround51 = "sink-sunshine-surround51";
|
constexpr auto surround51 = "sink-sunshine-surround51";
|
||||||
constexpr auto surround71 = "sink-sunshine-surround71";
|
constexpr auto surround71 = "sink-sunshine-surround71";
|
||||||
@@ -382,7 +395,8 @@ public:
|
|||||||
return std::make_optional(std::move(sink));
|
return std::make_optional(std::move(sink));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_default_sink_name() {
|
std::string
|
||||||
|
get_default_sink_name() {
|
||||||
std::string sink_name;
|
std::string sink_name;
|
||||||
auto alarm = safe::make_alarm<int>();
|
auto alarm = safe::make_alarm<int>();
|
||||||
|
|
||||||
@@ -404,7 +418,8 @@ public:
|
|||||||
return sink_name;
|
return sink_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_monitor_name(const std::string &sink_name) {
|
std::string
|
||||||
|
get_monitor_name(const std::string &sink_name) {
|
||||||
std::string monitor_name;
|
std::string monitor_name;
|
||||||
auto alarm = safe::make_alarm<int>();
|
auto alarm = safe::make_alarm<int>();
|
||||||
|
|
||||||
@@ -435,7 +450,8 @@ public:
|
|||||||
return monitor_name;
|
return monitor_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<mic_t> microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
std::unique_ptr<mic_t>
|
||||||
|
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
||||||
// Sink choice priority:
|
// Sink choice priority:
|
||||||
// 1. Config sink
|
// 1. Config sink
|
||||||
// 2. Last sink swapped to (Usually virtual in this case)
|
// 2. Last sink swapped to (Usually virtual in this case)
|
||||||
@@ -450,7 +466,8 @@ public:
|
|||||||
return ::platf::microphone(mapping, channels, sample_rate, frame_size, get_monitor_name(sink_name));
|
return ::platf::microphone(mapping, channels, sample_rate, frame_size, get_monitor_name(sink_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_sink(const std::string &sink) override {
|
int
|
||||||
|
set_sink(const std::string &sink) override {
|
||||||
auto alarm = safe::make_alarm<int>();
|
auto alarm = safe::make_alarm<int>();
|
||||||
|
|
||||||
BOOST_LOG(info) << "Setting default sink to: ["sv << sink << "]"sv;
|
BOOST_LOG(info) << "Setting default sink to: ["sv << sink << "]"sv;
|
||||||
@@ -495,7 +512,8 @@ public:
|
|||||||
};
|
};
|
||||||
} // namespace pa
|
} // namespace pa
|
||||||
|
|
||||||
std::unique_ptr<audio_control_t> audio_control() {
|
std::unique_ptr<audio_control_t>
|
||||||
|
audio_control() {
|
||||||
auto audio = std::make_unique<pa::server_t>();
|
auto audio = std::make_unique<pa::server_t>();
|
||||||
|
|
||||||
if (audio->init()) {
|
if (audio->init()) {
|
||||||
|
|||||||
@@ -30,11 +30,13 @@ namespace cuda {
|
|||||||
constexpr auto cudaDevAttrMaxThreadsPerBlock = (CUdevice_attribute) 1;
|
constexpr auto cudaDevAttrMaxThreadsPerBlock = (CUdevice_attribute) 1;
|
||||||
constexpr auto cudaDevAttrMaxThreadsPerMultiProcessor = (CUdevice_attribute) 39;
|
constexpr auto cudaDevAttrMaxThreadsPerMultiProcessor = (CUdevice_attribute) 39;
|
||||||
|
|
||||||
void pass_error(const std::string_view &sv, const char *name, const char *description) {
|
void
|
||||||
|
pass_error(const std::string_view &sv, const char *name, const char *description) {
|
||||||
BOOST_LOG(error) << sv << name << ':' << description;
|
BOOST_LOG(error) << sv << name << ':' << description;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cff(CudaFunctions *cf) {
|
void
|
||||||
|
cff(CudaFunctions *cf) {
|
||||||
cuda_free_functions(&cf);
|
cuda_free_functions(&cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +44,8 @@ using cdf_t = util::safe_ptr<CudaFunctions, cff>;
|
|||||||
|
|
||||||
static cdf_t cdf;
|
static cdf_t cdf;
|
||||||
|
|
||||||
inline static int check(CUresult result, const std::string_view &sv) {
|
inline static int
|
||||||
|
check(CUresult result, const std::string_view &sv) {
|
||||||
if (result != CUDA_SUCCESS) {
|
if (result != CUDA_SUCCESS) {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *description;
|
const char *description;
|
||||||
@@ -57,7 +60,8 @@ inline static int check(CUresult result, const std::string_view &sv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeStream(CUstream stream) {
|
void
|
||||||
|
freeStream(CUstream stream) {
|
||||||
CU_CHECK_IGNORE(cdf->cuStreamDestroy(stream), "Couldn't destroy cuda stream");
|
CU_CHECK_IGNORE(cdf->cuStreamDestroy(stream), "Couldn't destroy cuda stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +70,8 @@ public:
|
|||||||
tex_t tex;
|
tex_t tex;
|
||||||
};
|
};
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
auto status = cuda_load_functions(&cdf, nullptr);
|
auto status = cuda_load_functions(&cdf, nullptr);
|
||||||
if (status) {
|
if (status) {
|
||||||
BOOST_LOG(error) << "Couldn't load cuda: "sv << status;
|
BOOST_LOG(error) << "Couldn't load cuda: "sv << status;
|
||||||
@@ -81,7 +86,8 @@ int init() {
|
|||||||
|
|
||||||
class cuda_t: public platf::hwdevice_t {
|
class cuda_t: public platf::hwdevice_t {
|
||||||
public:
|
public:
|
||||||
int init(int in_width, int in_height) {
|
int
|
||||||
|
init(int in_width, int in_height) {
|
||||||
if (!cdf) {
|
if (!cdf) {
|
||||||
BOOST_LOG(warning) << "cuda not initialized"sv;
|
BOOST_LOG(warning) << "cuda not initialized"sv;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -95,7 +101,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
||||||
this->hwframe.reset(frame);
|
this->hwframe.reset(frame);
|
||||||
this->frame = frame;
|
this->frame = frame;
|
||||||
|
|
||||||
@@ -133,7 +140,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
||||||
sws.set_colorspace(colorspace, color_range);
|
sws.set_colorspace(colorspace, color_range);
|
||||||
|
|
||||||
auto tex = tex_t::make(height, width * 4);
|
auto tex = tex_t::make(height, width * 4);
|
||||||
@@ -161,7 +169,8 @@ public:
|
|||||||
sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex->texture.linear, stream.get(), { frame->width, frame->height, 0, 0 });
|
sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex->texture.linear, stream.get(), { frame->width, frame->height, 0, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
cudaTextureObject_t tex_obj(const tex_t &tex) const {
|
cudaTextureObject_t
|
||||||
|
tex_obj(const tex_t &tex) const {
|
||||||
return linear_interpolation ? tex.texture.linear : tex.texture.point;
|
return linear_interpolation ? tex.texture.linear : tex.texture.point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,11 +187,13 @@ public:
|
|||||||
|
|
||||||
class cuda_ram_t: public cuda_t {
|
class cuda_ram_t: public cuda_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img) override {
|
int
|
||||||
|
convert(platf::img_t &img) override {
|
||||||
return sws.load_ram(img, tex.array) || sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex_obj(tex), stream.get());
|
return sws.load_ram(img, tex.array) || sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex_obj(tex), stream.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||||
if (cuda_t::set_frame(frame, hw_frames_ctx)) {
|
if (cuda_t::set_frame(frame, hw_frames_ctx)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -202,12 +213,14 @@ public:
|
|||||||
|
|
||||||
class cuda_vram_t: public cuda_t {
|
class cuda_vram_t: public cuda_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img) override {
|
int
|
||||||
|
convert(platf::img_t &img) override {
|
||||||
return sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex_obj(((img_t *) &img)->tex), stream.get());
|
return sws.convert(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1], tex_obj(((img_t *) &img)->tex), stream.get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, bool vram) {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, bool vram) {
|
||||||
if (init()) {
|
if (init()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -232,12 +245,14 @@ namespace nvfbc {
|
|||||||
static PNVFBCCREATEINSTANCE createInstance {};
|
static PNVFBCCREATEINSTANCE createInstance {};
|
||||||
static NVFBC_API_FUNCTION_LIST func { NVFBC_VERSION };
|
static NVFBC_API_FUNCTION_LIST func { NVFBC_VERSION };
|
||||||
|
|
||||||
static constexpr inline NVFBC_BOOL nv_bool(bool b) {
|
static constexpr inline NVFBC_BOOL
|
||||||
|
nv_bool(bool b) {
|
||||||
return b ? NVFBC_TRUE : NVFBC_FALSE;
|
return b ? NVFBC_TRUE : NVFBC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
if (funcs_loaded) return 0;
|
if (funcs_loaded) return 0;
|
||||||
@@ -304,18 +319,21 @@ class handle_t {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
handle_t() = default;
|
handle_t() = default;
|
||||||
handle_t(handle_t &&other) : handle_flags { other.handle_flags }, handle { other.handle } {
|
handle_t(handle_t &&other):
|
||||||
|
handle_flags { other.handle_flags }, handle { other.handle } {
|
||||||
other.handle_flags.reset();
|
other.handle_flags.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_t &operator=(handle_t &&other) {
|
handle_t &
|
||||||
|
operator=(handle_t &&other) {
|
||||||
std::swap(handle_flags, other.handle_flags);
|
std::swap(handle_flags, other.handle_flags);
|
||||||
std::swap(handle, other.handle);
|
std::swap(handle, other.handle);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<handle_t> make() {
|
static std::optional<handle_t>
|
||||||
|
make() {
|
||||||
NVFBC_CREATE_HANDLE_PARAMS params { NVFBC_CREATE_HANDLE_PARAMS_VER };
|
NVFBC_CREATE_HANDLE_PARAMS params { NVFBC_CREATE_HANDLE_PARAMS_VER };
|
||||||
|
|
||||||
handle_t handle;
|
handle_t handle;
|
||||||
@@ -331,11 +349,13 @@ public:
|
|||||||
return std::move(handle);
|
return std::move(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *last_error() {
|
const char *
|
||||||
|
last_error() {
|
||||||
return func.nvFBCGetLastErrorStr(handle);
|
return func.nvFBCGetLastErrorStr(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<NVFBC_GET_STATUS_PARAMS> status() {
|
std::optional<NVFBC_GET_STATUS_PARAMS>
|
||||||
|
status() {
|
||||||
NVFBC_GET_STATUS_PARAMS params { NVFBC_GET_STATUS_PARAMS_VER };
|
NVFBC_GET_STATUS_PARAMS params { NVFBC_GET_STATUS_PARAMS_VER };
|
||||||
|
|
||||||
auto status = func.nvFBCGetStatus(handle, ¶ms);
|
auto status = func.nvFBCGetStatus(handle, ¶ms);
|
||||||
@@ -348,7 +368,8 @@ public:
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
int capture(NVFBC_CREATE_CAPTURE_SESSION_PARAMS &capture_params) {
|
int
|
||||||
|
capture(NVFBC_CREATE_CAPTURE_SESSION_PARAMS &capture_params) {
|
||||||
if (func.nvFBCCreateCaptureSession(handle, &capture_params)) {
|
if (func.nvFBCCreateCaptureSession(handle, &capture_params)) {
|
||||||
BOOST_LOG(error) << "Failed to start capture session: "sv << last_error();
|
BOOST_LOG(error) << "Failed to start capture session: "sv << last_error();
|
||||||
return -1;
|
return -1;
|
||||||
@@ -368,7 +389,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stop() {
|
int
|
||||||
|
stop() {
|
||||||
if (!handle_flags[SESSION_CAPTURE]) {
|
if (!handle_flags[SESSION_CAPTURE]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -386,7 +408,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reset() {
|
int
|
||||||
|
reset() {
|
||||||
if (!handle_flags[SESSION_HANDLE]) {
|
if (!handle_flags[SESSION_HANDLE]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -415,7 +438,8 @@ public:
|
|||||||
|
|
||||||
class display_t: public platf::display_t {
|
class display_t: public platf::display_t {
|
||||||
public:
|
public:
|
||||||
int init(const std::string_view &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string_view &display_name, const ::video::config_t &config) {
|
||||||
auto handle = handle_t::make();
|
auto handle = handle_t::make();
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -479,7 +503,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
platf::capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
// Force display_t::capture to initialize handle_t::capture
|
// Force display_t::capture to initialize handle_t::capture
|
||||||
@@ -522,7 +547,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reinitialize the capture session.
|
// Reinitialize the capture session.
|
||||||
platf::capture_e reinit(bool cursor) {
|
platf::capture_e
|
||||||
|
reinit(bool cursor) {
|
||||||
if (handle.stop()) {
|
if (handle.stop()) {
|
||||||
return platf::capture_e::error;
|
return platf::capture_e::error;
|
||||||
}
|
}
|
||||||
@@ -591,7 +617,8 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::capture_e snapshot(platf::img_t *img, std::chrono::milliseconds timeout, bool cursor) {
|
platf::capture_e
|
||||||
|
snapshot(platf::img_t *img, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
if (cursor != cursor_visible) {
|
if (cursor != cursor_visible) {
|
||||||
auto status = reinit(cursor);
|
auto status = reinit(cursor);
|
||||||
if (status != platf::capture_e::ok) {
|
if (status != platf::capture_e::ok) {
|
||||||
@@ -626,11 +653,13 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
||||||
return ::cuda::make_hwdevice(width, height, true);
|
return ::cuda::make_hwdevice(width, height, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::img_t> alloc_img() override {
|
std::shared_ptr<platf::img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<cuda::img_t>();
|
auto img = std::make_shared<cuda::img_t>();
|
||||||
|
|
||||||
img->data = nullptr;
|
img->data = nullptr;
|
||||||
@@ -649,7 +678,8 @@ public:
|
|||||||
return img;
|
return img;
|
||||||
};
|
};
|
||||||
|
|
||||||
int dummy_img(platf::img_t *) override {
|
int
|
||||||
|
dummy_img(platf::img_t *) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,7 +694,8 @@ public:
|
|||||||
} // namespace cuda
|
} // namespace cuda
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||||
if (hwdevice_type != mem_type_e::cuda) {
|
if (hwdevice_type != mem_type_e::cuda) {
|
||||||
BOOST_LOG(error) << "Could not initialize nvfbc display with the given hw device type"sv;
|
BOOST_LOG(error) << "Could not initialize nvfbc display with the given hw device type"sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -679,7 +710,8 @@ std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::st
|
|||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> nvfbc_display_names() {
|
std::vector<std::string>
|
||||||
|
nvfbc_display_names() {
|
||||||
if (cuda::init() || cuda::nvfbc::init()) {
|
if (cuda::init() || cuda::nvfbc::init()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,13 @@ class img_t;
|
|||||||
namespace cuda {
|
namespace cuda {
|
||||||
|
|
||||||
namespace nvfbc {
|
namespace nvfbc {
|
||||||
std::vector<std::string> display_names();
|
std::vector<std::string>
|
||||||
|
display_names();
|
||||||
}
|
}
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, bool vram);
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
int init();
|
make_hwdevice(int width, int height, bool vram);
|
||||||
|
int
|
||||||
|
init();
|
||||||
} // namespace cuda
|
} // namespace cuda
|
||||||
|
|
||||||
typedef struct cudaArray *cudaArray_t;
|
typedef struct cudaArray *cudaArray_t;
|
||||||
@@ -34,18 +37,21 @@ namespace cuda {
|
|||||||
|
|
||||||
class freeCudaPtr_t {
|
class freeCudaPtr_t {
|
||||||
public:
|
public:
|
||||||
void operator()(void *ptr);
|
void
|
||||||
|
operator()(void *ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
class freeCudaStream_t {
|
class freeCudaStream_t {
|
||||||
public:
|
public:
|
||||||
void operator()(cudaStream_t ptr);
|
void
|
||||||
|
operator()(cudaStream_t ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
using ptr_t = std::unique_ptr<void, freeCudaPtr_t>;
|
using ptr_t = std::unique_ptr<void, freeCudaPtr_t>;
|
||||||
using stream_t = std::unique_ptr<CUstream_st, freeCudaStream_t>;
|
using stream_t = std::unique_ptr<CUstream_st, freeCudaStream_t>;
|
||||||
|
|
||||||
stream_t make_stream(int flags = 0);
|
stream_t
|
||||||
|
make_stream(int flags = 0);
|
||||||
|
|
||||||
struct viewport_t {
|
struct viewport_t {
|
||||||
int width, height;
|
int width, height;
|
||||||
@@ -54,16 +60,19 @@ struct viewport_t {
|
|||||||
|
|
||||||
class tex_t {
|
class tex_t {
|
||||||
public:
|
public:
|
||||||
static std::optional<tex_t> make(int height, int pitch);
|
static std::optional<tex_t>
|
||||||
|
make(int height, int pitch);
|
||||||
|
|
||||||
tex_t();
|
tex_t();
|
||||||
tex_t(tex_t &&);
|
tex_t(tex_t &&);
|
||||||
|
|
||||||
tex_t &operator=(tex_t &&other);
|
tex_t &
|
||||||
|
operator=(tex_t &&other);
|
||||||
|
|
||||||
~tex_t();
|
~tex_t();
|
||||||
|
|
||||||
int copy(std::uint8_t *src, int height, int pitch);
|
int
|
||||||
|
copy(std::uint8_t *src, int height, int pitch);
|
||||||
|
|
||||||
cudaArray_t array;
|
cudaArray_t array;
|
||||||
|
|
||||||
@@ -84,15 +93,20 @@ public:
|
|||||||
*
|
*
|
||||||
* pitch -- The size of a single row of pixels in bytes
|
* pitch -- The size of a single row of pixels in bytes
|
||||||
*/
|
*/
|
||||||
static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_height, int pitch);
|
static std::optional<sws_t>
|
||||||
|
make(int in_width, int in_height, int out_width, int out_height, int pitch);
|
||||||
|
|
||||||
// Converts loaded image into a CUDevicePtr
|
// Converts loaded image into a CUDevicePtr
|
||||||
int convert(std::uint8_t *Y, std::uint8_t *UV, std::uint32_t pitchY, std::uint32_t pitchUV, cudaTextureObject_t texture, stream_t::pointer stream);
|
int
|
||||||
int convert(std::uint8_t *Y, std::uint8_t *UV, std::uint32_t pitchY, std::uint32_t pitchUV, cudaTextureObject_t texture, stream_t::pointer stream, const viewport_t &viewport);
|
convert(std::uint8_t *Y, std::uint8_t *UV, std::uint32_t pitchY, std::uint32_t pitchUV, cudaTextureObject_t texture, stream_t::pointer stream);
|
||||||
|
int
|
||||||
|
convert(std::uint8_t *Y, std::uint8_t *UV, std::uint32_t pitchY, std::uint32_t pitchUV, cudaTextureObject_t texture, stream_t::pointer stream, const viewport_t &viewport);
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
||||||
|
|
||||||
int load_ram(platf::img_t &img, cudaArray_t array);
|
int
|
||||||
|
load_ram(platf::img_t &img, cudaArray_t array);
|
||||||
|
|
||||||
ptr_t color_matrix;
|
ptr_t color_matrix;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ using namespace std::literals;
|
|||||||
namespace gl {
|
namespace gl {
|
||||||
GladGLContext ctx;
|
GladGLContext ctx;
|
||||||
|
|
||||||
void drain_errors(const std::string_view &prefix) {
|
void
|
||||||
|
drain_errors(const std::string_view &prefix) {
|
||||||
GLenum err;
|
GLenum err;
|
||||||
while ((err = ctx.GetError()) != GL_NO_ERROR) {
|
while ((err = ctx.GetError()) != GL_NO_ERROR) {
|
||||||
BOOST_LOG(error) << "GL: "sv << prefix << ": ["sv << util::hex(err).to_string_view() << ']';
|
BOOST_LOG(error) << "GL: "sv << prefix << ": ["sv << util::hex(err).to_string_view() << ']';
|
||||||
@@ -36,7 +37,8 @@ tex_t::~tex_t() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tex_t tex_t::make(std::size_t count) {
|
tex_t
|
||||||
|
tex_t::make(std::size_t count) {
|
||||||
tex_t textures { count };
|
tex_t textures { count };
|
||||||
|
|
||||||
ctx.GenTextures(textures.size(), textures.begin());
|
ctx.GenTextures(textures.size(), textures.begin());
|
||||||
@@ -61,7 +63,8 @@ frame_buf_t::~frame_buf_t() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_buf_t frame_buf_t::make(std::size_t count) {
|
frame_buf_t
|
||||||
|
frame_buf_t::make(std::size_t count) {
|
||||||
frame_buf_t frame_buf { count };
|
frame_buf_t frame_buf { count };
|
||||||
|
|
||||||
ctx.GenFramebuffers(frame_buf.size(), frame_buf.begin());
|
ctx.GenFramebuffers(frame_buf.size(), frame_buf.begin());
|
||||||
@@ -69,14 +72,16 @@ frame_buf_t frame_buf_t::make(std::size_t count) {
|
|||||||
return frame_buf;
|
return frame_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame_buf_t::copy(int id, int texture, int offset_x, int offset_y, int width, int height) {
|
void
|
||||||
|
frame_buf_t::copy(int id, int texture, int offset_x, int offset_y, int width, int height) {
|
||||||
gl::ctx.BindFramebuffer(GL_FRAMEBUFFER, (*this)[id]);
|
gl::ctx.BindFramebuffer(GL_FRAMEBUFFER, (*this)[id]);
|
||||||
gl::ctx.ReadBuffer(GL_COLOR_ATTACHMENT0 + id);
|
gl::ctx.ReadBuffer(GL_COLOR_ATTACHMENT0 + id);
|
||||||
gl::ctx.BindTexture(GL_TEXTURE_2D, texture);
|
gl::ctx.BindTexture(GL_TEXTURE_2D, texture);
|
||||||
gl::ctx.CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, offset_x, offset_y, width, height);
|
gl::ctx.CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, offset_x, offset_y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string shader_t::err_str() {
|
std::string
|
||||||
|
shader_t::err_str() {
|
||||||
int length;
|
int length;
|
||||||
ctx.GetShaderiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
ctx.GetShaderiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
||||||
|
|
||||||
@@ -90,7 +95,8 @@ std::string shader_t::err_str() {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Either<shader_t, std::string> shader_t::compile(const std::string_view &source, GLenum type) {
|
util::Either<shader_t, std::string>
|
||||||
|
shader_t::compile(const std::string_view &source, GLenum type) {
|
||||||
shader_t shader;
|
shader_t shader;
|
||||||
|
|
||||||
auto data = source.data();
|
auto data = source.data();
|
||||||
@@ -110,11 +116,13 @@ util::Either<shader_t, std::string> shader_t::compile(const std::string_view &so
|
|||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint shader_t::handle() const {
|
GLuint
|
||||||
|
shader_t::handle() const {
|
||||||
return _shader.el;
|
return _shader.el;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_t buffer_t::make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data) {
|
buffer_t
|
||||||
|
buffer_t::make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data) {
|
||||||
buffer_t buffer;
|
buffer_t buffer;
|
||||||
buffer._block = block;
|
buffer._block = block;
|
||||||
buffer._size = data.size();
|
buffer._size = data.size();
|
||||||
@@ -127,20 +135,24 @@ buffer_t buffer_t::make(util::buffer_t<GLint> &&offsets, const char *block, cons
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint buffer_t::handle() const {
|
GLuint
|
||||||
|
buffer_t::handle() const {
|
||||||
return _buffer.el;
|
return _buffer.el;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *buffer_t::block() const {
|
const char *
|
||||||
|
buffer_t::block() const {
|
||||||
return _block;
|
return _block;
|
||||||
}
|
}
|
||||||
|
|
||||||
void buffer_t::update(const std::string_view &view, std::size_t offset) {
|
void
|
||||||
|
buffer_t::update(const std::string_view &view, std::size_t offset) {
|
||||||
ctx.BindBuffer(GL_UNIFORM_BUFFER, handle());
|
ctx.BindBuffer(GL_UNIFORM_BUFFER, handle());
|
||||||
ctx.BufferSubData(GL_UNIFORM_BUFFER, offset, view.size(), (const void *) view.data());
|
ctx.BufferSubData(GL_UNIFORM_BUFFER, offset, view.size(), (const void *) view.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void buffer_t::update(std::string_view *members, std::size_t count, std::size_t offset) {
|
void
|
||||||
|
buffer_t::update(std::string_view *members, std::size_t count, std::size_t offset) {
|
||||||
util::buffer_t<std::uint8_t> buffer { _size };
|
util::buffer_t<std::uint8_t> buffer { _size };
|
||||||
|
|
||||||
for (int x = 0; x < count; ++x) {
|
for (int x = 0; x < count; ++x) {
|
||||||
@@ -152,7 +164,8 @@ void buffer_t::update(std::string_view *members, std::size_t count, std::size_t
|
|||||||
update(util::view(buffer.begin(), buffer.end()), offset);
|
update(util::view(buffer.begin(), buffer.end()), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string program_t::err_str() {
|
std::string
|
||||||
|
program_t::err_str() {
|
||||||
int length;
|
int length;
|
||||||
ctx.GetProgramiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
ctx.GetProgramiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
||||||
|
|
||||||
@@ -166,7 +179,8 @@ std::string program_t::err_str() {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Either<program_t, std::string> program_t::link(const shader_t &vert, const shader_t &frag) {
|
util::Either<program_t, std::string>
|
||||||
|
program_t::link(const shader_t &vert, const shader_t &frag) {
|
||||||
program_t program;
|
program_t program;
|
||||||
|
|
||||||
program._program.el = ctx.CreateProgram();
|
program._program.el = ctx.CreateProgram();
|
||||||
@@ -193,14 +207,16 @@ util::Either<program_t, std::string> program_t::link(const shader_t &vert, const
|
|||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
void program_t::bind(const buffer_t &buffer) {
|
void
|
||||||
|
program_t::bind(const buffer_t &buffer) {
|
||||||
ctx.UseProgram(handle());
|
ctx.UseProgram(handle());
|
||||||
auto i = ctx.GetUniformBlockIndex(handle(), buffer.block());
|
auto i = ctx.GetUniformBlockIndex(handle(), buffer.block());
|
||||||
|
|
||||||
ctx.BindBufferBase(GL_UNIFORM_BUFFER, i, buffer.handle());
|
ctx.BindBufferBase(GL_UNIFORM_BUFFER, i, buffer.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<buffer_t> program_t::uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count) {
|
std::optional<buffer_t>
|
||||||
|
program_t::uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count) {
|
||||||
auto i = ctx.GetUniformBlockIndex(handle(), block);
|
auto i = ctx.GetUniformBlockIndex(handle(), block);
|
||||||
if (i == GL_INVALID_INDEX) {
|
if (i == GL_INVALID_INDEX) {
|
||||||
BOOST_LOG(error) << "Couldn't find index of ["sv << block << ']';
|
BOOST_LOG(error) << "Couldn't find index of ["sv << block << ']';
|
||||||
@@ -248,7 +264,8 @@ std::optional<buffer_t> program_t::uniform(const char *block, std::pair<const ch
|
|||||||
return buffer_t::make(std::move(offsets), block, std::string_view { (char *) buffer.begin(), buffer.size() });
|
return buffer_t::make(std::move(offsets), block, std::string_view { (char *) buffer.begin(), buffer.size() });
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint program_t::handle() const {
|
GLuint
|
||||||
|
program_t::handle() const {
|
||||||
return _program.el;
|
return _program.el;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +275,8 @@ namespace gbm {
|
|||||||
device_destroy_fn device_destroy;
|
device_destroy_fn device_destroy;
|
||||||
create_device_fn create_device;
|
create_device_fn create_device;
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -309,11 +327,13 @@ constexpr auto EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT = 0x3448;
|
|||||||
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT = 0x3449;
|
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT = 0x3449;
|
||||||
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT = 0x344A;
|
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT = 0x344A;
|
||||||
|
|
||||||
bool fail() {
|
bool
|
||||||
|
fail() {
|
||||||
return eglGetError() != EGL_SUCCESS;
|
return eglGetError() != EGL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display) {
|
display_t
|
||||||
|
make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display) {
|
||||||
constexpr auto EGL_PLATFORM_GBM_MESA = 0x31D7;
|
constexpr auto EGL_PLATFORM_GBM_MESA = 0x31D7;
|
||||||
constexpr auto EGL_PLATFORM_WAYLAND_KHR = 0x31D8;
|
constexpr auto EGL_PLATFORM_WAYLAND_KHR = 0x31D8;
|
||||||
constexpr auto EGL_PLATFORM_X11_KHR = 0x31D5;
|
constexpr auto EGL_PLATFORM_X11_KHR = 0x31D5;
|
||||||
@@ -378,7 +398,8 @@ display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay
|
|||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ctx_t> make_ctx(display_t::pointer display) {
|
std::optional<ctx_t>
|
||||||
|
make_ctx(display_t::pointer display) {
|
||||||
constexpr int conf_attr[] {
|
constexpr int conf_attr[] {
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE
|
||||||
};
|
};
|
||||||
@@ -434,7 +455,8 @@ struct plane_attr_t {
|
|||||||
EGLAttrib hi;
|
EGLAttrib hi;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline plane_attr_t get_plane(std::uint32_t plane_indice) {
|
inline plane_attr_t
|
||||||
|
get_plane(std::uint32_t plane_indice) {
|
||||||
switch (plane_indice) {
|
switch (plane_indice) {
|
||||||
case 0:
|
case 0:
|
||||||
return {
|
return {
|
||||||
@@ -474,7 +496,8 @@ inline plane_attr_t get_plane(std::uint32_t plane_indice) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface_descriptor_t &xrgb) {
|
std::optional<rgb_t>
|
||||||
|
import_source(display_t::pointer egl_display, const surface_descriptor_t &xrgb) {
|
||||||
EGLAttrib attribs[47];
|
EGLAttrib attribs[47];
|
||||||
int atti = 0;
|
int atti = 0;
|
||||||
attribs[atti++] = EGL_WIDTH;
|
attribs[atti++] = EGL_WIDTH;
|
||||||
@@ -531,7 +554,8 @@ std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface
|
|||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nv12_t> import_target(display_t::pointer egl_display, std::array<file_t, nv12_img_t::num_fds> &&fds, const surface_descriptor_t &r8, const surface_descriptor_t &gr88) {
|
std::optional<nv12_t>
|
||||||
|
import_target(display_t::pointer egl_display, std::array<file_t, nv12_img_t::num_fds> &&fds, const surface_descriptor_t &r8, const surface_descriptor_t &gr88) {
|
||||||
EGLAttrib img_attr_planes[2][13] {
|
EGLAttrib img_attr_planes[2][13] {
|
||||||
{ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_R8,
|
{ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_R8,
|
||||||
EGL_WIDTH, r8.width,
|
EGL_WIDTH, r8.width,
|
||||||
@@ -578,7 +602,8 @@ std::optional<nv12_t> import_target(display_t::pointer egl_display, std::array<f
|
|||||||
return nv12;
|
return nv12;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sws_t::set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {
|
void
|
||||||
|
sws_t::set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {
|
||||||
video::color_t *color_p;
|
video::color_t *color_p;
|
||||||
switch (colorspace) {
|
switch (colorspace) {
|
||||||
case 5: // SWS_CS_SMPTE170M
|
case 5: // SWS_CS_SMPTE170M
|
||||||
@@ -614,7 +639,8 @@ void sws_t::set_colorspace(std::uint32_t colorspace, std::uint32_t color_range)
|
|||||||
program[1].bind(color_matrix);
|
program[1].bind(color_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sws_t> sws_t::make(int in_width, int in_height, int out_width, int out_heigth, gl::tex_t &&tex) {
|
std::optional<sws_t>
|
||||||
|
sws_t::make(int in_width, int in_height, int out_width, int out_heigth, gl::tex_t &&tex) {
|
||||||
sws_t sws;
|
sws_t sws;
|
||||||
|
|
||||||
sws.serial = std::numeric_limits<std::uint64_t>::max();
|
sws.serial = std::numeric_limits<std::uint64_t>::max();
|
||||||
@@ -742,7 +768,8 @@ std::optional<sws_t> sws_t::make(int in_width, int in_height, int out_width, int
|
|||||||
return std::move(sws);
|
return std::move(sws);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sws_t::blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int height) {
|
int
|
||||||
|
sws_t::blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int height) {
|
||||||
auto f = [&]() {
|
auto f = [&]() {
|
||||||
std::swap(offsetX, this->offsetX);
|
std::swap(offsetX, this->offsetX);
|
||||||
std::swap(offsetY, this->offsetY);
|
std::swap(offsetY, this->offsetY);
|
||||||
@@ -756,7 +783,8 @@ int sws_t::blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int h
|
|||||||
return convert(fb);
|
return convert(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sws_t> sws_t::make(int in_width, int in_height, int out_width, int out_heigth) {
|
std::optional<sws_t>
|
||||||
|
sws_t::make(int in_width, int in_height, int out_width, int out_heigth) {
|
||||||
auto tex = gl::tex_t::make(2);
|
auto tex = gl::tex_t::make(2);
|
||||||
gl::ctx.BindTexture(GL_TEXTURE_2D, tex[0]);
|
gl::ctx.BindTexture(GL_TEXTURE_2D, tex[0]);
|
||||||
gl::ctx.TexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, in_width, in_height);
|
gl::ctx.TexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, in_width, in_height);
|
||||||
@@ -764,14 +792,16 @@ std::optional<sws_t> sws_t::make(int in_width, int in_height, int out_width, int
|
|||||||
return make(in_width, in_height, out_width, out_heigth, std::move(tex));
|
return make(in_width, in_height, out_width, out_heigth, std::move(tex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void sws_t::load_ram(platf::img_t &img) {
|
void
|
||||||
|
sws_t::load_ram(platf::img_t &img) {
|
||||||
loaded_texture = tex[0];
|
loaded_texture = tex[0];
|
||||||
|
|
||||||
gl::ctx.BindTexture(GL_TEXTURE_2D, loaded_texture);
|
gl::ctx.BindTexture(GL_TEXTURE_2D, loaded_texture);
|
||||||
gl::ctx.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img.width, img.height, GL_BGRA, GL_UNSIGNED_BYTE, img.data);
|
gl::ctx.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img.width, img.height, GL_BGRA, GL_UNSIGNED_BYTE, img.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sws_t::load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture) {
|
void
|
||||||
|
sws_t::load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture) {
|
||||||
// When only a sub-part of the image must be encoded...
|
// When only a sub-part of the image must be encoded...
|
||||||
const bool copy = offset_x || offset_y || img.sd.width != in_width || img.sd.height != in_height;
|
const bool copy = offset_x || offset_y || img.sd.width != in_width || img.sd.height != in_height;
|
||||||
if (copy) {
|
if (copy) {
|
||||||
@@ -831,7 +861,8 @@ void sws_t::load_vram(img_descriptor_t &img, int offset_x, int offset_y, int tex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sws_t::convert(gl::frame_buf_t &fb) {
|
int
|
||||||
|
sws_t::convert(gl::frame_buf_t &fb) {
|
||||||
gl::ctx.BindTexture(GL_TEXTURE_2D, loaded_texture);
|
gl::ctx.BindTexture(GL_TEXTURE_2D, loaded_texture);
|
||||||
|
|
||||||
GLenum attachments[] {
|
GLenum attachments[] {
|
||||||
@@ -864,6 +895,7 @@ int sws_t::convert(gl::frame_buf_t &fb) {
|
|||||||
}
|
}
|
||||||
} // namespace egl
|
} // namespace egl
|
||||||
|
|
||||||
void free_frame(AVFrame *frame) {
|
void
|
||||||
|
free_frame(AVFrame *frame) {
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,30 +17,35 @@
|
|||||||
#define gl_drain_errors_helper(x) gl::drain_errors(x)
|
#define gl_drain_errors_helper(x) gl::drain_errors(x)
|
||||||
#define gl_drain_errors gl_drain_errors_helper(__FILE__ ":" SUNSHINE_STRINGIFY(__LINE__))
|
#define gl_drain_errors gl_drain_errors_helper(__FILE__ ":" SUNSHINE_STRINGIFY(__LINE__))
|
||||||
|
|
||||||
extern "C" int close(int __fd);
|
extern "C" int
|
||||||
|
close(int __fd);
|
||||||
|
|
||||||
// X11 Display
|
// X11 Display
|
||||||
extern "C" struct _XDisplay;
|
extern "C" struct _XDisplay;
|
||||||
|
|
||||||
struct AVFrame;
|
struct AVFrame;
|
||||||
void free_frame(AVFrame *frame);
|
void
|
||||||
|
free_frame(AVFrame *frame);
|
||||||
|
|
||||||
using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
extern GladGLContext ctx;
|
extern GladGLContext ctx;
|
||||||
void drain_errors(const std::string_view &prefix);
|
void
|
||||||
|
drain_errors(const std::string_view &prefix);
|
||||||
|
|
||||||
class tex_t: public util::buffer_t<GLuint> {
|
class tex_t: public util::buffer_t<GLuint> {
|
||||||
using util::buffer_t<GLuint>::buffer_t;
|
using util::buffer_t<GLuint>::buffer_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tex_t(tex_t &&) = default;
|
tex_t(tex_t &&) = default;
|
||||||
tex_t &operator=(tex_t &&) = default;
|
tex_t &
|
||||||
|
operator=(tex_t &&) = default;
|
||||||
|
|
||||||
~tex_t();
|
~tex_t();
|
||||||
|
|
||||||
static tex_t make(std::size_t count);
|
static tex_t
|
||||||
|
make(std::size_t count);
|
||||||
};
|
};
|
||||||
|
|
||||||
class frame_buf_t: public util::buffer_t<GLuint> {
|
class frame_buf_t: public util::buffer_t<GLuint> {
|
||||||
@@ -48,13 +53,16 @@ class frame_buf_t : public util::buffer_t<GLuint> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
frame_buf_t(frame_buf_t &&) = default;
|
frame_buf_t(frame_buf_t &&) = default;
|
||||||
frame_buf_t &operator=(frame_buf_t &&) = default;
|
frame_buf_t &
|
||||||
|
operator=(frame_buf_t &&) = default;
|
||||||
|
|
||||||
~frame_buf_t();
|
~frame_buf_t();
|
||||||
|
|
||||||
static frame_buf_t make(std::size_t count);
|
static frame_buf_t
|
||||||
|
make(std::size_t count);
|
||||||
|
|
||||||
inline void bind(std::nullptr_t, std::nullptr_t) {
|
inline void
|
||||||
|
bind(std::nullptr_t, std::nullptr_t) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for (auto fb : (*this)) {
|
for (auto fb : (*this)) {
|
||||||
ctx.BindFramebuffer(GL_FRAMEBUFFER, fb);
|
ctx.BindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||||
@@ -66,7 +74,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class It>
|
template <class It>
|
||||||
void bind(It it_begin, It it_end) {
|
void
|
||||||
|
bind(It it_begin, It it_end) {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
if (std::distance(it_begin, it_end) > size()) {
|
if (std::distance(it_begin, it_end) > size()) {
|
||||||
BOOST_LOG(warning) << "To many elements to bind"sv;
|
BOOST_LOG(warning) << "To many elements to bind"sv;
|
||||||
@@ -87,7 +96,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Copies a part of the framebuffer to texture
|
* Copies a part of the framebuffer to texture
|
||||||
*/
|
*/
|
||||||
void copy(int id, int texture, int offset_x, int offset_y, int width, int height);
|
void
|
||||||
|
copy(int id, int texture, int offset_x, int offset_y, int width, int height);
|
||||||
};
|
};
|
||||||
|
|
||||||
class shader_t {
|
class shader_t {
|
||||||
@@ -98,11 +108,14 @@ class shader_t {
|
|||||||
});
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string err_str();
|
std::string
|
||||||
|
err_str();
|
||||||
|
|
||||||
static util::Either<shader_t, std::string> compile(const std::string_view &source, GLenum type);
|
static util::Either<shader_t, std::string>
|
||||||
|
compile(const std::string_view &source, GLenum type);
|
||||||
|
|
||||||
GLuint handle() const;
|
GLuint
|
||||||
|
handle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shader_internal_t _shader;
|
shader_internal_t _shader;
|
||||||
@@ -116,14 +129,19 @@ class buffer_t {
|
|||||||
});
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static buffer_t make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data);
|
static buffer_t
|
||||||
|
make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data);
|
||||||
|
|
||||||
GLuint handle() const;
|
GLuint
|
||||||
|
handle() const;
|
||||||
|
|
||||||
const char *block() const;
|
const char *
|
||||||
|
block() const;
|
||||||
|
|
||||||
void update(const std::string_view &view, std::size_t offset = 0);
|
void
|
||||||
void update(std::string_view *members, std::size_t count, std::size_t offset = 0);
|
update(const std::string_view &view, std::size_t offset = 0);
|
||||||
|
void
|
||||||
|
update(std::string_view *members, std::size_t count, std::size_t offset = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *_block;
|
const char *_block;
|
||||||
@@ -143,15 +161,20 @@ class program_t {
|
|||||||
});
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string err_str();
|
std::string
|
||||||
|
err_str();
|
||||||
|
|
||||||
static util::Either<program_t, std::string> link(const shader_t &vert, const shader_t &frag);
|
static util::Either<program_t, std::string>
|
||||||
|
link(const shader_t &vert, const shader_t &frag);
|
||||||
|
|
||||||
void bind(const buffer_t &buffer);
|
void
|
||||||
|
bind(const buffer_t &buffer);
|
||||||
|
|
||||||
std::optional<buffer_t> uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count);
|
std::optional<buffer_t>
|
||||||
|
uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count);
|
||||||
|
|
||||||
GLuint handle() const;
|
GLuint
|
||||||
|
handle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
program_internal_t _program;
|
program_internal_t _program;
|
||||||
@@ -168,7 +191,8 @@ extern create_device_fn create_device;
|
|||||||
|
|
||||||
using gbm_t = util::dyn_safe_ptr<device, &device_destroy>;
|
using gbm_t = util::dyn_safe_ptr<device, &device_destroy>;
|
||||||
|
|
||||||
int init();
|
int
|
||||||
|
init();
|
||||||
|
|
||||||
} // namespace gbm
|
} // namespace gbm
|
||||||
|
|
||||||
@@ -230,14 +254,18 @@ struct surface_descriptor_t {
|
|||||||
std::uint32_t offsets[4];
|
std::uint32_t offsets[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display);
|
display_t
|
||||||
std::optional<ctx_t> make_ctx(display_t::pointer display);
|
make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display);
|
||||||
|
std::optional<ctx_t>
|
||||||
|
make_ctx(display_t::pointer display);
|
||||||
|
|
||||||
std::optional<rgb_t> import_source(
|
std::optional<rgb_t>
|
||||||
|
import_source(
|
||||||
display_t::pointer egl_display,
|
display_t::pointer egl_display,
|
||||||
const surface_descriptor_t &xrgb);
|
const surface_descriptor_t &xrgb);
|
||||||
|
|
||||||
std::optional<nv12_t> import_target(
|
std::optional<nv12_t>
|
||||||
|
import_target(
|
||||||
display_t::pointer egl_display,
|
display_t::pointer egl_display,
|
||||||
std::array<file_t, nv12_img_t::num_fds> &&fds,
|
std::array<file_t, nv12_img_t::num_fds> &&fds,
|
||||||
const surface_descriptor_t &r8, const surface_descriptor_t &gr88);
|
const surface_descriptor_t &r8, const surface_descriptor_t &gr88);
|
||||||
@@ -258,7 +286,8 @@ public:
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void
|
||||||
|
reset() {
|
||||||
for (auto x = 0; x < 4; ++x) {
|
for (auto x = 0; x < 4; ++x) {
|
||||||
if (sd.fds[x] >= 0) {
|
if (sd.fds[x] >= 0) {
|
||||||
close(sd.fds[x]);
|
close(sd.fds[x]);
|
||||||
@@ -276,19 +305,26 @@ public:
|
|||||||
|
|
||||||
class sws_t {
|
class sws_t {
|
||||||
public:
|
public:
|
||||||
static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_heigth, gl::tex_t &&tex);
|
static std::optional<sws_t>
|
||||||
static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_heigth);
|
make(int in_width, int in_height, int out_width, int out_heigth, gl::tex_t &&tex);
|
||||||
|
static std::optional<sws_t>
|
||||||
|
make(int in_width, int in_height, int out_width, int out_heigth);
|
||||||
|
|
||||||
// Convert the loaded image into the first two framebuffers
|
// Convert the loaded image into the first two framebuffers
|
||||||
int convert(gl::frame_buf_t &fb);
|
int
|
||||||
|
convert(gl::frame_buf_t &fb);
|
||||||
|
|
||||||
// Make an area of the image black
|
// Make an area of the image black
|
||||||
int blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int height);
|
int
|
||||||
|
blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int height);
|
||||||
|
|
||||||
void load_ram(platf::img_t &img);
|
void
|
||||||
void load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture);
|
load_ram(platf::img_t &img);
|
||||||
|
void
|
||||||
|
load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture);
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
||||||
|
|
||||||
// The first texture is the monitor image.
|
// The first texture is the monitor image.
|
||||||
// The second texture is the cursor image
|
// The second texture is the cursor image
|
||||||
@@ -313,7 +349,8 @@ public:
|
|||||||
std::uint64_t serial;
|
std::uint64_t serial;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool fail();
|
bool
|
||||||
|
fail();
|
||||||
} // namespace egl
|
} // namespace egl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ _FN(FakeRelativeMotionEvent, int, (Display * dpy, int deltaX, int deltaY, unsign
|
|||||||
_FN(FakeButtonEvent, int, (Display * dpy, unsigned int button, Bool is_press, unsigned long delay));
|
_FN(FakeButtonEvent, int, (Display * dpy, unsigned int button, Bool is_press, unsigned long delay));
|
||||||
_FN(FakeKeyEvent, int, (Display * dpy, unsigned int keycode, Bool is_press, unsigned long delay));
|
_FN(FakeKeyEvent, int, (Display * dpy, unsigned int keycode, Bool is_press, unsigned long delay));
|
||||||
|
|
||||||
static int init() {
|
static int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -83,7 +84,8 @@ static int init() {
|
|||||||
}
|
}
|
||||||
} // namespace tst
|
} // namespace tst
|
||||||
|
|
||||||
static int init() {
|
static int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -144,7 +146,8 @@ constexpr auto UNKNOWN = 0;
|
|||||||
* @brief Initializes the keycode constants for translating
|
* @brief Initializes the keycode constants for translating
|
||||||
* moonlight keycodes to linux/X11 keycodes
|
* moonlight keycodes to linux/X11 keycodes
|
||||||
*/
|
*/
|
||||||
static constexpr std::array<keycode_t, 0xE3> init_keycodes() {
|
static constexpr std::array<keycode_t, 0xE3>
|
||||||
|
init_keycodes() {
|
||||||
std::array<keycode_t, 0xE3> keycodes {};
|
std::array<keycode_t, 0xE3> keycodes {};
|
||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
@@ -301,28 +304,32 @@ constexpr touch_port_t target_touch_port {
|
|||||||
19200, 12000
|
19200, 12000
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::pair<std::uint32_t, std::uint32_t> operator*(const std::pair<std::uint32_t, std::uint32_t> &l, int r) {
|
static std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
operator*(const std::pair<std::uint32_t, std::uint32_t> &l, int r) {
|
||||||
return {
|
return {
|
||||||
l.first * r,
|
l.first * r,
|
||||||
l.second * r,
|
l.second * r,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<std::uint32_t, std::uint32_t> operator/(const std::pair<std::uint32_t, std::uint32_t> &l, int r) {
|
static std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
operator/(const std::pair<std::uint32_t, std::uint32_t> &l, int r) {
|
||||||
return {
|
return {
|
||||||
l.first / r,
|
l.first / r,
|
||||||
l.second / r,
|
l.second / r,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<std::uint32_t, std::uint32_t> &operator+=(std::pair<std::uint32_t, std::uint32_t> &l, const std::pair<std::uint32_t, std::uint32_t> &r) {
|
static std::pair<std::uint32_t, std::uint32_t> &
|
||||||
|
operator+=(std::pair<std::uint32_t, std::uint32_t> &l, const std::pair<std::uint32_t, std::uint32_t> &r) {
|
||||||
l.first += r.first;
|
l.first += r.first;
|
||||||
l.second += r.second;
|
l.second += r.second;
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void print(const ff_envelope &envelope) {
|
static inline void
|
||||||
|
print(const ff_envelope &envelope) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "Envelope:"sv << std::endl
|
<< "Envelope:"sv << std::endl
|
||||||
<< " attack_length: " << envelope.attack_length << std::endl
|
<< " attack_length: " << envelope.attack_length << std::endl
|
||||||
@@ -331,21 +338,24 @@ static inline void print(const ff_envelope &envelope) {
|
|||||||
<< " fade_level: " << envelope.fade_level;
|
<< " fade_level: " << envelope.fade_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void print(const ff_replay &replay) {
|
static inline void
|
||||||
|
print(const ff_replay &replay) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "Replay:"sv << std::endl
|
<< "Replay:"sv << std::endl
|
||||||
<< " length: "sv << replay.length << std::endl
|
<< " length: "sv << replay.length << std::endl
|
||||||
<< " delay: "sv << replay.delay;
|
<< " delay: "sv << replay.delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void print(const ff_trigger &trigger) {
|
static inline void
|
||||||
|
print(const ff_trigger &trigger) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "Trigger:"sv << std::endl
|
<< "Trigger:"sv << std::endl
|
||||||
<< " button: "sv << trigger.button << std::endl
|
<< " button: "sv << trigger.button << std::endl
|
||||||
<< " interval: "sv << trigger.interval;
|
<< " interval: "sv << trigger.interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void print(const ff_effect &effect) {
|
static inline void
|
||||||
|
print(const ff_effect &effect) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< std::endl
|
<< std::endl
|
||||||
<< std::endl
|
<< std::endl
|
||||||
@@ -392,7 +402,6 @@ static inline void print(const ff_effect &effect) {
|
|||||||
<< " weak_magnitude: " << effect.u.rumble.weak_magnitude;
|
<< " weak_magnitude: " << effect.u.rumble.weak_magnitude;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case FF_SPRING:
|
case FF_SPRING:
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "FF_SPRING:" << std::endl
|
<< "FF_SPRING:" << std::endl
|
||||||
@@ -439,21 +448,20 @@ class effect_t {
|
|||||||
public:
|
public:
|
||||||
KITTY_DEFAULT_CONSTR_MOVE(effect_t)
|
KITTY_DEFAULT_CONSTR_MOVE(effect_t)
|
||||||
|
|
||||||
effect_t(int gamepadnr, uinput_t::pointer dev, rumble_queue_t &&q)
|
effect_t(int gamepadnr, uinput_t::pointer dev, rumble_queue_t &&q):
|
||||||
: gamepadnr { gamepadnr }, dev { dev }, rumble_queue { std::move(q) }, gain { 0xFFFF }, id_to_data {} {}
|
gamepadnr { gamepadnr }, dev { dev }, rumble_queue { std::move(q) }, gain { 0xFFFF }, id_to_data {} {}
|
||||||
|
|
||||||
class data_t {
|
class data_t {
|
||||||
public:
|
public:
|
||||||
KITTY_DEFAULT_CONSTR(data_t)
|
KITTY_DEFAULT_CONSTR(data_t)
|
||||||
|
|
||||||
data_t(const ff_effect &effect)
|
data_t(const ff_effect &effect):
|
||||||
: delay { effect.replay.delay },
|
delay { effect.replay.delay },
|
||||||
length { effect.replay.length },
|
length { effect.replay.length },
|
||||||
end_point { std::chrono::steady_clock::time_point::min() },
|
end_point { std::chrono::steady_clock::time_point::min() },
|
||||||
envelope {},
|
envelope {},
|
||||||
start {},
|
start {},
|
||||||
end {} {
|
end {} {
|
||||||
|
|
||||||
switch (effect.type) {
|
switch (effect.type) {
|
||||||
case FF_CONSTANT:
|
case FF_CONSTANT:
|
||||||
start.weak = effect.u.constant.level;
|
start.weak = effect.u.constant.level;
|
||||||
@@ -493,13 +501,15 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t magnitude(std::chrono::milliseconds time_left, std::uint32_t start, std::uint32_t end) {
|
std::uint32_t
|
||||||
|
magnitude(std::chrono::milliseconds time_left, std::uint32_t start, std::uint32_t end) {
|
||||||
auto rel = end - start;
|
auto rel = end - start;
|
||||||
|
|
||||||
return start + (rel * time_left.count() / length.count());
|
return start + (rel * time_left.count() / length.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::uint32_t, std::uint32_t> rumble(std::chrono::steady_clock::time_point tp) {
|
std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
rumble(std::chrono::steady_clock::time_point tp) {
|
||||||
if (end_point < tp) {
|
if (end_point < tp) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -534,11 +544,13 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void activate() {
|
void
|
||||||
|
activate() {
|
||||||
end_point = std::chrono::steady_clock::now() + delay + length;
|
end_point = std::chrono::steady_clock::now() + delay + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivate() {
|
void
|
||||||
|
deactivate() {
|
||||||
end_point = std::chrono::steady_clock::time_point::min();
|
end_point = std::chrono::steady_clock::time_point::min();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +569,8 @@ public:
|
|||||||
} end;
|
} end;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::pair<std::uint32_t, std::uint32_t> rumble(std::chrono::steady_clock::time_point tp) {
|
std::pair<std::uint32_t, std::uint32_t>
|
||||||
|
rumble(std::chrono::steady_clock::time_point tp) {
|
||||||
std::pair<std::uint32_t, std::uint32_t> weak_strong {};
|
std::pair<std::uint32_t, std::uint32_t> weak_strong {};
|
||||||
for (auto &[_, data] : id_to_data) {
|
for (auto &[_, data] : id_to_data) {
|
||||||
weak_strong += data.rumble(tp);
|
weak_strong += data.rumble(tp);
|
||||||
@@ -570,7 +583,8 @@ public:
|
|||||||
return old_rumble;
|
return old_rumble;
|
||||||
}
|
}
|
||||||
|
|
||||||
void upload(const ff_effect &effect) {
|
void
|
||||||
|
upload(const ff_effect &effect) {
|
||||||
print(effect);
|
print(effect);
|
||||||
|
|
||||||
auto it = id_to_data.find(effect.id);
|
auto it = id_to_data.find(effect.id);
|
||||||
@@ -586,7 +600,8 @@ public:
|
|||||||
it->second = data;
|
it->second = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void activate(int id) {
|
void
|
||||||
|
activate(int id) {
|
||||||
auto it = id_to_data.find(id);
|
auto it = id_to_data.find(id);
|
||||||
|
|
||||||
if (it != std::end(id_to_data)) {
|
if (it != std::end(id_to_data)) {
|
||||||
@@ -594,7 +609,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivate(int id) {
|
void
|
||||||
|
deactivate(int id) {
|
||||||
auto it = id_to_data.find(id);
|
auto it = id_to_data.find(id);
|
||||||
|
|
||||||
if (it != std::end(id_to_data)) {
|
if (it != std::end(id_to_data)) {
|
||||||
@@ -602,7 +618,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(int id) {
|
void
|
||||||
|
erase(int id) {
|
||||||
id_to_data.erase(id);
|
id_to_data.erase(id);
|
||||||
BOOST_LOG(debug) << "Removed rumble effect id ["sv << id << ']';
|
BOOST_LOG(debug) << "Removed rumble effect id ["sv << id << ']';
|
||||||
}
|
}
|
||||||
@@ -629,14 +646,17 @@ struct rumble_ctx_t {
|
|||||||
safe::queue_t<mail_evdev_t> rumble_queue_queue;
|
safe::queue_t<mail_evdev_t> rumble_queue_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
void broadcastRumble(safe::queue_t<mail_evdev_t> &ctx);
|
void
|
||||||
int startRumble(rumble_ctx_t &ctx) {
|
broadcastRumble(safe::queue_t<mail_evdev_t> &ctx);
|
||||||
|
int
|
||||||
|
startRumble(rumble_ctx_t &ctx) {
|
||||||
ctx.rumble_thread = std::thread { broadcastRumble, std::ref(ctx.rumble_queue_queue) };
|
ctx.rumble_thread = std::thread { broadcastRumble, std::ref(ctx.rumble_queue_queue) };
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopRumble(rumble_ctx_t &ctx) {
|
void
|
||||||
|
stopRumble(rumble_ctx_t &ctx) {
|
||||||
ctx.rumble_queue_queue.stop();
|
ctx.rumble_queue_queue.stop();
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Waiting for Gamepad notifications to stop..."sv;
|
BOOST_LOG(debug) << "Waiting for Gamepad notifications to stop..."sv;
|
||||||
@@ -648,7 +668,8 @@ static auto notifications = safe::make_shared<rumble_ctx_t>(startRumble, stopRum
|
|||||||
|
|
||||||
struct input_raw_t {
|
struct input_raw_t {
|
||||||
public:
|
public:
|
||||||
void clear_touchscreen() {
|
void
|
||||||
|
clear_touchscreen() {
|
||||||
std::filesystem::path touch_path { appdata() / "sunshine_touchscreen"sv };
|
std::filesystem::path touch_path { appdata() / "sunshine_touchscreen"sv };
|
||||||
|
|
||||||
if (std::filesystem::is_symlink(touch_path)) {
|
if (std::filesystem::is_symlink(touch_path)) {
|
||||||
@@ -658,7 +679,8 @@ public:
|
|||||||
touch_input.reset();
|
touch_input.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_keyboard() {
|
void
|
||||||
|
clear_keyboard() {
|
||||||
std::filesystem::path key_path { appdata() / "sunshine_keyboard"sv };
|
std::filesystem::path key_path { appdata() / "sunshine_keyboard"sv };
|
||||||
|
|
||||||
if (std::filesystem::is_symlink(key_path)) {
|
if (std::filesystem::is_symlink(key_path)) {
|
||||||
@@ -668,7 +690,8 @@ public:
|
|||||||
keyboard_input.reset();
|
keyboard_input.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_mouse() {
|
void
|
||||||
|
clear_mouse() {
|
||||||
std::filesystem::path mouse_path { appdata() / "sunshine_mouse"sv };
|
std::filesystem::path mouse_path { appdata() / "sunshine_mouse"sv };
|
||||||
|
|
||||||
if (std::filesystem::is_symlink(mouse_path)) {
|
if (std::filesystem::is_symlink(mouse_path)) {
|
||||||
@@ -678,7 +701,8 @@ public:
|
|||||||
mouse_input.reset();
|
mouse_input.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_gamepad(int nr) {
|
void
|
||||||
|
clear_gamepad(int nr) {
|
||||||
auto &[dev, _] = gamepads[nr];
|
auto &[dev, _] = gamepads[nr];
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
@@ -700,7 +724,8 @@ public:
|
|||||||
gamepads[nr] = std::make_pair(uinput_t {}, gamepad_state_t {});
|
gamepads[nr] = std::make_pair(uinput_t {}, gamepad_state_t {});
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_mouse() {
|
int
|
||||||
|
create_mouse() {
|
||||||
int err = libevdev_uinput_create_from_device(mouse_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &mouse_input);
|
int err = libevdev_uinput_create_from_device(mouse_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &mouse_input);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -713,7 +738,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_touchscreen() {
|
int
|
||||||
|
create_touchscreen() {
|
||||||
int err = libevdev_uinput_create_from_device(touch_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &touch_input);
|
int err = libevdev_uinput_create_from_device(touch_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &touch_input);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -726,7 +752,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_keyboard() {
|
int
|
||||||
|
create_keyboard() {
|
||||||
int err = libevdev_uinput_create_from_device(keyboard_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &keyboard_input);
|
int err = libevdev_uinput_create_from_device(keyboard_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &keyboard_input);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -739,7 +766,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad(int nr, rumble_queue_t &&rumble_queue) {
|
int
|
||||||
|
alloc_gamepad(int nr, rumble_queue_t &&rumble_queue) {
|
||||||
TUPLE_2D_REF(input, gamepad_state, gamepads[nr]);
|
TUPLE_2D_REF(input, gamepad_state, gamepads[nr]);
|
||||||
|
|
||||||
int err = libevdev_uinput_create_from_device(gamepad_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &input);
|
int err = libevdev_uinput_create_from_device(gamepad_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &input);
|
||||||
@@ -775,7 +803,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void
|
||||||
|
clear() {
|
||||||
clear_touchscreen();
|
clear_touchscreen();
|
||||||
clear_keyboard();
|
clear_keyboard();
|
||||||
clear_mouse();
|
clear_mouse();
|
||||||
@@ -812,7 +841,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void rumbleIterate(std::vector<effect_t> &effects, std::vector<pollfd_t> &polls, std::chrono::milliseconds to) {
|
inline void
|
||||||
|
rumbleIterate(std::vector<effect_t> &effects, std::vector<pollfd_t> &polls, std::chrono::milliseconds to) {
|
||||||
std::vector<pollfd> polls_recv;
|
std::vector<pollfd> polls_recv;
|
||||||
polls_recv.reserve(polls.size());
|
polls_recv.reserve(polls.size());
|
||||||
for (auto &poll : polls) {
|
for (auto &poll : polls) {
|
||||||
@@ -947,7 +977,8 @@ inline void rumbleIterate(std::vector<effect_t> &effects, std::vector<pollfd_t>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void broadcastRumble(safe::queue_t<mail_evdev_t> &rumble_queue_queue) {
|
void
|
||||||
|
broadcastRumble(safe::queue_t<mail_evdev_t> &rumble_queue_queue) {
|
||||||
std::vector<effect_t> effects;
|
std::vector<effect_t> effects;
|
||||||
std::vector<pollfd_t> polls;
|
std::vector<pollfd_t> polls;
|
||||||
|
|
||||||
@@ -971,7 +1002,6 @@ void broadcastRumble(safe::queue_t<mail_evdev_t> &rumble_queue_queue) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (effect_it != std::end(effects)) {
|
if (effect_it != std::end(effects)) {
|
||||||
|
|
||||||
auto poll_it = std::begin(polls) + (effect_it - std::begin(effects));
|
auto poll_it = std::begin(polls) + (effect_it - std::begin(effects));
|
||||||
|
|
||||||
polls.erase(poll_it);
|
polls.erase(poll_it);
|
||||||
@@ -1027,7 +1057,8 @@ void broadcastRumble(safe::queue_t<mail_evdev_t> &rumble_queue_queue) {
|
|||||||
* x_abs_mouse(input, 0, 0);
|
* x_abs_mouse(input, 0, 0);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static void x_abs_mouse(input_t &input, float x, float y) {
|
static void
|
||||||
|
x_abs_mouse(input_t &input, float x, float y) {
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||||
if (!xdisplay) {
|
if (!xdisplay) {
|
||||||
@@ -1050,7 +1081,8 @@ static void x_abs_mouse(input_t &input, float x, float y) {
|
|||||||
* abs_mouse(input, touch_port, 0, 0);
|
* abs_mouse(input, touch_port, 0, 0);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
void
|
||||||
|
abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
||||||
auto touchscreen = ((input_raw_t *) input.get())->touch_input.get();
|
auto touchscreen = ((input_raw_t *) input.get())->touch_input.get();
|
||||||
if (!touchscreen) {
|
if (!touchscreen) {
|
||||||
x_abs_mouse(input, x, y);
|
x_abs_mouse(input, x, y);
|
||||||
@@ -1079,7 +1111,8 @@ void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y)
|
|||||||
* x_move_mouse(input, 10, 10); // Move mouse 10 pixels down and right
|
* x_move_mouse(input, 10, 10); // Move mouse 10 pixels down and right
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static void x_move_mouse(input_t &input, int deltaX, int deltaY) {
|
static void
|
||||||
|
x_move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||||
if (!xdisplay) {
|
if (!xdisplay) {
|
||||||
@@ -1101,7 +1134,8 @@ static void x_move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
* move_mouse(input, 10, 10); // Move mouse 10 pixels down and right
|
* move_mouse(input, 10, 10); // Move mouse 10 pixels down and right
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void move_mouse(input_t &input, int deltaX, int deltaY) {
|
void
|
||||||
|
move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||||
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
||||||
if (!mouse) {
|
if (!mouse) {
|
||||||
x_move_mouse(input, deltaX, deltaY);
|
x_move_mouse(input, deltaX, deltaY);
|
||||||
@@ -1130,7 +1164,8 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
* x_button_mouse(input, 1, false); // Press left mouse button
|
* x_button_mouse(input, 1, false); // Press left mouse button
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static void x_button_mouse(input_t &input, int button, bool release) {
|
static void
|
||||||
|
x_button_mouse(input_t &input, int button, bool release) {
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
unsigned int x_button = 0;
|
unsigned int x_button = 0;
|
||||||
switch (button) {
|
switch (button) {
|
||||||
@@ -1172,7 +1207,8 @@ static void x_button_mouse(input_t &input, int button, bool release) {
|
|||||||
* button_mouse(input, 1, false); // Press left mouse button
|
* button_mouse(input, 1, false); // Press left mouse button
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void button_mouse(input_t &input, int button, bool release) {
|
void
|
||||||
|
button_mouse(input_t &input, int button, bool release) {
|
||||||
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
||||||
if (!mouse) {
|
if (!mouse) {
|
||||||
x_button_mouse(input, button, release);
|
x_button_mouse(input, button, release);
|
||||||
@@ -1220,7 +1256,8 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||||||
* x_scroll(input, 10, 4, 5);
|
* x_scroll(input, 10, 4, 5);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static void x_scroll(input_t &input, int distance, int button_pos, int button_neg) {
|
static void
|
||||||
|
x_scroll(input_t &input, int distance, int button_pos, int button_neg) {
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||||
if (!xdisplay) {
|
if (!xdisplay) {
|
||||||
@@ -1246,7 +1283,8 @@ static void x_scroll(input_t &input, int distance, int button_pos, int button_ne
|
|||||||
* scroll(input, 1200);
|
* scroll(input, 1200);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void scroll(input_t &input, int high_res_distance) {
|
void
|
||||||
|
scroll(input_t &input, int high_res_distance) {
|
||||||
int distance = high_res_distance / 120;
|
int distance = high_res_distance / 120;
|
||||||
|
|
||||||
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
||||||
@@ -1270,7 +1308,8 @@ void scroll(input_t &input, int high_res_distance) {
|
|||||||
* hscroll(input, 1200);
|
* hscroll(input, 1200);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void hscroll(input_t &input, int high_res_distance) {
|
void
|
||||||
|
hscroll(input_t &input, int high_res_distance) {
|
||||||
int distance = high_res_distance / 120;
|
int distance = high_res_distance / 120;
|
||||||
|
|
||||||
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
auto mouse = ((input_raw_t *) input.get())->mouse_input.get();
|
||||||
@@ -1284,7 +1323,8 @@ void hscroll(input_t &input, int high_res_distance) {
|
|||||||
libevdev_uinput_write_event(mouse, EV_SYN, SYN_REPORT, 0);
|
libevdev_uinput_write_event(mouse, EV_SYN, SYN_REPORT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static keycode_t keysym(std::uint16_t modcode) {
|
static keycode_t
|
||||||
|
keysym(std::uint16_t modcode) {
|
||||||
if (modcode <= keycodes.size()) {
|
if (modcode <= keycodes.size()) {
|
||||||
return keycodes[modcode];
|
return keycodes[modcode];
|
||||||
}
|
}
|
||||||
@@ -1303,7 +1343,8 @@ static keycode_t keysym(std::uint16_t modcode) {
|
|||||||
* x_keyboard(input, 0x5A, false); // Press Z
|
* x_keyboard(input, 0x5A, false); // Press Z
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
static void x_keyboard(input_t &input, uint16_t modcode, bool release) {
|
static void
|
||||||
|
x_keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
auto keycode = keysym(modcode);
|
auto keycode = keysym(modcode);
|
||||||
if (keycode.keysym == UNKNOWN) {
|
if (keycode.keysym == UNKNOWN) {
|
||||||
@@ -1336,7 +1377,8 @@ static void x_keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
* keyboard(input, 0x5A, false); // Press Z
|
* keyboard(input, 0x5A, false); // Press Z
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
void keyboard(input_t &input, uint16_t modcode, bool release) {
|
void
|
||||||
|
keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||||
auto keyboard = ((input_raw_t *) input.get())->keyboard_input.get();
|
auto keyboard = ((input_raw_t *) input.get())->keyboard_input.get();
|
||||||
if (!keyboard) {
|
if (!keyboard) {
|
||||||
x_keyboard(input, modcode, release);
|
x_keyboard(input, modcode, release);
|
||||||
@@ -1356,7 +1398,8 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
libevdev_uinput_write_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
libevdev_uinput_write_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard_ev(libevdev_uinput *keyboard, int linux_code, int event_code = 1) {
|
void
|
||||||
|
keyboard_ev(libevdev_uinput *keyboard, int linux_code, int event_code = 1) {
|
||||||
libevdev_uinput_write_event(keyboard, EV_KEY, linux_code, event_code);
|
libevdev_uinput_write_event(keyboard, EV_KEY, linux_code, event_code);
|
||||||
libevdev_uinput_write_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
libevdev_uinput_write_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||||
}
|
}
|
||||||
@@ -1368,7 +1411,8 @@ void keyboard_ev(libevdev_uinput *keyboard, int linux_code, int event_code = 1)
|
|||||||
*
|
*
|
||||||
* adapted from: https://stackoverflow.com/a/7639754
|
* adapted from: https://stackoverflow.com/a/7639754
|
||||||
*/
|
*/
|
||||||
std::string to_hex(const std::basic_string<char32_t> &str) {
|
std::string
|
||||||
|
to_hex(const std::basic_string<char32_t> &str) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::hex << std::setfill('0');
|
ss << std::hex << std::setfill('0');
|
||||||
for (const auto &ch : str) {
|
for (const auto &ch : str) {
|
||||||
@@ -1391,7 +1435,8 @@ std::string to_hex(const std::basic_string<char32_t> &str) {
|
|||||||
* - then type: CTRL+SHIFT+U+1F471
|
* - then type: CTRL+SHIFT+U+1F471
|
||||||
* see the conversion at: https://www.compart.com/en/unicode/U+1F471
|
* see the conversion at: https://www.compart.com/en/unicode/U+1F471
|
||||||
*/
|
*/
|
||||||
void unicode(input_t &input, char *utf8, int size) {
|
void
|
||||||
|
unicode(input_t &input, char *utf8, int size) {
|
||||||
auto kb = ((input_raw_t *) input.get())->keyboard_input.get();
|
auto kb = ((input_raw_t *) input.get())->keyboard_input.get();
|
||||||
if (!kb) {
|
if (!kb) {
|
||||||
return;
|
return;
|
||||||
@@ -1429,18 +1474,20 @@ void unicode(input_t &input, char *utf8, int size) {
|
|||||||
keyboard_ev(kb, KEY_LEFTCTRL, 0);
|
keyboard_ev(kb, KEY_LEFTCTRL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
int
|
||||||
|
alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
||||||
return ((input_raw_t *) input.get())->alloc_gamepad(nr, std::move(rumble_queue));
|
return ((input_raw_t *) input.get())->alloc_gamepad(nr, std::move(rumble_queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_gamepad(input_t &input, int nr) {
|
void
|
||||||
|
free_gamepad(input_t &input, int nr) {
|
||||||
((input_raw_t *) input.get())->clear_gamepad(nr);
|
((input_raw_t *) input.get())->clear_gamepad(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
void
|
||||||
|
gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||||
TUPLE_2D_REF(uinput, gamepad_state_old, ((input_raw_t *) input.get())->gamepads[nr]);
|
TUPLE_2D_REF(uinput, gamepad_state_old, ((input_raw_t *) input.get())->gamepads[nr]);
|
||||||
|
|
||||||
|
|
||||||
auto bf = gamepad_state.buttonFlags ^ gamepad_state_old.buttonFlags;
|
auto bf = gamepad_state.buttonFlags ^ gamepad_state_old.buttonFlags;
|
||||||
auto bf_new = gamepad_state.buttonFlags;
|
auto bf_new = gamepad_state.buttonFlags;
|
||||||
|
|
||||||
@@ -1507,7 +1554,8 @@ void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
|||||||
* auto my_keyboard = keyboard();
|
* auto my_keyboard = keyboard();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
evdev_t keyboard() {
|
evdev_t
|
||||||
|
keyboard() {
|
||||||
evdev_t dev { libevdev_new() };
|
evdev_t dev { libevdev_new() };
|
||||||
|
|
||||||
libevdev_set_uniq(dev.get(), "Sunshine Keyboard");
|
libevdev_set_uniq(dev.get(), "Sunshine Keyboard");
|
||||||
@@ -1535,7 +1583,8 @@ evdev_t keyboard() {
|
|||||||
* auto my_mouse = mouse();
|
* auto my_mouse = mouse();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
evdev_t mouse() {
|
evdev_t
|
||||||
|
mouse() {
|
||||||
evdev_t dev { libevdev_new() };
|
evdev_t dev { libevdev_new() };
|
||||||
|
|
||||||
libevdev_set_uniq(dev.get(), "Sunshine Mouse");
|
libevdev_set_uniq(dev.get(), "Sunshine Mouse");
|
||||||
@@ -1585,7 +1634,8 @@ evdev_t mouse() {
|
|||||||
* auto my_touchscreen = touchscreen();
|
* auto my_touchscreen = touchscreen();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
evdev_t touchscreen() {
|
evdev_t
|
||||||
|
touchscreen() {
|
||||||
evdev_t dev { libevdev_new() };
|
evdev_t dev { libevdev_new() };
|
||||||
|
|
||||||
libevdev_set_uniq(dev.get(), "Sunshine Touch");
|
libevdev_set_uniq(dev.get(), "Sunshine Touch");
|
||||||
@@ -1597,7 +1647,6 @@ evdev_t touchscreen() {
|
|||||||
|
|
||||||
libevdev_enable_property(dev.get(), INPUT_PROP_DIRECT);
|
libevdev_enable_property(dev.get(), INPUT_PROP_DIRECT);
|
||||||
|
|
||||||
|
|
||||||
libevdev_enable_event_type(dev.get(), EV_KEY);
|
libevdev_enable_event_type(dev.get(), EV_KEY);
|
||||||
libevdev_enable_event_code(dev.get(), EV_KEY, BTN_TOUCH, nullptr);
|
libevdev_enable_event_code(dev.get(), EV_KEY, BTN_TOUCH, nullptr);
|
||||||
libevdev_enable_event_code(dev.get(), EV_KEY, BTN_TOOL_PEN, nullptr); // Needed to be enabled for BTN_TOOL_FINGER to work.
|
libevdev_enable_event_code(dev.get(), EV_KEY, BTN_TOOL_PEN, nullptr); // Needed to be enabled for BTN_TOOL_FINGER to work.
|
||||||
@@ -1635,7 +1684,8 @@ evdev_t touchscreen() {
|
|||||||
* auto my_x360 = x360();
|
* auto my_x360 = x360();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
evdev_t x360() {
|
evdev_t
|
||||||
|
x360() {
|
||||||
evdev_t dev { libevdev_new() };
|
evdev_t dev { libevdev_new() };
|
||||||
|
|
||||||
input_absinfo stick {
|
input_absinfo stick {
|
||||||
@@ -1711,7 +1761,8 @@ evdev_t x360() {
|
|||||||
* auto my_input = input();
|
* auto my_input = input();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
input_t input() {
|
input_t
|
||||||
|
input() {
|
||||||
input_t result { new input_raw_t() };
|
input_t result { new input_raw_t() };
|
||||||
auto &gp = *(input_raw_t *) result.get();
|
auto &gp = *(input_raw_t *) result.get();
|
||||||
|
|
||||||
@@ -1749,12 +1800,14 @@ input_t input() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeInput(void *p) {
|
void
|
||||||
|
freeInput(void *p) {
|
||||||
auto *input = (input_raw_t *) p;
|
auto *input = (input_raw_t *) p;
|
||||||
delete input;
|
delete input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string_view> &supported_gamepads() {
|
std::vector<std::string_view> &
|
||||||
|
supported_gamepads() {
|
||||||
static std::vector<std::string_view> gamepads { "x360"sv };
|
static std::vector<std::string_view> gamepads { "x360"sv };
|
||||||
|
|
||||||
return gamepads;
|
return gamepads;
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ public:
|
|||||||
|
|
||||||
class wrapper_fb {
|
class wrapper_fb {
|
||||||
public:
|
public:
|
||||||
wrapper_fb(drmModeFB *fb)
|
wrapper_fb(drmModeFB *fb):
|
||||||
: fb { fb }, fb_id { fb->fb_id }, width { fb->width }, height { fb->height } {
|
fb { fb }, fb_id { fb->fb_id }, width { fb->width }, height { fb->height } {
|
||||||
pixel_format = DRM_FORMAT_XRGB8888;
|
pixel_format = DRM_FORMAT_XRGB8888;
|
||||||
modifier = DRM_FORMAT_MOD_INVALID;
|
modifier = DRM_FORMAT_MOD_INVALID;
|
||||||
std::fill_n(handles, 4, 0);
|
std::fill_n(handles, 4, 0);
|
||||||
@@ -62,8 +62,8 @@ public:
|
|||||||
pitches[0] = fb->pitch;
|
pitches[0] = fb->pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper_fb(drmModeFB2 *fb2)
|
wrapper_fb(drmModeFB2 *fb2):
|
||||||
: fb2 { fb2 }, fb_id { fb2->fb_id }, width { fb2->width }, height { fb2->height } {
|
fb2 { fb2 }, fb_id { fb2->fb_id }, width { fb2->width }, height { fb2->height } {
|
||||||
pixel_format = fb2->pixel_format;
|
pixel_format = fb2->pixel_format;
|
||||||
modifier = (fb2->flags & DRM_MODE_FB_MODIFIERS) ? fb2->modifier : DRM_FORMAT_MOD_INVALID;
|
modifier = (fb2->flags & DRM_MODE_FB_MODIFIERS) ? fb2->modifier : DRM_FORMAT_MOD_INVALID;
|
||||||
|
|
||||||
@@ -107,7 +107,8 @@ using conn_type_count_t = std::map<std::uint32_t, std::uint32_t>;
|
|||||||
static int env_width;
|
static int env_width;
|
||||||
static int env_height;
|
static int env_height;
|
||||||
|
|
||||||
std::string_view plane_type(std::uint64_t val) {
|
std::string_view
|
||||||
|
plane_type(std::uint64_t val) {
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case DRM_PLANE_TYPE_OVERLAY:
|
case DRM_PLANE_TYPE_OVERLAY:
|
||||||
return "DRM_PLANE_TYPE_OVERLAY"sv;
|
return "DRM_PLANE_TYPE_OVERLAY"sv;
|
||||||
@@ -149,7 +150,8 @@ struct card_descriptor_t {
|
|||||||
|
|
||||||
static std::vector<card_descriptor_t> card_descriptors;
|
static std::vector<card_descriptor_t> card_descriptors;
|
||||||
|
|
||||||
static std::uint32_t from_view(const std::string_view &string) {
|
static std::uint32_t
|
||||||
|
from_view(const std::string_view &string) {
|
||||||
#define _CONVERT(x, y) \
|
#define _CONVERT(x, y) \
|
||||||
if (string == x) return DRM_MODE_CONNECTOR_##y
|
if (string == x) return DRM_MODE_CONNECTOR_##y
|
||||||
|
|
||||||
@@ -174,15 +176,16 @@ static std::uint32_t from_view(const std::string_view &string) {
|
|||||||
|
|
||||||
class plane_it_t: public round_robin_util::it_wrap_t<plane_t::element_type, plane_it_t> {
|
class plane_it_t: public round_robin_util::it_wrap_t<plane_t::element_type, plane_it_t> {
|
||||||
public:
|
public:
|
||||||
plane_it_t(int fd, std::uint32_t *plane_p, std::uint32_t *end)
|
plane_it_t(int fd, std::uint32_t *plane_p, std::uint32_t *end):
|
||||||
: fd { fd }, plane_p { plane_p }, end { end } {
|
fd { fd }, plane_p { plane_p }, end { end } {
|
||||||
inc();
|
inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_it_t(int fd, std::uint32_t *end)
|
plane_it_t(int fd, std::uint32_t *end):
|
||||||
: fd { fd }, plane_p { end }, end { end } {}
|
fd { fd }, plane_p { end }, end { end } {}
|
||||||
|
|
||||||
void inc() {
|
void
|
||||||
|
inc() {
|
||||||
this->plane.reset();
|
this->plane.reset();
|
||||||
|
|
||||||
for (; plane_p != end; ++plane_p) {
|
for (; plane_p != end; ++plane_p) {
|
||||||
@@ -204,11 +207,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool eq(const plane_it_t &other) const {
|
bool
|
||||||
|
eq(const plane_it_t &other) const {
|
||||||
return plane_p == other.plane_p;
|
return plane_p == other.plane_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_t::pointer get() {
|
plane_t::pointer
|
||||||
|
get() {
|
||||||
return plane.get();
|
return plane.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +228,8 @@ class card_t {
|
|||||||
public:
|
public:
|
||||||
using connector_interal_t = util::safe_ptr<drmModeConnector, drmModeFreeConnector>;
|
using connector_interal_t = util::safe_ptr<drmModeConnector, drmModeFreeConnector>;
|
||||||
|
|
||||||
int init(const char *path) {
|
int
|
||||||
|
init(const char *path) {
|
||||||
cap_sys_admin admin;
|
cap_sys_admin admin;
|
||||||
fd.el = open(path, O_RDWR);
|
fd.el = open(path, O_RDWR);
|
||||||
|
|
||||||
@@ -250,7 +256,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fb_t fb(plane_t::pointer plane) {
|
fb_t
|
||||||
|
fb(plane_t::pointer plane) {
|
||||||
cap_sys_admin admin;
|
cap_sys_admin admin;
|
||||||
|
|
||||||
auto fb2 = drmModeGetFB2(fd.el, plane->fb_id);
|
auto fb2 = drmModeGetFB2(fd.el, plane->fb_id);
|
||||||
@@ -266,19 +273,23 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
crtc_t crtc(std::uint32_t id) {
|
crtc_t
|
||||||
|
crtc(std::uint32_t id) {
|
||||||
return drmModeGetCrtc(fd.el, id);
|
return drmModeGetCrtc(fd.el, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder_t encoder(std::uint32_t id) {
|
encoder_t
|
||||||
|
encoder(std::uint32_t id) {
|
||||||
return drmModeGetEncoder(fd.el, id);
|
return drmModeGetEncoder(fd.el, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
res_t res() {
|
res_t
|
||||||
|
res() {
|
||||||
return drmModeGetResources(fd.el);
|
return drmModeGetResources(fd.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_cursor(std::uint32_t plane_id) {
|
bool
|
||||||
|
is_cursor(std::uint32_t plane_id) {
|
||||||
auto props = plane_props(plane_id);
|
auto props = plane_props(plane_id);
|
||||||
for (auto &[prop, val] : props) {
|
for (auto &[prop, val] : props) {
|
||||||
if (prop->name == "type"sv) {
|
if (prop->name == "type"sv) {
|
||||||
@@ -294,7 +305,8 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t get_panel_orientation(std::uint32_t plane_id) {
|
std::uint32_t
|
||||||
|
get_panel_orientation(std::uint32_t plane_id) {
|
||||||
auto props = plane_props(plane_id);
|
auto props = plane_props(plane_id);
|
||||||
for (auto &[prop, val] : props) {
|
for (auto &[prop, val] : props) {
|
||||||
if (prop->name == "rotation"sv) {
|
if (prop->name == "rotation"sv) {
|
||||||
@@ -306,11 +318,13 @@ public:
|
|||||||
return DRM_MODE_ROTATE_0;
|
return DRM_MODE_ROTATE_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connector_interal_t connector(std::uint32_t id) {
|
connector_interal_t
|
||||||
|
connector(std::uint32_t id) {
|
||||||
return drmModeGetConnector(fd.el, id);
|
return drmModeGetConnector(fd.el, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<connector_t> monitors(conn_type_count_t &conn_type_count) {
|
std::vector<connector_t>
|
||||||
|
monitors(conn_type_count_t &conn_type_count) {
|
||||||
auto resources = res();
|
auto resources = res();
|
||||||
if (!resources) {
|
if (!resources) {
|
||||||
BOOST_LOG(error) << "Couldn't get connector resources"sv;
|
BOOST_LOG(error) << "Couldn't get connector resources"sv;
|
||||||
@@ -343,7 +357,8 @@ public:
|
|||||||
return monitors;
|
return monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t handleFD(std::uint32_t handle) {
|
file_t
|
||||||
|
handleFD(std::uint32_t handle) {
|
||||||
file_t fb_fd;
|
file_t fb_fd;
|
||||||
|
|
||||||
auto status = drmPrimeHandleToFD(fd.el, handle, 0 /* flags */, &fb_fd.el);
|
auto status = drmPrimeHandleToFD(fd.el, handle, 0 /* flags */, &fb_fd.el);
|
||||||
@@ -354,7 +369,8 @@ public:
|
|||||||
return fb_fd;
|
return fb_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<prop_t, std::uint64_t>> props(std::uint32_t id, std::uint32_t type) {
|
std::vector<std::pair<prop_t, std::uint64_t>>
|
||||||
|
props(std::uint32_t id, std::uint32_t type) {
|
||||||
obj_prop_t obj_prop = drmModeObjectGetProperties(fd.el, id, type);
|
obj_prop_t obj_prop = drmModeObjectGetProperties(fd.el, id, type);
|
||||||
|
|
||||||
std::vector<std::pair<prop_t, std::uint64_t>> props;
|
std::vector<std::pair<prop_t, std::uint64_t>> props;
|
||||||
@@ -367,40 +383,47 @@ public:
|
|||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<prop_t, std::uint64_t>> plane_props(std::uint32_t id) {
|
std::vector<std::pair<prop_t, std::uint64_t>>
|
||||||
|
plane_props(std::uint32_t id) {
|
||||||
return props(id, DRM_MODE_OBJECT_PLANE);
|
return props(id, DRM_MODE_OBJECT_PLANE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<prop_t, std::uint64_t>> crtc_props(std::uint32_t id) {
|
std::vector<std::pair<prop_t, std::uint64_t>>
|
||||||
|
crtc_props(std::uint32_t id) {
|
||||||
return props(id, DRM_MODE_OBJECT_CRTC);
|
return props(id, DRM_MODE_OBJECT_CRTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<prop_t, std::uint64_t>> connector_props(std::uint32_t id) {
|
std::vector<std::pair<prop_t, std::uint64_t>>
|
||||||
|
connector_props(std::uint32_t id) {
|
||||||
return props(id, DRM_MODE_OBJECT_CONNECTOR);
|
return props(id, DRM_MODE_OBJECT_CONNECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_t operator[](std::uint32_t index) {
|
plane_t
|
||||||
|
operator[](std::uint32_t index) {
|
||||||
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t count() {
|
std::uint32_t
|
||||||
|
count() {
|
||||||
return plane_res->count_planes;
|
return plane_res->count_planes;
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_it_t begin() const {
|
plane_it_t
|
||||||
|
begin() const {
|
||||||
return plane_it_t { fd.el, plane_res->planes, plane_res->planes + plane_res->count_planes };
|
return plane_it_t { fd.el, plane_res->planes, plane_res->planes + plane_res->count_planes };
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_it_t end() const {
|
plane_it_t
|
||||||
|
end() const {
|
||||||
return plane_it_t { fd.el, plane_res->planes + plane_res->count_planes };
|
return plane_it_t { fd.el, plane_res->planes + plane_res->count_planes };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
file_t fd;
|
file_t fd;
|
||||||
plane_res_t plane_res;
|
plane_res_t plane_res;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::uint32_t, monitor_t> map_crtc_to_monitor(const std::vector<connector_t> &connectors) {
|
std::map<std::uint32_t, monitor_t>
|
||||||
|
map_crtc_to_monitor(const std::vector<connector_t> &connectors) {
|
||||||
std::map<std::uint32_t, monitor_t> result;
|
std::map<std::uint32_t, monitor_t> result;
|
||||||
|
|
||||||
for (auto &connector : connectors) {
|
for (auto &connector : connectors) {
|
||||||
@@ -421,7 +444,8 @@ struct kms_img_t : public img_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void print(plane_t::pointer plane, fb_t::pointer fb, crtc_t::pointer crtc) {
|
void
|
||||||
|
print(plane_t::pointer plane, fb_t::pointer fb, crtc_t::pointer crtc) {
|
||||||
if (crtc) {
|
if (crtc) {
|
||||||
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
|
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
|
||||||
BOOST_LOG(debug) << "crtc("sv << crtc->width << ", "sv << crtc->height << ')';
|
BOOST_LOG(debug) << "crtc("sv << crtc->width << ", "sv << crtc->height << ')';
|
||||||
@@ -455,9 +479,11 @@ void print(plane_t::pointer plane, fb_t::pointer fb, crtc_t::pointer crtc) {
|
|||||||
|
|
||||||
class display_t: public platf::display_t {
|
class display_t: public platf::display_t {
|
||||||
public:
|
public:
|
||||||
display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {}
|
display_t(mem_type_e mem_type):
|
||||||
|
platf::display_t(), mem_type { mem_type } {}
|
||||||
|
|
||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
delay = std::chrono::nanoseconds { 1s } / config.framerate;
|
delay = std::chrono::nanoseconds { 1s } / config.framerate;
|
||||||
|
|
||||||
int monitor_index = util::from_view(display_name);
|
int monitor_index = util::from_view(display_name);
|
||||||
@@ -593,7 +619,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline capture_e refresh(file_t *file, egl::surface_descriptor_t *sd) {
|
inline capture_e
|
||||||
|
refresh(file_t *file, egl::surface_descriptor_t *sd) {
|
||||||
plane_t plane = drmModeGetPlane(card.fd.el, plane_id);
|
plane_t plane = drmModeGetPlane(card.fd.el, plane_id);
|
||||||
|
|
||||||
auto fb = card.fb(plane.get());
|
auto fb = card.fb(plane.get());
|
||||||
@@ -660,9 +687,11 @@ public:
|
|||||||
|
|
||||||
class display_ram_t: public display_t {
|
class display_ram_t: public display_t {
|
||||||
public:
|
public:
|
||||||
display_ram_t(mem_type_e mem_type) : display_t(mem_type) {}
|
display_ram_t(mem_type_e mem_type):
|
||||||
|
display_t(mem_type) {}
|
||||||
|
|
||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (!gbm::create_device) {
|
if (!gbm::create_device) {
|
||||||
BOOST_LOG(warning) << "libgbm not initialized"sv;
|
BOOST_LOG(warning) << "libgbm not initialized"sv;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -693,7 +722,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -728,7 +758,8 @@ public:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
std::shared_ptr<hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||||
if (mem_type == mem_type_e::vaapi) {
|
if (mem_type == mem_type_e::vaapi) {
|
||||||
return va::make_hwdevice(width, height, false);
|
return va::make_hwdevice(width, height, false);
|
||||||
}
|
}
|
||||||
@@ -736,7 +767,8 @@ public:
|
|||||||
return std::make_shared<hwdevice_t>();
|
return std::make_shared<hwdevice_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
capture_e
|
||||||
|
snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
file_t fb_fd[4];
|
file_t fb_fd[4];
|
||||||
|
|
||||||
egl::surface_descriptor_t sd;
|
egl::surface_descriptor_t sd;
|
||||||
@@ -770,7 +802,8 @@ public:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<kms_img_t>();
|
auto img = std::make_shared<kms_img_t>();
|
||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
@@ -781,7 +814,8 @@ public:
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int
|
||||||
|
dummy_img(platf::img_t *img) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,9 +826,11 @@ public:
|
|||||||
|
|
||||||
class display_vram_t: public display_t {
|
class display_vram_t: public display_t {
|
||||||
public:
|
public:
|
||||||
display_vram_t(mem_type_e mem_type) : display_t(mem_type) {}
|
display_vram_t(mem_type_e mem_type):
|
||||||
|
display_t(mem_type) {}
|
||||||
|
|
||||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
std::shared_ptr<hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||||
if (mem_type == mem_type_e::vaapi) {
|
if (mem_type == mem_type_e::vaapi) {
|
||||||
return va::make_hwdevice(width, height, dup(card.fd.el), img_offset_x, img_offset_y, true);
|
return va::make_hwdevice(width, height, dup(card.fd.el), img_offset_x, img_offset_y, true);
|
||||||
}
|
}
|
||||||
@@ -803,7 +839,8 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<egl::img_descriptor_t>();
|
auto img = std::make_shared<egl::img_descriptor_t>();
|
||||||
|
|
||||||
img->serial = std::numeric_limits<decltype(img->serial)>::max();
|
img->serial = std::numeric_limits<decltype(img->serial)>::max();
|
||||||
@@ -816,11 +853,13 @@ public:
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int
|
||||||
|
dummy_img(platf::img_t *img) override {
|
||||||
return snapshot(img, 1s, false) != capture_e::ok;
|
return snapshot(img, 1s, false) != capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) {
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -855,7 +894,8 @@ public:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds /* timeout */, bool cursor) {
|
capture_e
|
||||||
|
snapshot(img_t *img_out_base, std::chrono::milliseconds /* timeout */, bool cursor) {
|
||||||
file_t fb_fd[4];
|
file_t fb_fd[4];
|
||||||
|
|
||||||
auto img = (egl::img_descriptor_t *) img_out_base;
|
auto img = (egl::img_descriptor_t *) img_out_base;
|
||||||
@@ -888,7 +928,8 @@ public:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (display_t::init(display_name, config)) {
|
if (display_t::init(display_name, config)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -908,7 +949,8 @@ public:
|
|||||||
|
|
||||||
} // namespace kms
|
} // namespace kms
|
||||||
|
|
||||||
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
kms_display(mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (hwdevice_type == mem_type_e::vaapi) {
|
if (hwdevice_type == mem_type_e::vaapi) {
|
||||||
auto disp = std::make_shared<kms::display_vram_t>(hwdevice_type);
|
auto disp = std::make_shared<kms::display_vram_t>(hwdevice_type);
|
||||||
|
|
||||||
@@ -928,7 +970,6 @@ std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::stri
|
|||||||
return disp;
|
return disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Wayland, it's not possible to determine the position of the monitor on the desktop with KMS.
|
* On Wayland, it's not possible to determine the position of the monitor on the desktop with KMS.
|
||||||
* Wayland does allow applications to query attached monitors on the desktop,
|
* Wayland does allow applications to query attached monitors on the desktop,
|
||||||
@@ -939,7 +980,8 @@ std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::stri
|
|||||||
*
|
*
|
||||||
* This is an ugly hack :(
|
* This is an ugly hack :(
|
||||||
*/
|
*/
|
||||||
void correlate_to_wayland(std::vector<kms::card_descriptor_t> &cds) {
|
void
|
||||||
|
correlate_to_wayland(std::vector<kms::card_descriptor_t> &cds) {
|
||||||
auto monitors = wl::monitors();
|
auto monitors = wl::monitors();
|
||||||
|
|
||||||
for (auto &monitor : monitors) {
|
for (auto &monitor : monitors) {
|
||||||
@@ -990,7 +1032,8 @@ void correlate_to_wayland(std::vector<kms::card_descriptor_t> &cds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A list of names of displays accepted as display_name
|
// A list of names of displays accepted as display_name
|
||||||
std::vector<std::string> kms_display_names() {
|
std::vector<std::string>
|
||||||
|
kms_display_names() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (!fs::exists("/dev/dri")) {
|
if (!fs::exists("/dev/dri")) {
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ namespace bp = boost::process;
|
|||||||
window_system_e window_system;
|
window_system_e window_system;
|
||||||
|
|
||||||
namespace dyn {
|
namespace dyn {
|
||||||
void *handle(const std::vector<const char *> &libs) {
|
void *
|
||||||
|
handle(const std::vector<const char *> &libs) {
|
||||||
void *handle;
|
void *handle;
|
||||||
|
|
||||||
for (auto lib : libs) {
|
for (auto lib : libs) {
|
||||||
@@ -60,7 +61,8 @@ void *handle(const std::vector<const char *> &libs) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
int
|
||||||
|
load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
for (auto &func : funcs) {
|
for (auto &func : funcs) {
|
||||||
TUPLE_2D_REF(fn, name, func);
|
TUPLE_2D_REF(fn, name, func);
|
||||||
@@ -80,7 +82,8 @@ int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &f
|
|||||||
namespace platf {
|
namespace platf {
|
||||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||||
|
|
||||||
ifaddr_t get_ifaddrs() {
|
ifaddr_t
|
||||||
|
get_ifaddrs() {
|
||||||
ifaddrs *p { nullptr };
|
ifaddrs *p { nullptr };
|
||||||
|
|
||||||
getifaddrs(&p);
|
getifaddrs(&p);
|
||||||
@@ -88,7 +91,8 @@ ifaddr_t get_ifaddrs() {
|
|||||||
return ifaddr_t { p };
|
return ifaddr_t { p };
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path appdata() {
|
fs::path
|
||||||
|
appdata() {
|
||||||
const char *homedir;
|
const char *homedir;
|
||||||
if ((homedir = getenv("HOME")) == nullptr) {
|
if ((homedir = getenv("HOME")) == nullptr) {
|
||||||
homedir = getpwuid(geteuid())->pw_dir;
|
homedir = getpwuid(geteuid())->pw_dir;
|
||||||
@@ -97,7 +101,8 @@ fs::path appdata() {
|
|||||||
return fs::path { homedir } / ".config/sunshine"sv;
|
return fs::path { homedir } / ".config/sunshine"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string from_sockaddr(const sockaddr *const ip_addr) {
|
std::string
|
||||||
|
from_sockaddr(const sockaddr *const ip_addr) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
@@ -114,7 +119,8 @@ std::string from_sockaddr(const sockaddr *const ip_addr) {
|
|||||||
return std::string { data };
|
return std::string { data };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
|
std::pair<std::uint16_t, std::string>
|
||||||
|
from_sockaddr_ex(const sockaddr *const ip_addr) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
@@ -134,7 +140,8 @@ std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_
|
|||||||
return { port, std::string { data } };
|
return { port, std::string { data } };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mac_address(const std::string_view &address) {
|
std::string
|
||||||
|
get_mac_address(const std::string_view &address) {
|
||||||
auto ifaddrs = get_ifaddrs();
|
auto ifaddrs = get_ifaddrs();
|
||||||
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
||||||
if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
|
if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
|
||||||
@@ -151,7 +158,8 @@ std::string get_mac_address(const std::string_view &address) {
|
|||||||
return "00:00:00:00:00:00"s;
|
return "00:00:00:00:00:00"s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
bp::child
|
||||||
|
run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
||||||
BOOST_LOG(warning) << "run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions."sv;
|
BOOST_LOG(warning) << "run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions."sv;
|
||||||
if (!group) {
|
if (!group) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@@ -171,29 +179,35 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjust_thread_priority(thread_priority_e priority) {
|
void
|
||||||
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_start() {
|
void
|
||||||
|
streaming_will_start() {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_stop() {
|
void
|
||||||
|
streaming_will_stop() {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart_supported() {
|
bool
|
||||||
|
restart_supported() {
|
||||||
// Restart not supported yet
|
// Restart not supported yet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart() {
|
bool
|
||||||
|
restart() {
|
||||||
// Restart not supported yet
|
// Restart not supported yet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool send_batch(batched_send_info_t &send_info) {
|
bool
|
||||||
|
send_batch(batched_send_info_t &send_info) {
|
||||||
auto sockfd = (int) send_info.native_socket;
|
auto sockfd = (int) send_info.native_socket;
|
||||||
|
|
||||||
// Convert the target address into a sockaddr
|
// Convert the target address into a sockaddr
|
||||||
@@ -349,7 +363,8 @@ bool send_batch(batched_send_info_t &send_info) {
|
|||||||
|
|
||||||
class qos_t: public deinit_t {
|
class qos_t: public deinit_t {
|
||||||
public:
|
public:
|
||||||
qos_t(int sockfd, int level, int option) : sockfd(sockfd), level(level), option(option) {}
|
qos_t(int sockfd, int level, int option):
|
||||||
|
sockfd(sockfd), level(level), option(option) {}
|
||||||
|
|
||||||
virtual ~qos_t() {
|
virtual ~qos_t() {
|
||||||
int reset_val = -1;
|
int reset_val = -1;
|
||||||
@@ -364,7 +379,8 @@ private:
|
|||||||
int option;
|
int option;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
std::unique_ptr<deinit_t>
|
||||||
|
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
||||||
int sockfd = (int) native_socket;
|
int sockfd = (int) native_socket;
|
||||||
|
|
||||||
int level;
|
int level;
|
||||||
@@ -423,42 +439,55 @@ enum source_e : std::size_t {
|
|||||||
static std::bitset<source::MAX_FLAGS> sources;
|
static std::bitset<source::MAX_FLAGS> sources;
|
||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_CUDA
|
#ifdef SUNSHINE_BUILD_CUDA
|
||||||
std::vector<std::string> nvfbc_display_names();
|
std::vector<std::string>
|
||||||
std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
nvfbc_display_names();
|
||||||
|
std::shared_ptr<display_t>
|
||||||
|
nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
||||||
|
|
||||||
bool verify_nvfbc() {
|
bool
|
||||||
|
verify_nvfbc() {
|
||||||
return !nvfbc_display_names().empty();
|
return !nvfbc_display_names().empty();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_WAYLAND
|
#ifdef SUNSHINE_BUILD_WAYLAND
|
||||||
std::vector<std::string> wl_display_names();
|
std::vector<std::string>
|
||||||
std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
wl_display_names();
|
||||||
|
std::shared_ptr<display_t>
|
||||||
|
wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
||||||
|
|
||||||
bool verify_wl() {
|
bool
|
||||||
|
verify_wl() {
|
||||||
return window_system == window_system_e::WAYLAND && !wl_display_names().empty();
|
return window_system == window_system_e::WAYLAND && !wl_display_names().empty();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_DRM
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
std::vector<std::string> kms_display_names();
|
std::vector<std::string>
|
||||||
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
kms_display_names();
|
||||||
|
std::shared_ptr<display_t>
|
||||||
|
kms_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
||||||
|
|
||||||
bool verify_kms() {
|
bool
|
||||||
|
verify_kms() {
|
||||||
return !kms_display_names().empty();
|
return !kms_display_names().empty();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
std::vector<std::string> x11_display_names();
|
std::vector<std::string>
|
||||||
std::shared_ptr<display_t> x11_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
x11_display_names();
|
||||||
|
std::shared_ptr<display_t>
|
||||||
|
x11_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
|
||||||
|
|
||||||
bool verify_x11() {
|
bool
|
||||||
|
verify_x11() {
|
||||||
return window_system == window_system_e::X11 && !x11_display_names().empty();
|
return window_system == window_system_e::X11 && !x11_display_names().empty();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::string> display_names(mem_type_e hwdevice_type) {
|
std::vector<std::string>
|
||||||
|
display_names(mem_type_e hwdevice_type) {
|
||||||
#ifdef SUNSHINE_BUILD_CUDA
|
#ifdef SUNSHINE_BUILD_CUDA
|
||||||
// display using NvFBC only supports mem_type_e::cuda
|
// display using NvFBC only supports mem_type_e::cuda
|
||||||
if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) return nvfbc_display_names();
|
if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) return nvfbc_display_names();
|
||||||
@@ -475,7 +504,8 @@ std::vector<std::string> display_names(mem_type_e hwdevice_type) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||||
#ifdef SUNSHINE_BUILD_CUDA
|
#ifdef SUNSHINE_BUILD_CUDA
|
||||||
if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) {
|
if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) {
|
||||||
BOOST_LOG(info) << "Screencasting with NvFBC"sv;
|
BOOST_LOG(info) << "Screencasting with NvFBC"sv;
|
||||||
@@ -504,7 +534,8 @@ std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> init() {
|
std::unique_ptr<deinit_t>
|
||||||
|
init() {
|
||||||
// These are allowed to fail.
|
// These are allowed to fail.
|
||||||
gbm::init();
|
gbm::init();
|
||||||
va::init();
|
va::init();
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ extern window_system_e window_system;
|
|||||||
namespace dyn {
|
namespace dyn {
|
||||||
typedef void (*apiproc)(void);
|
typedef void (*apiproc)(void);
|
||||||
|
|
||||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
int
|
||||||
void *handle(const std::vector<const char *> &libs);
|
load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
||||||
|
void *
|
||||||
|
handle(const std::vector<const char *> &libs);
|
||||||
|
|
||||||
} // namespace dyn
|
} // namespace dyn
|
||||||
|
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ simple_poll_quit_fn simple_poll_quit;
|
|||||||
simple_poll_new_fn simple_poll_new;
|
simple_poll_new_fn simple_poll_new;
|
||||||
simple_poll_free_fn simple_poll_free;
|
simple_poll_free_fn simple_poll_free;
|
||||||
|
|
||||||
|
int
|
||||||
int init_common() {
|
init_common() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -229,7 +229,8 @@ int init_common() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_client() {
|
int
|
||||||
|
init_client() {
|
||||||
if (init_common()) {
|
if (init_common()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -270,7 +271,8 @@ int init_client() {
|
|||||||
namespace platf::publish {
|
namespace platf::publish {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void free(T *p) {
|
void
|
||||||
|
free(T *p) {
|
||||||
avahi::free(p);
|
avahi::free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +288,11 @@ client_t client;
|
|||||||
|
|
||||||
ptr_t<char> name;
|
ptr_t<char> name;
|
||||||
|
|
||||||
void create_services(avahi::Client *c);
|
void
|
||||||
|
create_services(avahi::Client *c);
|
||||||
|
|
||||||
void entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, void *) {
|
void
|
||||||
|
entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, void *) {
|
||||||
group = g;
|
group = g;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -311,7 +315,8 @@ void entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_services(avahi::Client *c) {
|
void
|
||||||
|
create_services(avahi::Client *c) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
auto fg = util::fail_guard([]() {
|
auto fg = util::fail_guard([]() {
|
||||||
@@ -366,7 +371,8 @@ void create_services(avahi::Client *c) {
|
|||||||
fg.disable();
|
fg.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
void
|
||||||
|
client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case avahi::CLIENT_S_RUNNING:
|
case avahi::CLIENT_S_RUNNING:
|
||||||
create_services(c);
|
create_services(c);
|
||||||
@@ -388,7 +394,8 @@ class deinit_t : public ::platf::deinit_t {
|
|||||||
public:
|
public:
|
||||||
std::thread poll_thread;
|
std::thread poll_thread;
|
||||||
|
|
||||||
deinit_t(std::thread poll_thread) : poll_thread { std::move(poll_thread) } {}
|
deinit_t(std::thread poll_thread):
|
||||||
|
poll_thread { std::move(poll_thread) } {}
|
||||||
|
|
||||||
~deinit_t() override {
|
~deinit_t() override {
|
||||||
if (avahi::simple_poll_quit && poll) {
|
if (avahi::simple_poll_quit && poll) {
|
||||||
@@ -401,7 +408,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<::platf::deinit_t> start() {
|
[[nodiscard]] std::unique_ptr<::platf::deinit_t>
|
||||||
|
start() {
|
||||||
if (avahi::init_client()) {
|
if (avahi::init_client()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ extern "C" {
|
|||||||
#if !VA_CHECK_VERSION(1, 9, 0)
|
#if !VA_CHECK_VERSION(1, 9, 0)
|
||||||
/* vaSyncBuffer stub allows Sunshine built against libva <2.9.0
|
/* vaSyncBuffer stub allows Sunshine built against libva <2.9.0
|
||||||
to link against ffmpeg on libva 2.9.0 or later */
|
to link against ffmpeg on libva 2.9.0 or later */
|
||||||
VAStatus vaSyncBuffer(
|
VAStatus
|
||||||
|
vaSyncBuffer(
|
||||||
VADisplay dpy,
|
VADisplay dpy,
|
||||||
VABufferID buf_id,
|
VABufferID buf_id,
|
||||||
uint64_t timeout_ns) {
|
uint64_t timeout_ns) {
|
||||||
@@ -193,7 +194,6 @@ enum class entry_e {
|
|||||||
ProtectedContent = 14,
|
ProtectedContent = 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef VAStatus (*queryConfigEntrypoints_fn)(VADisplay dpy, profile_e profile, entry_e *entrypoint_list, int *num_entrypoints);
|
typedef VAStatus (*queryConfigEntrypoints_fn)(VADisplay dpy, profile_e profile, entry_e *entrypoint_list, int *num_entrypoints);
|
||||||
typedef int (*maxNumEntrypoints_fn)(VADisplay dpy);
|
typedef int (*maxNumEntrypoints_fn)(VADisplay dpy);
|
||||||
typedef VADisplay (*getDisplayDRM_fn)(int fd);
|
typedef VADisplay (*getDisplayDRM_fn)(int fd);
|
||||||
@@ -222,7 +222,8 @@ static exportSurfaceHandle_fn exportSurfaceHandle;
|
|||||||
|
|
||||||
using display_t = util::dyn_safe_ptr_v2<void, VAStatus, &terminate>;
|
using display_t = util::dyn_safe_ptr_v2<void, VAStatus, &terminate>;
|
||||||
|
|
||||||
int init_main_va() {
|
int
|
||||||
|
init_main_va() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -255,7 +256,8 @@ int init_main_va() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
if (init_main_va()) {
|
if (init_main_va()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -284,11 +286,13 @@ int init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf);
|
int
|
||||||
|
vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf);
|
||||||
|
|
||||||
class va_t: public platf::hwdevice_t {
|
class va_t: public platf::hwdevice_t {
|
||||||
public:
|
public:
|
||||||
int init(int in_width, int in_height, file_t &&render_device) {
|
int
|
||||||
|
init(int in_width, int in_height, file_t &&render_device) {
|
||||||
file = std::move(render_device);
|
file = std::move(render_device);
|
||||||
|
|
||||||
if (!va::initialize || !gbm::create_device) {
|
if (!va::initialize || !gbm::create_device) {
|
||||||
@@ -324,7 +328,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
||||||
this->hwframe.reset(frame);
|
this->hwframe.reset(frame);
|
||||||
this->frame = frame;
|
this->frame = frame;
|
||||||
|
|
||||||
@@ -345,7 +350,6 @@ public:
|
|||||||
va::EXPORT_SURFACE_WRITE_ONLY | va::EXPORT_SURFACE_COMPOSED_LAYERS,
|
va::EXPORT_SURFACE_WRITE_ONLY | va::EXPORT_SURFACE_COMPOSED_LAYERS,
|
||||||
&prime);
|
&prime);
|
||||||
if (status) {
|
if (status) {
|
||||||
|
|
||||||
BOOST_LOG(error) << "Couldn't export va surface handle: ["sv << (int) surface << "]: "sv << va::errorStr(status);
|
BOOST_LOG(error) << "Couldn't export va surface handle: ["sv << (int) surface << "]: "sv << va::errorStr(status);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@@ -390,7 +394,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
||||||
sws.set_colorspace(colorspace, color_range);
|
sws.set_colorspace(colorspace, color_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +418,8 @@ public:
|
|||||||
|
|
||||||
class va_ram_t: public va_t {
|
class va_ram_t: public va_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img) override {
|
int
|
||||||
|
convert(platf::img_t &img) override {
|
||||||
sws.load_ram(img);
|
sws.load_ram(img);
|
||||||
|
|
||||||
sws.convert(nv12->buf);
|
sws.convert(nv12->buf);
|
||||||
@@ -423,7 +429,8 @@ public:
|
|||||||
|
|
||||||
class va_vram_t: public va_t {
|
class va_vram_t: public va_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img) override {
|
int
|
||||||
|
convert(platf::img_t &img) override {
|
||||||
auto &descriptor = (egl::img_descriptor_t &) img;
|
auto &descriptor = (egl::img_descriptor_t &) img;
|
||||||
|
|
||||||
if (descriptor.sequence > sequence) {
|
if (descriptor.sequence > sequence) {
|
||||||
@@ -446,7 +453,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(int in_width, int in_height, file_t &&render_device, int offset_x, int offset_y) {
|
int
|
||||||
|
init(int in_width, int in_height, file_t &&render_device, int offset_x, int offset_y) {
|
||||||
if (va_t::init(in_width, in_height, std::move(render_device))) {
|
if (va_t::init(in_width, in_height, std::move(render_device))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -499,11 +507,13 @@ typedef struct AVVAAPIDeviceContext {
|
|||||||
unsigned int driver_quirks;
|
unsigned int driver_quirks;
|
||||||
} AVVAAPIDeviceContext;
|
} AVVAAPIDeviceContext;
|
||||||
|
|
||||||
static void __log(void *level, const char *msg) {
|
static void
|
||||||
|
__log(void *level, const char *msg) {
|
||||||
BOOST_LOG(*(boost::log::sources::severity_logger<int> *) level) << msg;
|
BOOST_LOG(*(boost::log::sources::severity_logger<int> *) level) << msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf) {
|
int
|
||||||
|
vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf) {
|
||||||
if (!va::initialize) {
|
if (!va::initialize) {
|
||||||
BOOST_LOG(warning) << "libva not loaded"sv;
|
BOOST_LOG(warning) << "libva not loaded"sv;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -565,7 +575,8 @@ int vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool query(display_t::pointer display, profile_e profile) {
|
static bool
|
||||||
|
query(display_t::pointer display, profile_e profile) {
|
||||||
std::vector<entry_e> entrypoints;
|
std::vector<entry_e> entrypoints;
|
||||||
entrypoints.resize(maxNumEntrypoints(display));
|
entrypoints.resize(maxNumEntrypoints(display));
|
||||||
|
|
||||||
@@ -586,7 +597,8 @@ static bool query(display_t::pointer display, profile_e profile) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate(int fd) {
|
bool
|
||||||
|
validate(int fd) {
|
||||||
if (init()) {
|
if (init()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -625,7 +637,8 @@ bool validate(int fd) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, file_t &&card, int offset_x, int offset_y, bool vram) {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, file_t &&card, int offset_x, int offset_y, bool vram) {
|
||||||
if (vram) {
|
if (vram) {
|
||||||
auto egl = std::make_shared<va::va_vram_t>();
|
auto egl = std::make_shared<va::va_vram_t>();
|
||||||
if (egl->init(width, height, std::move(card), offset_x, offset_y)) {
|
if (egl->init(width, height, std::move(card), offset_x, offset_y)) {
|
||||||
@@ -645,7 +658,8 @@ std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, file_t &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, int offset_x, int offset_y, bool vram) {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, int offset_x, int offset_y, bool vram) {
|
||||||
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();
|
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();
|
||||||
|
|
||||||
file_t file = open(render_device, O_RDWR);
|
file_t file = open(render_device, O_RDWR);
|
||||||
@@ -659,7 +673,8 @@ std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, int offs
|
|||||||
return make_hwdevice(width, height, std::move(file), offset_x, offset_y, vram);
|
return make_hwdevice(width, height, std::move(file), offset_x, offset_y, vram);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, bool vram) {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, bool vram) {
|
||||||
return make_hwdevice(width, height, 0, 0, vram);
|
return make_hwdevice(width, height, 0, 0, vram);
|
||||||
}
|
}
|
||||||
} // namespace va
|
} // namespace va
|
||||||
|
|||||||
@@ -15,13 +15,18 @@ namespace va {
|
|||||||
* offset_y --> Vertical offset of the image in the texture
|
* offset_y --> Vertical offset of the image in the texture
|
||||||
* file_t card --> The file descriptor of the render device used for encoding
|
* file_t card --> The file descriptor of the render device used for encoding
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, bool vram);
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, int offset_x, int offset_y, bool vram);
|
make_hwdevice(int width, int height, bool vram);
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, file_t &&card, int offset_x, int offset_y, bool vram);
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, int offset_x, int offset_y, bool vram);
|
||||||
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(int width, int height, file_t &&card, int offset_x, int offset_y, bool vram);
|
||||||
|
|
||||||
// Ensure the render device pointed to by fd is capable of encoding h264 with the hevc_mode configured
|
// Ensure the render device pointed to by fd is capable of encoding h264 with the hevc_mode configured
|
||||||
bool validate(int fd);
|
bool
|
||||||
|
validate(int fd);
|
||||||
|
|
||||||
int init();
|
int
|
||||||
|
init();
|
||||||
} // namespace va
|
} // namespace va
|
||||||
#endif
|
#endif
|
||||||
@@ -23,13 +23,15 @@ namespace wl {
|
|||||||
|
|
||||||
// Helper to call C++ method from wayland C callback
|
// Helper to call C++ method from wayland C callback
|
||||||
template <class T, class Method, Method m, class... Params>
|
template <class T, class Method, Method m, class... Params>
|
||||||
static auto classCall(void *data, Params... params) -> decltype(((*reinterpret_cast<T *>(data)).*m)(params...)) {
|
static auto
|
||||||
|
classCall(void *data, Params... params) -> decltype(((*reinterpret_cast<T *>(data)).*m)(params...)) {
|
||||||
return ((*reinterpret_cast<T *>(data)).*m)(params...);
|
return ((*reinterpret_cast<T *>(data)).*m)(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CLASS_CALL(c, m) classCall<c, decltype(&c::m), &c::m>
|
#define CLASS_CALL(c, m) classCall<c, decltype(&c::m), &c::m>
|
||||||
|
|
||||||
int display_t::init(const char *display_name) {
|
int
|
||||||
|
display_t::init(const char *display_name) {
|
||||||
if (!display_name) {
|
if (!display_name) {
|
||||||
display_name = std::getenv("WAYLAND_DISPLAY");
|
display_name = std::getenv("WAYLAND_DISPLAY");
|
||||||
}
|
}
|
||||||
@@ -50,16 +52,18 @@ int display_t::init(const char *display_name) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_t::roundtrip() {
|
void
|
||||||
|
display_t::roundtrip() {
|
||||||
wl_display_roundtrip(display_internal.get());
|
wl_display_roundtrip(display_internal.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_registry *display_t::registry() {
|
wl_registry *
|
||||||
|
display_t::registry() {
|
||||||
return wl_display_get_registry(display_internal.get());
|
return wl_display_get_registry(display_internal.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline monitor_t::monitor_t(wl_output *output)
|
inline monitor_t::monitor_t(wl_output *output):
|
||||||
: output { output }, listener {
|
output { output }, listener {
|
||||||
&CLASS_CALL(monitor_t, xdg_position),
|
&CLASS_CALL(monitor_t, xdg_position),
|
||||||
&CLASS_CALL(monitor_t, xdg_size),
|
&CLASS_CALL(monitor_t, xdg_size),
|
||||||
&CLASS_CALL(monitor_t, xdg_done),
|
&CLASS_CALL(monitor_t, xdg_done),
|
||||||
@@ -67,52 +71,62 @@ inline monitor_t::monitor_t(wl_output *output)
|
|||||||
&CLASS_CALL(monitor_t, xdg_description)
|
&CLASS_CALL(monitor_t, xdg_description)
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
inline void monitor_t::xdg_name(zxdg_output_v1 *, const char *name) {
|
inline void
|
||||||
|
monitor_t::xdg_name(zxdg_output_v1 *, const char *name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Name: "sv << this->name;
|
BOOST_LOG(info) << "Name: "sv << this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_t::xdg_description(zxdg_output_v1 *, const char *description) {
|
void
|
||||||
|
monitor_t::xdg_description(zxdg_output_v1 *, const char *description) {
|
||||||
this->description = description;
|
this->description = description;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Found monitor: "sv << this->description;
|
BOOST_LOG(info) << "Found monitor: "sv << this->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_t::xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y) {
|
void
|
||||||
|
monitor_t::xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y) {
|
||||||
viewport.offset_x = x;
|
viewport.offset_x = x;
|
||||||
viewport.offset_y = y;
|
viewport.offset_y = y;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Offset: "sv << x << 'x' << y;
|
BOOST_LOG(info) << "Offset: "sv << x << 'x' << y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_t::xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height) {
|
void
|
||||||
|
monitor_t::xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height) {
|
||||||
viewport.width = width;
|
viewport.width = width;
|
||||||
viewport.height = height;
|
viewport.height = height;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Resolution: "sv << width << 'x' << height;
|
BOOST_LOG(info) << "Resolution: "sv << width << 'x' << height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_t::xdg_done(zxdg_output_v1 *) {
|
void
|
||||||
|
monitor_t::xdg_done(zxdg_output_v1 *) {
|
||||||
BOOST_LOG(info) << "All info about monitor ["sv << name << "] has been send"sv;
|
BOOST_LOG(info) << "All info about monitor ["sv << name << "] has been send"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_t::listen(zxdg_output_manager_v1 *output_manager) {
|
void
|
||||||
|
monitor_t::listen(zxdg_output_manager_v1 *output_manager) {
|
||||||
auto xdg_output = zxdg_output_manager_v1_get_xdg_output(output_manager, output);
|
auto xdg_output = zxdg_output_manager_v1_get_xdg_output(output_manager, output);
|
||||||
zxdg_output_v1_add_listener(xdg_output, &listener, this);
|
zxdg_output_v1_add_listener(xdg_output, &listener, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface_t::interface_t() noexcept
|
interface_t::interface_t() noexcept
|
||||||
: output_manager { nullptr }, listener {
|
:
|
||||||
|
output_manager { nullptr },
|
||||||
|
listener {
|
||||||
&CLASS_CALL(interface_t, add_interface),
|
&CLASS_CALL(interface_t, add_interface),
|
||||||
&CLASS_CALL(interface_t, del_interface)
|
&CLASS_CALL(interface_t, del_interface)
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
void interface_t::listen(wl_registry *registry) {
|
void
|
||||||
|
interface_t::listen(wl_registry *registry) {
|
||||||
wl_registry_add_listener(registry, &listener, this);
|
wl_registry_add_listener(registry, &listener, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void interface_t::add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version) {
|
void
|
||||||
|
interface_t::add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version) {
|
||||||
BOOST_LOG(debug) << "Available interface: "sv << interface << '(' << id << ") version "sv << version;
|
BOOST_LOG(debug) << "Available interface: "sv << interface << '(' << id << ") version "sv << version;
|
||||||
|
|
||||||
if (!std::strcmp(interface, wl_output_interface.name)) {
|
if (!std::strcmp(interface, wl_output_interface.name)) {
|
||||||
@@ -135,12 +149,13 @@ void interface_t::add_interface(wl_registry *registry, std::uint32_t id, const c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interface_t::del_interface(wl_registry *registry, uint32_t id) {
|
void
|
||||||
|
interface_t::del_interface(wl_registry *registry, uint32_t id) {
|
||||||
BOOST_LOG(info) << "Delete: "sv << id;
|
BOOST_LOG(info) << "Delete: "sv << id;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmabuf_t::dmabuf_t()
|
dmabuf_t::dmabuf_t():
|
||||||
: status { READY }, frames {}, current_frame { &frames[0] }, listener {
|
status { READY }, frames {}, current_frame { &frames[0] }, listener {
|
||||||
&CLASS_CALL(dmabuf_t, frame),
|
&CLASS_CALL(dmabuf_t, frame),
|
||||||
&CLASS_CALL(dmabuf_t, object),
|
&CLASS_CALL(dmabuf_t, object),
|
||||||
&CLASS_CALL(dmabuf_t, ready),
|
&CLASS_CALL(dmabuf_t, ready),
|
||||||
@@ -148,7 +163,8 @@ dmabuf_t::dmabuf_t()
|
|||||||
} {
|
} {
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmabuf_t::listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor) {
|
void
|
||||||
|
dmabuf_t::listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor) {
|
||||||
auto frame = zwlr_export_dmabuf_manager_v1_capture_output(dmabuf_manager, blend_cursor, output);
|
auto frame = zwlr_export_dmabuf_manager_v1_capture_output(dmabuf_manager, blend_cursor, output);
|
||||||
zwlr_export_dmabuf_frame_v1_add_listener(frame, &listener, this);
|
zwlr_export_dmabuf_frame_v1_add_listener(frame, &listener, this);
|
||||||
|
|
||||||
@@ -161,7 +177,8 @@ dmabuf_t::~dmabuf_t() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmabuf_t::frame(
|
void
|
||||||
|
dmabuf_t::frame(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t width, std::uint32_t height,
|
std::uint32_t width, std::uint32_t height,
|
||||||
std::uint32_t x, std::uint32_t y,
|
std::uint32_t x, std::uint32_t y,
|
||||||
@@ -177,7 +194,8 @@ void dmabuf_t::frame(
|
|||||||
next_frame->sd.modifier = (((std::uint64_t) high) << 32) | low;
|
next_frame->sd.modifier = (((std::uint64_t) high) << 32) | low;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmabuf_t::object(
|
void
|
||||||
|
dmabuf_t::object(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t index,
|
std::uint32_t index,
|
||||||
std::int32_t fd,
|
std::int32_t fd,
|
||||||
@@ -192,10 +210,10 @@ void dmabuf_t::object(
|
|||||||
next_frame->sd.offsets[plane_index] = offset;
|
next_frame->sd.offsets[plane_index] = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmabuf_t::ready(
|
void
|
||||||
|
dmabuf_t::ready(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec) {
|
std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec) {
|
||||||
|
|
||||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||||
|
|
||||||
current_frame->destroy();
|
current_frame->destroy();
|
||||||
@@ -204,10 +222,10 @@ void dmabuf_t::ready(
|
|||||||
status = READY;
|
status = READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmabuf_t::cancel(
|
void
|
||||||
|
dmabuf_t::cancel(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t reason) {
|
std::uint32_t reason) {
|
||||||
|
|
||||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||||
|
|
||||||
auto next_frame = get_next_frame();
|
auto next_frame = get_next_frame();
|
||||||
@@ -216,7 +234,8 @@ void dmabuf_t::cancel(
|
|||||||
status = REINIT;
|
status = REINIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame_t::destroy() {
|
void
|
||||||
|
frame_t::destroy() {
|
||||||
for (auto x = 0; x < 4; ++x) {
|
for (auto x = 0; x < 4; ++x) {
|
||||||
if (sd.fds[x] >= 0) {
|
if (sd.fds[x] >= 0) {
|
||||||
close(sd.fds[x]);
|
close(sd.fds[x]);
|
||||||
@@ -231,7 +250,8 @@ frame_t::frame_t() {
|
|||||||
std::fill_n(sd.fds, 4, -1);
|
std::fill_n(sd.fds, 4, -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::unique_ptr<monitor_t>> monitors(const char *display_name) {
|
std::vector<std::unique_ptr<monitor_t>>
|
||||||
|
monitors(const char *display_name) {
|
||||||
display_t display;
|
display_t display;
|
||||||
|
|
||||||
if (display.init(display_name)) {
|
if (display.init(display_name)) {
|
||||||
@@ -257,13 +277,15 @@ std::vector<std::unique_ptr<monitor_t>> monitors(const char *display_name) {
|
|||||||
return std::move(interface.monitors);
|
return std::move(interface.monitors);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validate() {
|
static bool
|
||||||
|
validate() {
|
||||||
display_t display;
|
display_t display;
|
||||||
|
|
||||||
return display.init() == 0;
|
return display.init() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
static bool validated = validate();
|
static bool validated = validate();
|
||||||
|
|
||||||
return !validated;
|
return !validated;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ public:
|
|||||||
frame_t();
|
frame_t();
|
||||||
egl::surface_descriptor_t sd;
|
egl::surface_descriptor_t sd;
|
||||||
|
|
||||||
void destroy();
|
void
|
||||||
|
destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
class dmabuf_t {
|
class dmabuf_t {
|
||||||
@@ -38,16 +39,20 @@ public:
|
|||||||
dmabuf_t(dmabuf_t &&) = delete;
|
dmabuf_t(dmabuf_t &&) = delete;
|
||||||
dmabuf_t(const dmabuf_t &) = delete;
|
dmabuf_t(const dmabuf_t &) = delete;
|
||||||
|
|
||||||
dmabuf_t &operator=(const dmabuf_t &) = delete;
|
dmabuf_t &
|
||||||
dmabuf_t &operator=(dmabuf_t &&) = delete;
|
operator=(const dmabuf_t &) = delete;
|
||||||
|
dmabuf_t &
|
||||||
|
operator=(dmabuf_t &&) = delete;
|
||||||
|
|
||||||
dmabuf_t();
|
dmabuf_t();
|
||||||
|
|
||||||
void listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor = false);
|
void
|
||||||
|
listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor = false);
|
||||||
|
|
||||||
~dmabuf_t();
|
~dmabuf_t();
|
||||||
|
|
||||||
void frame(
|
void
|
||||||
|
frame(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t width, std::uint32_t height,
|
std::uint32_t width, std::uint32_t height,
|
||||||
std::uint32_t x, std::uint32_t y,
|
std::uint32_t x, std::uint32_t y,
|
||||||
@@ -56,7 +61,8 @@ public:
|
|||||||
std::uint32_t high, std::uint32_t low,
|
std::uint32_t high, std::uint32_t low,
|
||||||
std::uint32_t obj_count);
|
std::uint32_t obj_count);
|
||||||
|
|
||||||
void object(
|
void
|
||||||
|
object(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t index,
|
std::uint32_t index,
|
||||||
std::int32_t fd,
|
std::int32_t fd,
|
||||||
@@ -65,15 +71,18 @@ public:
|
|||||||
std::uint32_t stride,
|
std::uint32_t stride,
|
||||||
std::uint32_t plane_index);
|
std::uint32_t plane_index);
|
||||||
|
|
||||||
void ready(
|
void
|
||||||
|
ready(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec);
|
std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec);
|
||||||
|
|
||||||
void cancel(
|
void
|
||||||
|
cancel(
|
||||||
zwlr_export_dmabuf_frame_v1 *frame,
|
zwlr_export_dmabuf_frame_v1 *frame,
|
||||||
std::uint32_t reason);
|
std::uint32_t reason);
|
||||||
|
|
||||||
inline frame_t *get_next_frame() {
|
inline frame_t *
|
||||||
|
get_next_frame() {
|
||||||
return current_frame == &frames[0] ? &frames[1] : &frames[0];
|
return current_frame == &frames[0] ? &frames[1] : &frames[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,18 +99,26 @@ public:
|
|||||||
monitor_t(monitor_t &&) = delete;
|
monitor_t(monitor_t &&) = delete;
|
||||||
monitor_t(const monitor_t &) = delete;
|
monitor_t(const monitor_t &) = delete;
|
||||||
|
|
||||||
monitor_t &operator=(const monitor_t &) = delete;
|
monitor_t &
|
||||||
monitor_t &operator=(monitor_t &&) = delete;
|
operator=(const monitor_t &) = delete;
|
||||||
|
monitor_t &
|
||||||
|
operator=(monitor_t &&) = delete;
|
||||||
|
|
||||||
monitor_t(wl_output *output);
|
monitor_t(wl_output *output);
|
||||||
|
|
||||||
void xdg_name(zxdg_output_v1 *, const char *name);
|
void
|
||||||
void xdg_description(zxdg_output_v1 *, const char *description);
|
xdg_name(zxdg_output_v1 *, const char *name);
|
||||||
void xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y);
|
void
|
||||||
void xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height);
|
xdg_description(zxdg_output_v1 *, const char *description);
|
||||||
void xdg_done(zxdg_output_v1 *);
|
void
|
||||||
|
xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y);
|
||||||
|
void
|
||||||
|
xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height);
|
||||||
|
void
|
||||||
|
xdg_done(zxdg_output_v1 *);
|
||||||
|
|
||||||
void listen(zxdg_output_manager_v1 *output_manager);
|
void
|
||||||
|
listen(zxdg_output_manager_v1 *output_manager);
|
||||||
|
|
||||||
wl_output *output;
|
wl_output *output;
|
||||||
|
|
||||||
@@ -129,25 +146,31 @@ public:
|
|||||||
interface_t(interface_t &&) = delete;
|
interface_t(interface_t &&) = delete;
|
||||||
interface_t(const interface_t &) = delete;
|
interface_t(const interface_t &) = delete;
|
||||||
|
|
||||||
interface_t &operator=(const interface_t &) = delete;
|
interface_t &
|
||||||
interface_t &operator=(interface_t &&) = delete;
|
operator=(const interface_t &) = delete;
|
||||||
|
interface_t &
|
||||||
|
operator=(interface_t &&) = delete;
|
||||||
|
|
||||||
interface_t() noexcept;
|
interface_t() noexcept;
|
||||||
|
|
||||||
void listen(wl_registry *registry);
|
void
|
||||||
|
listen(wl_registry *registry);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<monitor_t>> monitors;
|
std::vector<std::unique_ptr<monitor_t>> monitors;
|
||||||
|
|
||||||
zwlr_export_dmabuf_manager_v1 *dmabuf_manager;
|
zwlr_export_dmabuf_manager_v1 *dmabuf_manager;
|
||||||
zxdg_output_manager_v1 *output_manager;
|
zxdg_output_manager_v1 *output_manager;
|
||||||
|
|
||||||
bool operator[](interface_e bit) const {
|
bool
|
||||||
|
operator[](interface_e bit) const {
|
||||||
return interface[bit];
|
return interface[bit];
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version);
|
void
|
||||||
void del_interface(wl_registry *registry, uint32_t id);
|
add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version);
|
||||||
|
void
|
||||||
|
del_interface(wl_registry *registry, uint32_t id);
|
||||||
|
|
||||||
std::bitset<MAX_INTERFACES> interface;
|
std::bitset<MAX_INTERFACES> interface;
|
||||||
|
|
||||||
@@ -160,16 +183,20 @@ public:
|
|||||||
* Initialize display with display_name
|
* Initialize display with display_name
|
||||||
* If display_name == nullptr -> display_name = std::getenv("WAYLAND_DISPLAY")
|
* If display_name == nullptr -> display_name = std::getenv("WAYLAND_DISPLAY")
|
||||||
*/
|
*/
|
||||||
int init(const char *display_name = nullptr);
|
int
|
||||||
|
init(const char *display_name = nullptr);
|
||||||
|
|
||||||
// Roundtrip with Wayland connection
|
// Roundtrip with Wayland connection
|
||||||
void roundtrip();
|
void
|
||||||
|
roundtrip();
|
||||||
|
|
||||||
// Get the registry associated with the display
|
// Get the registry associated with the display
|
||||||
// No need to manually free the registry
|
// No need to manually free the registry
|
||||||
wl_registry *registry();
|
wl_registry *
|
||||||
|
registry();
|
||||||
|
|
||||||
inline display_internal_t::pointer get() {
|
inline display_internal_t::pointer
|
||||||
|
get() {
|
||||||
return display_internal.get();
|
return display_internal.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,9 +204,11 @@ private:
|
|||||||
display_internal_t display_internal;
|
display_internal_t display_internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::unique_ptr<monitor_t>> monitors(const char *display_name = nullptr);
|
std::vector<std::unique_ptr<monitor_t>>
|
||||||
|
monitors(const char *display_name = nullptr);
|
||||||
|
|
||||||
int init();
|
int
|
||||||
|
init();
|
||||||
} // namespace wl
|
} // namespace wl
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -192,12 +221,15 @@ public:
|
|||||||
monitor_t(monitor_t &&) = delete;
|
monitor_t(monitor_t &&) = delete;
|
||||||
monitor_t(const monitor_t &) = delete;
|
monitor_t(const monitor_t &) = delete;
|
||||||
|
|
||||||
monitor_t &operator=(const monitor_t &) = delete;
|
monitor_t &
|
||||||
monitor_t &operator=(monitor_t &&) = delete;
|
operator=(const monitor_t &) = delete;
|
||||||
|
monitor_t &
|
||||||
|
operator=(monitor_t &&) = delete;
|
||||||
|
|
||||||
monitor_t(wl_output *output);
|
monitor_t(wl_output *output);
|
||||||
|
|
||||||
void listen(zxdg_output_manager_v1 *output_manager);
|
void
|
||||||
|
listen(zxdg_output_manager_v1 *output_manager);
|
||||||
|
|
||||||
wl_output *output;
|
wl_output *output;
|
||||||
|
|
||||||
@@ -207,9 +239,11 @@ public:
|
|||||||
platf::touch_port_t viewport;
|
platf::touch_port_t viewport;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::vector<std::unique_ptr<monitor_t>> monitors(const char *display_name = nullptr) { return {}; }
|
inline std::vector<std::unique_ptr<monitor_t>>
|
||||||
|
monitors(const char *display_name = nullptr) { return {}; }
|
||||||
|
|
||||||
inline int init() { return -1; }
|
inline int
|
||||||
|
init() { return -1; }
|
||||||
} // namespace wl
|
} // namespace wl
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ struct img_t : public platf::img_t {
|
|||||||
|
|
||||||
class wlr_t: public platf::display_t {
|
class wlr_t: public platf::display_t {
|
||||||
public:
|
public:
|
||||||
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
||||||
delay = std::chrono::nanoseconds { 1s } / config.framerate;
|
delay = std::chrono::nanoseconds { 1s } / config.framerate;
|
||||||
mem_type = hwdevice_type;
|
mem_type = hwdevice_type;
|
||||||
|
|
||||||
@@ -73,11 +74,13 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int
|
||||||
|
dummy_img(platf::img_t *img) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline platf::capture_e snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
inline platf::capture_e
|
||||||
|
snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
auto to = std::chrono::steady_clock::now() + timeout;
|
auto to = std::chrono::steady_clock::now() + timeout;
|
||||||
|
|
||||||
dmabuf.listen(interface.dmabuf_manager, output, cursor);
|
dmabuf.listen(interface.dmabuf_manager, output, cursor);
|
||||||
@@ -95,7 +98,6 @@ public:
|
|||||||
dmabuf.status == dmabuf_t::REINIT ||
|
dmabuf.status == dmabuf_t::REINIT ||
|
||||||
current_frame->sd.width != width ||
|
current_frame->sd.width != width ||
|
||||||
current_frame->sd.height != height) {
|
current_frame->sd.height != height) {
|
||||||
|
|
||||||
return platf::capture_e::reinit;
|
return platf::capture_e::reinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +117,8 @@ public:
|
|||||||
|
|
||||||
class wlr_ram_t: public wlr_t {
|
class wlr_ram_t: public wlr_t {
|
||||||
public:
|
public:
|
||||||
platf::capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
platf::capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -149,7 +152,8 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::capture_e snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
platf::capture_e
|
||||||
|
snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
auto status = wlr_t::snapshot(img_out_base, timeout, cursor);
|
auto status = wlr_t::snapshot(img_out_base, timeout, cursor);
|
||||||
if (status != platf::capture_e::ok) {
|
if (status != platf::capture_e::ok) {
|
||||||
return status;
|
return status;
|
||||||
@@ -176,7 +180,8 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (wlr_t::init(hwdevice_type, display_name, config)) {
|
if (wlr_t::init(hwdevice_type, display_name, config)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -196,7 +201,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
||||||
if (mem_type == platf::mem_type_e::vaapi) {
|
if (mem_type == platf::mem_type_e::vaapi) {
|
||||||
return va::make_hwdevice(width, height, false);
|
return va::make_hwdevice(width, height, false);
|
||||||
}
|
}
|
||||||
@@ -204,7 +210,8 @@ public:
|
|||||||
return std::make_shared<platf::hwdevice_t>();
|
return std::make_shared<platf::hwdevice_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::img_t> alloc_img() override {
|
std::shared_ptr<platf::img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<img_t>();
|
auto img = std::make_shared<img_t>();
|
||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
@@ -221,7 +228,8 @@ public:
|
|||||||
|
|
||||||
class wlr_vram_t: public wlr_t {
|
class wlr_vram_t: public wlr_t {
|
||||||
public:
|
public:
|
||||||
platf::capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
platf::capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<platf::img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -255,7 +263,8 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::capture_e snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
platf::capture_e
|
||||||
|
snapshot(platf::img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
auto status = wlr_t::snapshot(img_out_base, timeout, cursor);
|
auto status = wlr_t::snapshot(img_out_base, timeout, cursor);
|
||||||
if (status != platf::capture_e::ok) {
|
if (status != platf::capture_e::ok) {
|
||||||
return status;
|
return status;
|
||||||
@@ -277,7 +286,8 @@ public:
|
|||||||
return platf::capture_e::ok;
|
return platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::img_t> alloc_img() override {
|
std::shared_ptr<platf::img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<egl::img_descriptor_t>();
|
auto img = std::make_shared<egl::img_descriptor_t>();
|
||||||
|
|
||||||
img->sequence = 0;
|
img->sequence = 0;
|
||||||
@@ -290,7 +300,8 @@ public:
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(platf::pix_fmt_e pix_fmt) override {
|
||||||
if (mem_type == platf::mem_type_e::vaapi) {
|
if (mem_type == platf::mem_type_e::vaapi) {
|
||||||
return va::make_hwdevice(width, height, 0, 0, true);
|
return va::make_hwdevice(width, height, 0, 0, true);
|
||||||
}
|
}
|
||||||
@@ -298,7 +309,8 @@ public:
|
|||||||
return std::make_shared<platf::hwdevice_t>();
|
return std::make_shared<platf::hwdevice_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int
|
||||||
|
dummy_img(platf::img_t *img) override {
|
||||||
return snapshot(img, 1000ms, false) != platf::capture_e::ok;
|
return snapshot(img, 1000ms, false) != platf::capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +320,8 @@ public:
|
|||||||
} // namespace wl
|
} // namespace wl
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||||
if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
||||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -331,7 +344,8 @@ std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::strin
|
|||||||
return wlr;
|
return wlr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> wl_display_names() {
|
std::vector<std::string>
|
||||||
|
wl_display_names() {
|
||||||
std::vector<std::string> display_names;
|
std::vector<std::string> display_names;
|
||||||
|
|
||||||
wl::display_t display;
|
wl::display_t display;
|
||||||
|
|||||||
@@ -30,8 +30,10 @@
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
int load_xcb();
|
int
|
||||||
int load_x11();
|
load_xcb();
|
||||||
|
int
|
||||||
|
load_x11();
|
||||||
|
|
||||||
namespace x11 {
|
namespace x11 {
|
||||||
#define _FN(x, ret, args) \
|
#define _FN(x, ret, args) \
|
||||||
@@ -66,7 +68,8 @@ _FN(FreeScreenResources, void, (XRRScreenResources * resources));
|
|||||||
_FN(FreeOutputInfo, void, (XRROutputInfo * outputInfo));
|
_FN(FreeOutputInfo, void, (XRROutputInfo * outputInfo));
|
||||||
_FN(FreeCrtcInfo, void, (XRRCrtcInfo * crtcInfo));
|
_FN(FreeCrtcInfo, void, (XRRCrtcInfo * crtcInfo));
|
||||||
|
|
||||||
static int init() {
|
static int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -100,7 +103,8 @@ static int init() {
|
|||||||
namespace fix {
|
namespace fix {
|
||||||
_FN(GetCursorImage, XFixesCursorImage *, (Display * dpy));
|
_FN(GetCursorImage, XFixesCursorImage *, (Display * dpy));
|
||||||
|
|
||||||
static int init() {
|
static int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -126,7 +130,8 @@ static int init() {
|
|||||||
}
|
}
|
||||||
} // namespace fix
|
} // namespace fix
|
||||||
|
|
||||||
static int init() {
|
static int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -193,7 +198,8 @@ _FN(connect, xcb_connection_t *, (const char *displayname, int *screenp));
|
|||||||
_FN(setup_roots_iterator, xcb_screen_iterator_t, (const xcb_setup_t *R));
|
_FN(setup_roots_iterator, xcb_screen_iterator_t, (const xcb_setup_t *R));
|
||||||
_FN(generate_id, std::uint32_t, (xcb_connection_t * c));
|
_FN(generate_id, std::uint32_t, (xcb_connection_t * c));
|
||||||
|
|
||||||
int init_shm() {
|
int
|
||||||
|
init_shm() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -221,7 +227,8 @@ int init_shm() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -255,8 +262,10 @@ int init() {
|
|||||||
#undef _FN
|
#undef _FN
|
||||||
} // namespace xcb
|
} // namespace xcb
|
||||||
|
|
||||||
void freeImage(XImage *);
|
void
|
||||||
void freeX(XFixesCursorImage *);
|
freeImage(XImage *);
|
||||||
|
void
|
||||||
|
freeX(XFixesCursorImage *);
|
||||||
|
|
||||||
using xcb_connect_t = util::dyn_safe_ptr<xcb_connection_t, &xcb::disconnect>;
|
using xcb_connect_t = util::dyn_safe_ptr<xcb_connection_t, &xcb::disconnect>;
|
||||||
using xcb_img_t = util::c_ptr<xcb_shm_get_image_reply_t>;
|
using xcb_img_t = util::c_ptr<xcb_shm_get_image_reply_t>;
|
||||||
@@ -270,9 +279,12 @@ using screen_res_t = util::dyn_safe_ptr<_XRRScreenResources, &x11::rr::FreeScre
|
|||||||
|
|
||||||
class shm_id_t {
|
class shm_id_t {
|
||||||
public:
|
public:
|
||||||
shm_id_t() : id { -1 } {}
|
shm_id_t():
|
||||||
shm_id_t(int id) : id { id } {}
|
id { -1 } {}
|
||||||
shm_id_t(shm_id_t &&other) noexcept : id(other.id) {
|
shm_id_t(int id):
|
||||||
|
id { id } {}
|
||||||
|
shm_id_t(shm_id_t &&other) noexcept:
|
||||||
|
id(other.id) {
|
||||||
other.id = -1;
|
other.id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,10 +299,13 @@ public:
|
|||||||
|
|
||||||
class shm_data_t {
|
class shm_data_t {
|
||||||
public:
|
public:
|
||||||
shm_data_t() : data { (void *)-1 } {}
|
shm_data_t():
|
||||||
shm_data_t(void *data) : data { data } {}
|
data { (void *) -1 } {}
|
||||||
|
shm_data_t(void *data):
|
||||||
|
data { data } {}
|
||||||
|
|
||||||
shm_data_t(shm_data_t &&other) noexcept : data(other.data) {
|
shm_data_t(shm_data_t &&other) noexcept:
|
||||||
|
data(other.data) {
|
||||||
other.data = (void *) -1;
|
other.data = (void *) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +329,8 @@ struct shm_img_t : public img_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void blend_cursor(Display *display, img_t &img, int offsetX, int offsetY) {
|
static void
|
||||||
|
blend_cursor(Display *display, img_t &img, int offsetX, int offsetY) {
|
||||||
xcursor_t overlay { x11::fix::GetCursorImage(display) };
|
xcursor_t overlay { x11::fix::GetCursorImage(display) };
|
||||||
|
|
||||||
if (!overlay) {
|
if (!overlay) {
|
||||||
@@ -379,11 +395,13 @@ struct x11_attr_t : public display_t {
|
|||||||
*/
|
*/
|
||||||
// int env_width, env_height;
|
// int env_width, env_height;
|
||||||
|
|
||||||
x11_attr_t(mem_type_e mem_type) : xdisplay { x11::OpenDisplay(nullptr) }, xwindow {}, xattr {}, mem_type { mem_type } {
|
x11_attr_t(mem_type_e mem_type):
|
||||||
|
xdisplay { x11::OpenDisplay(nullptr) }, xwindow {}, xattr {}, mem_type { mem_type } {
|
||||||
x11::InitThreads();
|
x11::InitThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (!xdisplay) {
|
if (!xdisplay) {
|
||||||
BOOST_LOG(error) << "Could not open X11 display"sv;
|
BOOST_LOG(error) << "Could not open X11 display"sv;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -452,11 +470,13 @@ struct x11_attr_t : public display_t {
|
|||||||
/**
|
/**
|
||||||
* Called when the display attributes should change.
|
* Called when the display attributes should change.
|
||||||
*/
|
*/
|
||||||
void refresh() {
|
void
|
||||||
|
refresh() {
|
||||||
x11::GetWindowAttributes(xdisplay.get(), xwindow, &xattr); //Update xattr's
|
x11::GetWindowAttributes(xdisplay.get(), xwindow, &xattr); //Update xattr's
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -491,7 +511,8 @@ struct x11_attr_t : public display_t {
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
capture_e
|
||||||
|
snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
//The whole X server changed, so we must reinit everything
|
//The whole X server changed, so we must reinit everything
|
||||||
@@ -516,11 +537,13 @@ struct x11_attr_t : public display_t {
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t>
|
||||||
|
alloc_img() override {
|
||||||
return std::make_shared<x11_img_t>();
|
return std::make_shared<x11_img_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
std::shared_ptr<hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||||
if (mem_type == mem_type_e::vaapi) {
|
if (mem_type == mem_type_e::vaapi) {
|
||||||
return va::make_hwdevice(width, height, false);
|
return va::make_hwdevice(width, height, false);
|
||||||
}
|
}
|
||||||
@@ -534,7 +557,8 @@ struct x11_attr_t : public display_t {
|
|||||||
return std::make_shared<hwdevice_t>();
|
return std::make_shared<hwdevice_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(img_t *img) override {
|
int
|
||||||
|
dummy_img(img_t *img) override {
|
||||||
snapshot(img, 0s, true);
|
snapshot(img, 0s, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -552,13 +576,15 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
|
|
||||||
task_pool_util::TaskPool::task_id_t refresh_task_id;
|
task_pool_util::TaskPool::task_id_t refresh_task_id;
|
||||||
|
|
||||||
void delayed_refresh() {
|
void
|
||||||
|
delayed_refresh() {
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
shm_attr_t(mem_type_e mem_type) : x11_attr_t(mem_type), shm_xdisplay { x11::OpenDisplay(nullptr) } {
|
shm_attr_t(mem_type_e mem_type):
|
||||||
|
x11_attr_t(mem_type), shm_xdisplay { x11::OpenDisplay(nullptr) } {
|
||||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +593,8 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
while (img) {
|
while (img) {
|
||||||
@@ -602,7 +629,8 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) {
|
capture_e
|
||||||
|
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
//The whole X server changed, so we must reinit everything
|
//The whole X server changed, so we must reinit everything
|
||||||
if (xattr.width != env_width || xattr.height != env_height) {
|
if (xattr.width != env_width || xattr.height != env_height) {
|
||||||
BOOST_LOG(warning) << "X dimensions changed in SHM mode, request reinit"sv;
|
BOOST_LOG(warning) << "X dimensions changed in SHM mode, request reinit"sv;
|
||||||
@@ -627,7 +655,8 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t>
|
||||||
|
alloc_img() override {
|
||||||
auto img = std::make_shared<shm_img_t>();
|
auto img = std::make_shared<shm_img_t>();
|
||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
@@ -638,11 +667,13 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int
|
||||||
|
dummy_img(platf::img_t *img) override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(const std::string &display_name, const ::video::config_t &config) {
|
int
|
||||||
|
init(const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (x11_attr_t::init(display_name, config)) {
|
if (x11_attr_t::init(display_name, config)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -681,12 +712,14 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t frame_size() {
|
std::uint32_t
|
||||||
|
frame_size() {
|
||||||
return width * height * 4;
|
return width * height * 4;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
x11_display(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
|
||||||
if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
||||||
BOOST_LOG(error) << "Could not initialize x11 display with the given hw device type"sv;
|
BOOST_LOG(error) << "Could not initialize x11 display with the given hw device type"sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -720,7 +753,8 @@ std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const st
|
|||||||
return x11_disp;
|
return x11_disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> x11_display_names() {
|
std::vector<std::string>
|
||||||
|
x11_display_names() {
|
||||||
if (load_x11() || load_xcb()) {
|
if (load_x11() || load_xcb()) {
|
||||||
BOOST_LOG(error) << "Couldn't init x11 libraries"sv;
|
BOOST_LOG(error) << "Couldn't init x11 libraries"sv;
|
||||||
|
|
||||||
@@ -756,21 +790,25 @@ std::vector<std::string> x11_display_names() {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeImage(XImage *p) {
|
void
|
||||||
|
freeImage(XImage *p) {
|
||||||
XDestroyImage(p);
|
XDestroyImage(p);
|
||||||
}
|
}
|
||||||
void freeX(XFixesCursorImage *p) {
|
void
|
||||||
|
freeX(XFixesCursorImage *p) {
|
||||||
x11::Free(p);
|
x11::Free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_xcb() {
|
int
|
||||||
|
load_xcb() {
|
||||||
// This will be called once only
|
// This will be called once only
|
||||||
static int xcb_status = xcb::init_shm() || xcb::init();
|
static int xcb_status = xcb::init_shm() || xcb::init();
|
||||||
|
|
||||||
return xcb_status;
|
return xcb_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_x11() {
|
int
|
||||||
|
load_x11() {
|
||||||
// This will be called once only
|
// This will be called once only
|
||||||
static int x11_status =
|
static int x11_status =
|
||||||
window_system == window_system_e::NONE ||
|
window_system == window_system_e::NONE ||
|
||||||
@@ -780,7 +818,8 @@ int load_x11() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace x11 {
|
namespace x11 {
|
||||||
std::optional<cursor_t> cursor_t::make() {
|
std::optional<cursor_t>
|
||||||
|
cursor_t::make() {
|
||||||
if (load_x11()) {
|
if (load_x11()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -792,7 +831,8 @@ std::optional<cursor_t> cursor_t::make() {
|
|||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_t::capture(egl::cursor_t &img) {
|
void
|
||||||
|
cursor_t::capture(egl::cursor_t &img) {
|
||||||
auto display = (xdisplay_t::pointer) ctx.get();
|
auto display = (xdisplay_t::pointer) ctx.get();
|
||||||
|
|
||||||
xcursor_t xcursor = fix::GetCursorImage(display);
|
xcursor_t xcursor = fix::GetCursorImage(display);
|
||||||
@@ -819,19 +859,23 @@ void cursor_t::capture(egl::cursor_t &img) {
|
|||||||
img.serial = xcursor->cursor_serial;
|
img.serial = xcursor->cursor_serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_t::blend(img_t &img, int offsetX, int offsetY) {
|
void
|
||||||
|
cursor_t::blend(img_t &img, int offsetX, int offsetY) {
|
||||||
blend_cursor((xdisplay_t::pointer) ctx.get(), img, offsetX, offsetY);
|
blend_cursor((xdisplay_t::pointer) ctx.get(), img, offsetX, offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
xdisplay_t make_display() {
|
xdisplay_t
|
||||||
|
make_display() {
|
||||||
return OpenDisplay(nullptr);
|
return OpenDisplay(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeDisplay(_XDisplay *xdisplay) {
|
void
|
||||||
|
freeDisplay(_XDisplay *xdisplay) {
|
||||||
CloseDisplay(xdisplay);
|
CloseDisplay(xdisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeCursorCtx(cursor_ctx_t::pointer ctx) {
|
void
|
||||||
|
freeCursorCtx(cursor_ctx_t::pointer ctx) {
|
||||||
CloseDisplay((xdisplay_t::pointer) ctx);
|
CloseDisplay((xdisplay_t::pointer) ctx);
|
||||||
}
|
}
|
||||||
} // namespace x11
|
} // namespace x11
|
||||||
|
|||||||
@@ -17,17 +17,21 @@ namespace platf::x11 {
|
|||||||
|
|
||||||
#ifdef SUNSHINE_BUILD_X11
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
struct cursor_ctx_raw_t;
|
struct cursor_ctx_raw_t;
|
||||||
void freeCursorCtx(cursor_ctx_raw_t *ctx);
|
void
|
||||||
void freeDisplay(_XDisplay *xdisplay);
|
freeCursorCtx(cursor_ctx_raw_t *ctx);
|
||||||
|
void
|
||||||
|
freeDisplay(_XDisplay *xdisplay);
|
||||||
|
|
||||||
using cursor_ctx_t = util::safe_ptr<cursor_ctx_raw_t, freeCursorCtx>;
|
using cursor_ctx_t = util::safe_ptr<cursor_ctx_raw_t, freeCursorCtx>;
|
||||||
using xdisplay_t = util::safe_ptr<_XDisplay, freeDisplay>;
|
using xdisplay_t = util::safe_ptr<_XDisplay, freeDisplay>;
|
||||||
|
|
||||||
class cursor_t {
|
class cursor_t {
|
||||||
public:
|
public:
|
||||||
static std::optional<cursor_t> make();
|
static std::optional<cursor_t>
|
||||||
|
make();
|
||||||
|
|
||||||
void capture(egl::cursor_t &img);
|
void
|
||||||
|
capture(egl::cursor_t &img);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture and blend the cursor into the image
|
* Capture and blend the cursor into the image
|
||||||
@@ -35,25 +39,31 @@ public:
|
|||||||
* img <-- destination image
|
* img <-- destination image
|
||||||
* offsetX, offsetY <--- Top left corner of the virtual screen
|
* offsetX, offsetY <--- Top left corner of the virtual screen
|
||||||
*/
|
*/
|
||||||
void blend(img_t &img, int offsetX, int offsetY);
|
void
|
||||||
|
blend(img_t &img, int offsetX, int offsetY);
|
||||||
|
|
||||||
cursor_ctx_t ctx;
|
cursor_ctx_t ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
xdisplay_t make_display();
|
xdisplay_t
|
||||||
|
make_display();
|
||||||
#else
|
#else
|
||||||
// It's never something different from nullptr
|
// It's never something different from nullptr
|
||||||
util::safe_ptr<_XDisplay, std::default_delete<_XDisplay>>;
|
util::safe_ptr<_XDisplay, std::default_delete<_XDisplay>>;
|
||||||
|
|
||||||
class cursor_t {
|
class cursor_t {
|
||||||
public:
|
public:
|
||||||
static std::optional<cursor_t> make() { return std::nullopt; }
|
static std::optional<cursor_t>
|
||||||
|
make() { return std::nullopt; }
|
||||||
|
|
||||||
void capture(egl::cursor_t &) {}
|
void
|
||||||
void blend(img_t &, int, int) {}
|
capture(egl::cursor_t &) {}
|
||||||
|
void
|
||||||
|
blend(img_t &, int, int) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
xdisplay_t make_display() { return nullptr; }
|
xdisplay_t
|
||||||
|
make_display() { return nullptr; }
|
||||||
#endif
|
#endif
|
||||||
} // namespace platf::x11
|
} // namespace platf::x11
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@implementation AVAudio
|
@implementation AVAudio
|
||||||
|
|
||||||
+ (NSArray<AVCaptureDevice *> *)microphones {
|
+ (NSArray<AVCaptureDevice *> *)microphones {
|
||||||
|
|
||||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) { 10, 15, 0 })]) {
|
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) { 10, 15, 0 })]) {
|
||||||
// This will generate a warning about AVCaptureDeviceDiscoverySession being
|
// This will generate a warning about AVCaptureDeviceDiscoverySession being
|
||||||
// unavailable before macOS 10.15, but we have a guard to prevent it from
|
// unavailable before macOS 10.15, but we have a guard to prevent it from
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
|
|
||||||
struct CaptureSession {
|
struct CaptureSession {
|
||||||
AVCaptureVideoDataOutput *output;
|
AVCaptureVideoDataOutput *output;
|
||||||
NSCondition *captureStopped;
|
NSCondition *captureStopped;
|
||||||
|
|||||||
@@ -163,7 +163,6 @@
|
|||||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
||||||
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||||
fromConnection:(AVCaptureConnection *)connection {
|
fromConnection:(AVCaptureConnection *)connection {
|
||||||
|
|
||||||
FrameCallbackBlock callback = [self.captureCallbacks objectForKey:connection];
|
FrameCallbackBlock callback = [self.captureCallbacks objectForKey:connection];
|
||||||
|
|
||||||
if (callback != nil) {
|
if (callback != nil) {
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ struct av_display_t : public display_t {
|
|||||||
[av_capture release];
|
[av_capture release];
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
||||||
__block auto img_next = std::move(img);
|
__block auto img_next = std::move(img);
|
||||||
|
|
||||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||||
@@ -76,11 +77,13 @@ struct av_display_t : public display_t {
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t>
|
||||||
|
alloc_img() override {
|
||||||
return std::make_shared<av_img_t>();
|
return std::make_shared<av_img_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
std::shared_ptr<hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||||
if (pix_fmt == pix_fmt_e::yuv420p) {
|
if (pix_fmt == pix_fmt_e::yuv420p) {
|
||||||
av_capture.pixelFormat = kCVPixelFormatType_32BGRA;
|
av_capture.pixelFormat = kCVPixelFormatType_32BGRA;
|
||||||
|
|
||||||
@@ -99,7 +102,8 @@ struct av_display_t : public display_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(img_t *img) override {
|
int
|
||||||
|
dummy_img(img_t *img) override {
|
||||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||||
auto av_img = (av_img_t *) img;
|
auto av_img = (av_img_t *) img;
|
||||||
|
|
||||||
@@ -143,16 +147,19 @@ struct av_display_t : public display_t {
|
|||||||
* width --> the intended capture width
|
* width --> the intended capture width
|
||||||
* height --> the intended capture height
|
* height --> the intended capture height
|
||||||
*/
|
*/
|
||||||
static void setResolution(void *display, int width, int height) {
|
static void
|
||||||
|
setResolution(void *display, int width, int height) {
|
||||||
[static_cast<AVVideo *>(display) setFrameWidth:width frameHeight:height];
|
[static_cast<AVVideo *>(display) setFrameWidth:width frameHeight:height];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setPixelFormat(void *display, OSType pixelFormat) {
|
static void
|
||||||
|
setPixelFormat(void *display, OSType pixelFormat) {
|
||||||
static_cast<AVVideo *>(display).pixelFormat = pixelFormat;
|
static_cast<AVVideo *>(display).pixelFormat = pixelFormat;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
display(platf::mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||||
if (hwdevice_type != platf::mem_type_e::system) {
|
if (hwdevice_type != platf::mem_type_e::system) {
|
||||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -186,7 +193,8 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::s
|
|||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> display_names(mem_type_e hwdevice_type) {
|
std::vector<std::string>
|
||||||
|
display_names(mem_type_e hwdevice_type) {
|
||||||
__block std::vector<std::string> display_names;
|
__block std::vector<std::string> display_names;
|
||||||
|
|
||||||
auto display_array = [AVVideo displayNames];
|
auto display_array = [AVVideo displayNames];
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ struct KeyCodeMap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Customized less operator for using std::lower_bound() on a KeyCodeMap array.
|
// Customized less operator for using std::lower_bound() on a KeyCodeMap array.
|
||||||
bool operator<(const KeyCodeMap &a, const KeyCodeMap &b) {
|
bool
|
||||||
|
operator<(const KeyCodeMap &a, const KeyCodeMap &b) {
|
||||||
return a.win_keycode < b.win_keycode;
|
return a.win_keycode < b.win_keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +213,8 @@ const KeyCodeMap kKeyCodesMap[] = {
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
int keysym(int keycode) {
|
int
|
||||||
|
keysym(int keycode) {
|
||||||
KeyCodeMap key_map;
|
KeyCodeMap key_map;
|
||||||
|
|
||||||
key_map.win_keycode = keycode;
|
key_map.win_keycode = keycode;
|
||||||
@@ -227,7 +229,8 @@ int keysym(int keycode) {
|
|||||||
return temp_map->mac_keycode;
|
return temp_map->mac_keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard(input_t &input, uint16_t modcode, bool release) {
|
void
|
||||||
|
keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||||
auto key = keysym(modcode);
|
auto key = keysym(modcode);
|
||||||
|
|
||||||
BOOST_LOG(debug) << "got keycode: 0x"sv << std::hex << modcode << ", translated to: 0x" << std::hex << key << ", release:" << release;
|
BOOST_LOG(debug) << "got keycode: 0x"sv << std::hex << modcode << ", translated to: 0x" << std::hex << key << ", release:" << release;
|
||||||
@@ -243,7 +246,6 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
key == kVK_Command || key == kVK_RightCommand ||
|
key == kVK_Command || key == kVK_RightCommand ||
|
||||||
key == kVK_Option || key == kVK_RightOption ||
|
key == kVK_Option || key == kVK_RightOption ||
|
||||||
key == kVK_Control || key == kVK_RightControl) {
|
key == kVK_Control || key == kVK_RightControl) {
|
||||||
|
|
||||||
CGEventFlags mask;
|
CGEventFlags mask;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@@ -277,29 +279,35 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
CGEventPost(kCGHIDEventTap, event);
|
CGEventPost(kCGHIDEventTap, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unicode(input_t &input, char *utf8, int size) {
|
void
|
||||||
|
unicode(input_t &input, char *utf8, int size) {
|
||||||
BOOST_LOG(info) << "unicode: Unicode input not yet implemented for MacOS."sv;
|
BOOST_LOG(info) << "unicode: Unicode input not yet implemented for MacOS."sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
int
|
||||||
|
alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
||||||
BOOST_LOG(info) << "alloc_gamepad: Gamepad not yet implemented for MacOS."sv;
|
BOOST_LOG(info) << "alloc_gamepad: Gamepad not yet implemented for MacOS."sv;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_gamepad(input_t &input, int nr) {
|
void
|
||||||
|
free_gamepad(input_t &input, int nr) {
|
||||||
BOOST_LOG(info) << "free_gamepad: Gamepad not yet implemented for MacOS."sv;
|
BOOST_LOG(info) << "free_gamepad: Gamepad not yet implemented for MacOS."sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
void
|
||||||
|
gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||||
BOOST_LOG(info) << "gamepad: Gamepad not yet implemented for MacOS."sv;
|
BOOST_LOG(info) << "gamepad: Gamepad not yet implemented for MacOS."sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns current mouse location:
|
// returns current mouse location:
|
||||||
inline CGPoint get_mouse_loc(input_t &input) {
|
inline CGPoint
|
||||||
|
get_mouse_loc(input_t &input) {
|
||||||
return CGEventGetLocation(((macos_input_t *) input.get())->mouse_event);
|
return CGEventGetLocation(((macos_input_t *) input.get())->mouse_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_mouse(input_t &input, CGMouseButton button, CGEventType type, CGPoint location, int click_count) {
|
void
|
||||||
|
post_mouse(input_t &input, CGMouseButton button, CGEventType type, CGPoint location, int click_count) {
|
||||||
BOOST_LOG(debug) << "mouse_event: "sv << button << ", type: "sv << type << ", location:"sv << location.x << ":"sv << location.y << " click_count: "sv << click_count;
|
BOOST_LOG(debug) << "mouse_event: "sv << button << ", type: "sv << type << ", location:"sv << location.x << ":"sv << location.y << " click_count: "sv << click_count;
|
||||||
|
|
||||||
auto macos_input = (macos_input_t *) input.get();
|
auto macos_input = (macos_input_t *) input.get();
|
||||||
@@ -328,7 +336,8 @@ void post_mouse(input_t &input, CGMouseButton button, CGEventType type, CGPoint
|
|||||||
CGWarpMouseCursorPosition(location);
|
CGWarpMouseCursorPosition(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CGEventType event_type_mouse(input_t &input) {
|
inline CGEventType
|
||||||
|
event_type_mouse(input_t &input) {
|
||||||
auto macos_input = ((macos_input_t *) input.get());
|
auto macos_input = ((macos_input_t *) input.get());
|
||||||
|
|
||||||
if (macos_input->mouse_down[0]) {
|
if (macos_input->mouse_down[0]) {
|
||||||
@@ -345,7 +354,8 @@ inline CGEventType event_type_mouse(input_t &input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void move_mouse(input_t &input, int deltaX, int deltaY) {
|
void
|
||||||
|
move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||||
auto current = get_mouse_loc(input);
|
auto current = get_mouse_loc(input);
|
||||||
|
|
||||||
CGPoint location = CGPointMake(current.x + deltaX, current.y + deltaY);
|
CGPoint location = CGPointMake(current.x + deltaX, current.y + deltaY);
|
||||||
@@ -353,7 +363,8 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, 0);
|
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
void
|
||||||
|
abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
||||||
auto scaling = ((macos_input_t *) input.get())->displayScaling;
|
auto scaling = ((macos_input_t *) input.get())->displayScaling;
|
||||||
|
|
||||||
CGPoint location = CGPointMake(x * scaling, y * scaling);
|
CGPoint location = CGPointMake(x * scaling, y * scaling);
|
||||||
@@ -361,7 +372,8 @@ void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y)
|
|||||||
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, 0);
|
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t time_diff(uint64_t start) {
|
uint64_t
|
||||||
|
time_diff(uint64_t start) {
|
||||||
uint64_t elapsed;
|
uint64_t elapsed;
|
||||||
Nanoseconds elapsedNano;
|
Nanoseconds elapsedNano;
|
||||||
|
|
||||||
@@ -371,7 +383,8 @@ uint64_t time_diff(uint64_t start) {
|
|||||||
return *(uint64_t *) &elapsedNano;
|
return *(uint64_t *) &elapsedNano;
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_mouse(input_t &input, int button, bool release) {
|
void
|
||||||
|
button_mouse(input_t &input, int button, bool release) {
|
||||||
CGMouseButton mac_button;
|
CGMouseButton mac_button;
|
||||||
CGEventType event;
|
CGEventType event;
|
||||||
|
|
||||||
@@ -408,7 +421,8 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||||||
mouse->last_mouse_event[mac_button][release] = mach_absolute_time();
|
mouse->last_mouse_event[mac_button][release] = mach_absolute_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
void scroll(input_t &input, int high_res_distance) {
|
void
|
||||||
|
scroll(input_t &input, int high_res_distance) {
|
||||||
CGEventRef upEvent = CGEventCreateScrollWheelEvent(
|
CGEventRef upEvent = CGEventCreateScrollWheelEvent(
|
||||||
NULL,
|
NULL,
|
||||||
kCGScrollEventUnitLine,
|
kCGScrollEventUnitLine,
|
||||||
@@ -417,11 +431,13 @@ void scroll(input_t &input, int high_res_distance) {
|
|||||||
CFRelease(upEvent);
|
CFRelease(upEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hscroll(input_t &input, int high_res_distance) {
|
void
|
||||||
|
hscroll(input_t &input, int high_res_distance) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
input_t input() {
|
input_t
|
||||||
|
input() {
|
||||||
input_t result { new macos_input_t() };
|
input_t result { new macos_input_t() };
|
||||||
|
|
||||||
auto macos_input = (macos_input_t *) result.get();
|
auto macos_input = (macos_input_t *) result.get();
|
||||||
@@ -455,7 +471,8 @@ input_t input() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeInput(void *p) {
|
void
|
||||||
|
freeInput(void *p) {
|
||||||
auto *input = (macos_input_t *) p;
|
auto *input = (macos_input_t *) p;
|
||||||
|
|
||||||
CFRelease(input->source);
|
CFRelease(input->source);
|
||||||
@@ -465,7 +482,8 @@ void freeInput(void *p) {
|
|||||||
delete input;
|
delete input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string_view> &supported_gamepads() {
|
std::vector<std::string_view> &
|
||||||
|
supported_gamepads() {
|
||||||
static std::vector<std::string_view> gamepads { ""sv };
|
static std::vector<std::string_view> gamepads { ""sv };
|
||||||
|
|
||||||
return gamepads;
|
return gamepads;
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ struct av_mic_t : public mic_t {
|
|||||||
[av_audio_capture release];
|
[av_audio_capture release];
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e sample(std::vector<std::int16_t> &sample_in) override {
|
capture_e
|
||||||
|
sample(std::vector<std::int16_t> &sample_in) override {
|
||||||
auto sample_size = sample_in.size();
|
auto sample_size = sample_in.size();
|
||||||
|
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
@@ -40,12 +41,14 @@ struct macos_audio_control_t : public audio_control_t {
|
|||||||
AVCaptureDevice *audio_capture_device;
|
AVCaptureDevice *audio_capture_device;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int set_sink(const std::string &sink) override {
|
int
|
||||||
|
set_sink(const std::string &sink) override {
|
||||||
BOOST_LOG(warning) << "audio_control_t::set_sink() unimplemented: "sv << sink;
|
BOOST_LOG(warning) << "audio_control_t::set_sink() unimplemented: "sv << sink;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<mic_t> microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
std::unique_ptr<mic_t>
|
||||||
|
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
||||||
auto mic = std::make_unique<av_mic_t>();
|
auto mic = std::make_unique<av_mic_t>();
|
||||||
const char *audio_sink = "";
|
const char *audio_sink = "";
|
||||||
|
|
||||||
@@ -74,14 +77,16 @@ public:
|
|||||||
return mic;
|
return mic;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sink_t> sink_info() override {
|
std::optional<sink_t>
|
||||||
|
sink_info() override {
|
||||||
sink_t sink;
|
sink_t sink;
|
||||||
|
|
||||||
return sink;
|
return sink;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<audio_control_t> audio_control() {
|
std::unique_ptr<audio_control_t>
|
||||||
|
audio_control() {
|
||||||
return std::make_unique<macos_audio_control_t>();
|
return std::make_unique<macos_audio_control_t>();
|
||||||
}
|
}
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
namespace dyn {
|
namespace dyn {
|
||||||
typedef void (*apiproc)(void);
|
typedef void (*apiproc)(void);
|
||||||
|
|
||||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
int
|
||||||
void *handle(const std::vector<const char *> &libs);
|
load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
||||||
|
void *
|
||||||
|
handle(const std::vector<const char *> &libs);
|
||||||
|
|
||||||
} // namespace dyn
|
} // namespace dyn
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ namespace platf {
|
|||||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 110000 // __MAC_11_0
|
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 110000 // __MAC_11_0
|
||||||
// If they're not in the SDK then we can use our own function definitions.
|
// If they're not in the SDK then we can use our own function definitions.
|
||||||
// Need to use weak import so that this will link in macOS 10.14 and earlier
|
// Need to use weak import so that this will link in macOS 10.14 and earlier
|
||||||
extern "C" bool CGPreflightScreenCaptureAccess(void) __attribute__((weak_import));
|
extern "C" bool
|
||||||
extern "C" bool CGRequestScreenCaptureAccess(void) __attribute__((weak_import));
|
CGPreflightScreenCaptureAccess(void) __attribute__((weak_import));
|
||||||
|
extern "C" bool
|
||||||
|
CGRequestScreenCaptureAccess(void) __attribute__((weak_import));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> init() {
|
std::unique_ptr<deinit_t>
|
||||||
|
init() {
|
||||||
// This will generate a warning about CGPreflightScreenCaptureAccess and
|
// This will generate a warning about CGPreflightScreenCaptureAccess and
|
||||||
// CGRequestScreenCaptureAccess being unavailable before macOS 10.15, but
|
// CGRequestScreenCaptureAccess being unavailable before macOS 10.15, but
|
||||||
// we have a guard to prevent it from being called on those earlier systems.
|
// we have a guard to prevent it from being called on those earlier systems.
|
||||||
@@ -55,7 +58,8 @@ std::unique_ptr<deinit_t> init() {
|
|||||||
return std::make_unique<deinit_t>();
|
return std::make_unique<deinit_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path appdata() {
|
fs::path
|
||||||
|
appdata() {
|
||||||
const char *homedir;
|
const char *homedir;
|
||||||
if ((homedir = getenv("HOME")) == nullptr) {
|
if ((homedir = getenv("HOME")) == nullptr) {
|
||||||
homedir = getpwuid(geteuid())->pw_dir;
|
homedir = getpwuid(geteuid())->pw_dir;
|
||||||
@@ -66,7 +70,8 @@ fs::path appdata() {
|
|||||||
|
|
||||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||||
|
|
||||||
ifaddr_t get_ifaddrs() {
|
ifaddr_t
|
||||||
|
get_ifaddrs() {
|
||||||
ifaddrs *p { nullptr };
|
ifaddrs *p { nullptr };
|
||||||
|
|
||||||
getifaddrs(&p);
|
getifaddrs(&p);
|
||||||
@@ -74,7 +79,8 @@ ifaddr_t get_ifaddrs() {
|
|||||||
return ifaddr_t { p };
|
return ifaddr_t { p };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string from_sockaddr(const sockaddr *const ip_addr) {
|
std::string
|
||||||
|
from_sockaddr(const sockaddr *const ip_addr) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
@@ -91,7 +97,8 @@ std::string from_sockaddr(const sockaddr *const ip_addr) {
|
|||||||
return std::string { data };
|
return std::string { data };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
|
std::pair<std::uint16_t, std::string>
|
||||||
|
from_sockaddr_ex(const sockaddr *const ip_addr) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
@@ -111,7 +118,8 @@ std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_
|
|||||||
return { port, std::string { data } };
|
return { port, std::string { data } };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mac_address(const std::string_view &address) {
|
std::string
|
||||||
|
get_mac_address(const std::string_view &address) {
|
||||||
auto ifaddrs = get_ifaddrs();
|
auto ifaddrs = get_ifaddrs();
|
||||||
|
|
||||||
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
||||||
@@ -149,7 +157,8 @@ std::string get_mac_address(const std::string_view &address) {
|
|||||||
return "00:00:00:00:00:00"s;
|
return "00:00:00:00:00:00"s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
bp::child
|
||||||
|
run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
||||||
BOOST_LOG(warning) << "run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions."sv;
|
BOOST_LOG(warning) << "run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions."sv;
|
||||||
if (!group) {
|
if (!group) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@@ -169,34 +178,41 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjust_thread_priority(thread_priority_e priority) {
|
void
|
||||||
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_start() {
|
void
|
||||||
|
streaming_will_start() {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_stop() {
|
void
|
||||||
|
streaming_will_stop() {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart_supported() {
|
bool
|
||||||
|
restart_supported() {
|
||||||
// Restart not supported yet
|
// Restart not supported yet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart() {
|
bool
|
||||||
|
restart() {
|
||||||
// Restart not supported yet
|
// Restart not supported yet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool send_batch(batched_send_info_t &send_info) {
|
bool
|
||||||
|
send_batch(batched_send_info_t &send_info) {
|
||||||
// Fall back to unbatched send calls
|
// Fall back to unbatched send calls
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
std::unique_ptr<deinit_t>
|
||||||
|
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
//
|
//
|
||||||
// NB: When implementing, remember to consider that some routes can drop DSCP-tagged packets completely!
|
// NB: When implementing, remember to consider that some routes can drop DSCP-tagged packets completely!
|
||||||
@@ -206,7 +222,8 @@ std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio
|
|||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|
||||||
namespace dyn {
|
namespace dyn {
|
||||||
void *handle(const std::vector<const char *> &libs) {
|
void *
|
||||||
|
handle(const std::vector<const char *> &libs) {
|
||||||
void *handle;
|
void *handle;
|
||||||
|
|
||||||
for (auto lib : libs) {
|
for (auto lib : libs) {
|
||||||
@@ -229,7 +246,8 @@ void *handle(const std::vector<const char *> &libs) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
int
|
||||||
|
load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
for (auto &func : funcs) {
|
for (auto &func : funcs) {
|
||||||
TUPLE_2D_REF(fn, name, func);
|
TUPLE_2D_REF(fn, name, func);
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ extern "C" {
|
|||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
|
|
||||||
void free_frame(AVFrame *frame) {
|
void
|
||||||
|
free_frame(AVFrame *frame) {
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::safe_ptr<AVFrame, free_frame> av_frame;
|
util::safe_ptr<AVFrame, free_frame> av_frame;
|
||||||
|
|
||||||
int nv12_zero_device::convert(platf::img_t &img) {
|
int
|
||||||
|
nv12_zero_device::convert(platf::img_t &img) {
|
||||||
av_frame_make_writable(av_frame.get());
|
av_frame_make_writable(av_frame.get());
|
||||||
|
|
||||||
av_img_t *av_img = (av_img_t *) &img;
|
av_img_t *av_img = (av_img_t *) &img;
|
||||||
@@ -53,7 +55,8 @@ int nv12_zero_device::convert(platf::img_t &img) {
|
|||||||
return result > 0 ? 0 : -1;
|
return result > 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nv12_zero_device::set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
int
|
||||||
|
nv12_zero_device::set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||||
this->frame = frame;
|
this->frame = frame;
|
||||||
|
|
||||||
av_frame.reset(frame);
|
av_frame.reset(frame);
|
||||||
@@ -63,10 +66,12 @@ int nv12_zero_device::set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nv12_zero_device::set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {
|
void
|
||||||
|
nv12_zero_device::set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int nv12_zero_device::init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn) {
|
int
|
||||||
|
nv12_zero_device::init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn) {
|
||||||
pixel_format_fn(display, '420v');
|
pixel_format_fn(display, '420v');
|
||||||
|
|
||||||
this->display = display;
|
this->display = display;
|
||||||
|
|||||||
@@ -17,11 +17,15 @@ public:
|
|||||||
resolution_fn_t resolution_fn;
|
resolution_fn_t resolution_fn;
|
||||||
using pixel_format_fn_t = std::function<void(void *display, int pixelFormat)>;
|
using pixel_format_fn_t = std::function<void(void *display, int pixelFormat)>;
|
||||||
|
|
||||||
int init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn);
|
int
|
||||||
|
init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn);
|
||||||
|
|
||||||
int convert(img_t &img);
|
int
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx);
|
convert(img_t &img);
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx);
|
||||||
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ simple_poll_quit_fn simple_poll_quit;
|
|||||||
simple_poll_new_fn simple_poll_new;
|
simple_poll_new_fn simple_poll_new;
|
||||||
simple_poll_free_fn simple_poll_free;
|
simple_poll_free_fn simple_poll_free;
|
||||||
|
|
||||||
|
int
|
||||||
int init_common() {
|
init_common() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -229,7 +229,8 @@ int init_common() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_client() {
|
int
|
||||||
|
init_client() {
|
||||||
if (init_common()) {
|
if (init_common()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -270,7 +271,8 @@ int init_client() {
|
|||||||
namespace platf::publish {
|
namespace platf::publish {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void free(T *p) {
|
void
|
||||||
|
free(T *p) {
|
||||||
avahi::free(p);
|
avahi::free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +288,11 @@ client_t client;
|
|||||||
|
|
||||||
ptr_t<char> name;
|
ptr_t<char> name;
|
||||||
|
|
||||||
void create_services(avahi::Client *c);
|
void
|
||||||
|
create_services(avahi::Client *c);
|
||||||
|
|
||||||
void entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, void *) {
|
void
|
||||||
|
entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, void *) {
|
||||||
group = g;
|
group = g;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -311,7 +315,8 @@ void entry_group_callback(avahi::EntryGroup *g, avahi::EntryGroupState state, vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_services(avahi::Client *c) {
|
void
|
||||||
|
create_services(avahi::Client *c) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
auto fg = util::fail_guard([]() {
|
auto fg = util::fail_guard([]() {
|
||||||
@@ -366,7 +371,8 @@ void create_services(avahi::Client *c) {
|
|||||||
fg.disable();
|
fg.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
void
|
||||||
|
client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case avahi::CLIENT_S_RUNNING:
|
case avahi::CLIENT_S_RUNNING:
|
||||||
create_services(c);
|
create_services(c);
|
||||||
@@ -388,7 +394,8 @@ class deinit_t : public ::platf::deinit_t {
|
|||||||
public:
|
public:
|
||||||
std::thread poll_thread;
|
std::thread poll_thread;
|
||||||
|
|
||||||
deinit_t(std::thread poll_thread) : poll_thread { std::move(poll_thread) } {}
|
deinit_t(std::thread poll_thread):
|
||||||
|
poll_thread { std::move(poll_thread) } {}
|
||||||
|
|
||||||
~deinit_t() override {
|
~deinit_t() override {
|
||||||
if (avahi::simple_poll_quit && poll) {
|
if (avahi::simple_poll_quit && poll) {
|
||||||
@@ -401,7 +408,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<::platf::deinit_t> start() {
|
[[nodiscard]] std::unique_ptr<::platf::deinit_t>
|
||||||
|
start() {
|
||||||
if (avahi::init_client()) {
|
if (avahi::init_client()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
// http://eretik.omegahg.com/
|
// http://eretik.omegahg.com/
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
@@ -39,11 +38,13 @@ class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
interface IPolicyConfig: public IUnknown {
|
interface IPolicyConfig: public IUnknown {
|
||||||
public:
|
public:
|
||||||
virtual HRESULT GetMixFormat(
|
virtual HRESULT
|
||||||
|
GetMixFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
WAVEFORMATEX **);
|
WAVEFORMATEX **);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetDeviceFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
INT,
|
INT,
|
||||||
WAVEFORMATEX **);
|
WAVEFORMATEX **);
|
||||||
@@ -51,7 +52,8 @@ public:
|
|||||||
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
||||||
PCWSTR);
|
PCWSTR);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetDeviceFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
WAVEFORMATEX *,
|
WAVEFORMATEX *,
|
||||||
WAVEFORMATEX *);
|
WAVEFORMATEX *);
|
||||||
@@ -66,25 +68,30 @@ public:
|
|||||||
PCWSTR,
|
PCWSTR,
|
||||||
PINT64);
|
PINT64);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetShareMode(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
struct DeviceShareMode *);
|
struct DeviceShareMode *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetShareMode(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
struct DeviceShareMode *);
|
struct DeviceShareMode *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetPropertyValue(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
const PROPERTYKEY &,
|
const PROPERTYKEY &,
|
||||||
PROPVARIANT *);
|
PROPVARIANT *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetPropertyValue(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
const PROPERTYKEY &,
|
const PROPERTYKEY &,
|
||||||
PROPVARIANT *);
|
PROPVARIANT *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetDefaultEndpoint(
|
||||||
PCWSTR wszDeviceId,
|
PCWSTR wszDeviceId,
|
||||||
ERole eRole);
|
ERole eRole);
|
||||||
|
|
||||||
@@ -110,16 +117,19 @@ class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") CPolicyConfigVistaCl
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
interface IPolicyConfigVista: public IUnknown {
|
interface IPolicyConfigVista: public IUnknown {
|
||||||
public:
|
public:
|
||||||
virtual HRESULT GetMixFormat(
|
virtual HRESULT
|
||||||
|
GetMixFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
WAVEFORMATEX **); // not available on Windows 7, use method from IPolicyConfig
|
WAVEFORMATEX **); // not available on Windows 7, use method from IPolicyConfig
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetDeviceFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
INT,
|
INT,
|
||||||
WAVEFORMATEX **);
|
WAVEFORMATEX **);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetDeviceFormat(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
WAVEFORMATEX *,
|
WAVEFORMATEX *,
|
||||||
WAVEFORMATEX *);
|
WAVEFORMATEX *);
|
||||||
@@ -134,25 +144,30 @@ public:
|
|||||||
PCWSTR,
|
PCWSTR,
|
||||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetShareMode(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetShareMode(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
GetPropertyValue(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
const PROPERTYKEY &,
|
const PROPERTYKEY &,
|
||||||
PROPVARIANT *);
|
PROPVARIANT *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetPropertyValue(
|
||||||
PCWSTR,
|
PCWSTR,
|
||||||
const PROPERTYKEY &,
|
const PROPERTYKEY &,
|
||||||
PROPVARIANT *);
|
PROPVARIANT *);
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
virtual HRESULT STDMETHODCALLTYPE
|
||||||
|
SetDefaultEndpoint(
|
||||||
PCWSTR wszDeviceId,
|
PCWSTR wszDeviceId,
|
||||||
ERole eRole);
|
ERole eRole);
|
||||||
|
|
||||||
|
|||||||
@@ -37,12 +37,14 @@ namespace platf::audio {
|
|||||||
constexpr auto SAMPLE_RATE = 48000;
|
constexpr auto SAMPLE_RATE = 48000;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Release(T *p) {
|
void
|
||||||
|
Release(T *p) {
|
||||||
p->Release();
|
p->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void co_task_free(T *p) {
|
void
|
||||||
|
co_task_free(T *p) {
|
||||||
CoTaskMemFree((LPVOID) p);
|
CoTaskMemFree((LPVOID) p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +140,8 @@ static format_t surround_51_side_speakers {
|
|||||||
SPEAKER_SIDE_RIGHT,
|
SPEAKER_SIDE_RIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
WAVEFORMATEXTENSIBLE create_wave_format(const format_t &format) {
|
WAVEFORMATEXTENSIBLE
|
||||||
|
create_wave_format(const format_t &format) {
|
||||||
WAVEFORMATEXTENSIBLE wave_format;
|
WAVEFORMATEXTENSIBLE wave_format;
|
||||||
|
|
||||||
wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||||
@@ -156,7 +159,8 @@ WAVEFORMATEXTENSIBLE create_wave_format(const format_t &format) {
|
|||||||
return wave_format;
|
return wave_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
int
|
||||||
|
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
||||||
wave_format->nSamplesPerSec = SAMPLE_RATE;
|
wave_format->nSamplesPerSec = SAMPLE_RATE;
|
||||||
wave_format->wBitsPerSample = 16;
|
wave_format->wBitsPerSample = 16;
|
||||||
|
|
||||||
@@ -184,7 +188,8 @@ int set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
audio_client_t
|
||||||
|
make_audio_client(device_t &device, const format_t &format) {
|
||||||
audio_client_t audio_client;
|
audio_client_t audio_client;
|
||||||
auto status = device->Activate(
|
auto status = device->Activate(
|
||||||
IID_IAudioClient,
|
IID_IAudioClient,
|
||||||
@@ -216,11 +221,13 @@ audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
|||||||
return audio_client;
|
return audio_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *no_null(const wchar_t *str) {
|
const wchar_t *
|
||||||
|
no_null(const wchar_t *str) {
|
||||||
return str ? str : L"Unknown";
|
return str ? str : L"Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_device(device_t &device) {
|
bool
|
||||||
|
validate_device(device_t &device) {
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
||||||
// Check for any valid format
|
// Check for any valid format
|
||||||
@@ -237,7 +244,8 @@ bool validate_device(device_t &device) {
|
|||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_t default_device(device_enum_t &device_enum) {
|
device_t
|
||||||
|
default_device(device_enum_t &device_enum) {
|
||||||
device_t device;
|
device_t device;
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
status = device_enum->GetDefaultAudioEndpoint(
|
status = device_enum->GetDefaultAudioEndpoint(
|
||||||
@@ -245,7 +253,6 @@ device_t default_device(device_enum_t &device_enum) {
|
|||||||
eConsole,
|
eConsole,
|
||||||
&device);
|
&device);
|
||||||
|
|
||||||
|
|
||||||
if (FAILED(status)) {
|
if (FAILED(status)) {
|
||||||
BOOST_LOG(error) << "Couldn't create audio Device [0x"sv << util::hex(status).to_string_view() << ']';
|
BOOST_LOG(error) << "Couldn't create audio Device [0x"sv << util::hex(status).to_string_view() << ']';
|
||||||
|
|
||||||
@@ -257,7 +264,8 @@ device_t default_device(device_enum_t &device_enum) {
|
|||||||
|
|
||||||
class mic_wasapi_t: public mic_t {
|
class mic_wasapi_t: public mic_t {
|
||||||
public:
|
public:
|
||||||
capture_e sample(std::vector<std::int16_t> &sample_out) override {
|
capture_e
|
||||||
|
sample(std::vector<std::int16_t> &sample_out) override {
|
||||||
auto sample_size = sample_out.size();
|
auto sample_size = sample_out.size();
|
||||||
|
|
||||||
// Refill the sample buffer if needed
|
// Refill the sample buffer if needed
|
||||||
@@ -278,8 +286,8 @@ public:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
int init(std::uint32_t sample_rate, std::uint32_t frame_size, std::uint32_t channels_out) {
|
init(std::uint32_t sample_rate, std::uint32_t frame_size, std::uint32_t channels_out) {
|
||||||
audio_event.reset(CreateEventA(nullptr, FALSE, FALSE, nullptr));
|
audio_event.reset(CreateEventA(nullptr, FALSE, FALSE, nullptr));
|
||||||
if (!audio_event) {
|
if (!audio_event) {
|
||||||
BOOST_LOG(error) << "Couldn't create Event handle"sv;
|
BOOST_LOG(error) << "Couldn't create Event handle"sv;
|
||||||
@@ -375,7 +383,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
capture_e _fill_buffer() {
|
capture_e
|
||||||
|
_fill_buffer() {
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
|
|
||||||
// Total number of samples
|
// Total number of samples
|
||||||
@@ -465,7 +474,8 @@ public:
|
|||||||
|
|
||||||
class audio_control_t: public ::platf::audio_control_t {
|
class audio_control_t: public ::platf::audio_control_t {
|
||||||
public:
|
public:
|
||||||
std::optional<sink_t> sink_info() override {
|
std::optional<sink_t>
|
||||||
|
sink_info() override {
|
||||||
auto virtual_adapter_name = L"Steam Streaming Speakers"sv;
|
auto virtual_adapter_name = L"Steam Streaming Speakers"sv;
|
||||||
|
|
||||||
sink_t sink;
|
sink_t sink;
|
||||||
@@ -553,7 +563,8 @@ public:
|
|||||||
return sink;
|
return sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<mic_t> microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
std::unique_ptr<mic_t>
|
||||||
|
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override {
|
||||||
auto mic = std::make_unique<mic_wasapi_t>();
|
auto mic = std::make_unique<mic_wasapi_t>();
|
||||||
|
|
||||||
if (mic->init(sample_rate, frame_size, channels)) {
|
if (mic->init(sample_rate, frame_size, channels)) {
|
||||||
@@ -571,7 +582,8 @@ public:
|
|||||||
* virtual-(format name)
|
* virtual-(format name)
|
||||||
* If it doesn't contain that prefix, then the format will not be changed
|
* If it doesn't contain that prefix, then the format will not be changed
|
||||||
*/
|
*/
|
||||||
std::optional<std::wstring> set_format(const std::string &sink) {
|
std::optional<std::wstring>
|
||||||
|
set_format(const std::string &sink) {
|
||||||
std::string_view sv { sink.c_str(), sink.size() };
|
std::string_view sv { sink.c_str(), sink.size() };
|
||||||
|
|
||||||
format_t::type_e type = format_t::none;
|
format_t::type_e type = format_t::none;
|
||||||
@@ -628,7 +640,8 @@ public:
|
|||||||
return std::make_optional(std::move(wstring_device_id));
|
return std::make_optional(std::move(wstring_device_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_sink(const std::string &sink) override {
|
int
|
||||||
|
set_sink(const std::string &sink) override {
|
||||||
auto wstring_device_id = set_format(sink);
|
auto wstring_device_id = set_format(sink);
|
||||||
if (!wstring_device_id) {
|
if (!wstring_device_id) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -647,7 +660,8 @@ public:
|
|||||||
return failure;
|
return failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
auto status = CoCreateInstance(
|
auto status = CoCreateInstance(
|
||||||
CLSID_CPolicyConfigClient,
|
CLSID_CPolicyConfigClient,
|
||||||
nullptr,
|
nullptr,
|
||||||
@@ -674,10 +688,12 @@ namespace platf {
|
|||||||
|
|
||||||
// It's not big enough to justify it's own source file :/
|
// It's not big enough to justify it's own source file :/
|
||||||
namespace dxgi {
|
namespace dxgi {
|
||||||
int init();
|
int
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<audio_control_t> audio_control() {
|
std::unique_ptr<audio_control_t>
|
||||||
|
audio_control() {
|
||||||
auto control = std::make_unique<audio::audio_control_t>();
|
auto control = std::make_unique<audio::audio_control_t>();
|
||||||
|
|
||||||
if (control->init()) {
|
if (control->init()) {
|
||||||
@@ -687,7 +703,8 @@ std::unique_ptr<audio_control_t> audio_control() {
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> init() {
|
std::unique_ptr<deinit_t>
|
||||||
|
init() {
|
||||||
if (dxgi::init()) {
|
if (dxgi::init()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ extern const char *format_str[];
|
|||||||
auto constexpr D3D11_CREATE_DEVICE_FLAGS = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
auto constexpr D3D11_CREATE_DEVICE_FLAGS = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Release(T *dxgi) {
|
void
|
||||||
|
Release(T *dxgi) {
|
||||||
dxgi->Release();
|
dxgi->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,15 +79,18 @@ struct cursor_t {
|
|||||||
|
|
||||||
class gpu_cursor_t {
|
class gpu_cursor_t {
|
||||||
public:
|
public:
|
||||||
gpu_cursor_t() : cursor_view { 0, 0, 0, 0, 0.0f, 1.0f } {};
|
gpu_cursor_t():
|
||||||
void set_pos(LONG rel_x, LONG rel_y, bool visible) {
|
cursor_view { 0, 0, 0, 0, 0.0f, 1.0f } {};
|
||||||
|
void
|
||||||
|
set_pos(LONG rel_x, LONG rel_y, bool visible) {
|
||||||
cursor_view.TopLeftX = rel_x;
|
cursor_view.TopLeftX = rel_x;
|
||||||
cursor_view.TopLeftY = rel_y;
|
cursor_view.TopLeftY = rel_y;
|
||||||
|
|
||||||
this->visible = visible;
|
this->visible = visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_texture(LONG width, LONG height, texture2d_t &&texture) {
|
void
|
||||||
|
set_texture(LONG width, LONG height, texture2d_t &&texture) {
|
||||||
cursor_view.Width = width;
|
cursor_view.Width = width;
|
||||||
cursor_view.Height = height;
|
cursor_view.Height = height;
|
||||||
|
|
||||||
@@ -107,17 +111,22 @@ public:
|
|||||||
bool has_frame {};
|
bool has_frame {};
|
||||||
bool use_dwmflush {};
|
bool use_dwmflush {};
|
||||||
|
|
||||||
capture_e next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
capture_e
|
||||||
capture_e reset(dup_t::pointer dup_p = dup_t::pointer());
|
next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
||||||
capture_e release_frame();
|
capture_e
|
||||||
|
reset(dup_t::pointer dup_p = dup_t::pointer());
|
||||||
|
capture_e
|
||||||
|
release_frame();
|
||||||
|
|
||||||
~duplication_t();
|
~duplication_t();
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_base_t: public display_t {
|
class display_base_t: public display_t {
|
||||||
public:
|
public:
|
||||||
int init(const ::video::config_t &config, const std::string &display_name);
|
int
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
init(const ::video::config_t &config, const std::string &display_name);
|
||||||
|
capture_e
|
||||||
|
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
||||||
|
|
||||||
std::chrono::nanoseconds delay;
|
std::chrono::nanoseconds delay;
|
||||||
|
|
||||||
@@ -142,34 +151,50 @@ public:
|
|||||||
|
|
||||||
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||||
|
|
||||||
virtual bool is_hdr() override;
|
virtual bool
|
||||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
is_hdr() override;
|
||||||
|
virtual bool
|
||||||
|
get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int get_pixel_pitch() {
|
int
|
||||||
|
get_pixel_pitch() {
|
||||||
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *dxgi_format_to_string(DXGI_FORMAT format);
|
const char *
|
||||||
const char *colorspace_to_string(DXGI_COLOR_SPACE_TYPE type);
|
dxgi_format_to_string(DXGI_FORMAT format);
|
||||||
|
const char *
|
||||||
|
colorspace_to_string(DXGI_COLOR_SPACE_TYPE type);
|
||||||
|
|
||||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
virtual capture_e
|
||||||
virtual int complete_img(img_t *img, bool dummy) = 0;
|
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||||
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
|
virtual int
|
||||||
virtual std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() = 0;
|
complete_img(img_t *img, bool dummy) = 0;
|
||||||
|
virtual std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_sdr_capture_formats() = 0;
|
||||||
|
virtual std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_hdr_capture_formats() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_ram_t: public display_base_t {
|
class display_ram_t: public display_base_t {
|
||||||
public:
|
public:
|
||||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
virtual capture_e
|
||||||
|
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override;
|
std::shared_ptr<img_t>
|
||||||
int dummy_img(img_t *img) override;
|
alloc_img() override;
|
||||||
int complete_img(img_t *img, bool dummy) override;
|
int
|
||||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
dummy_img(img_t *img) override;
|
||||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
int
|
||||||
|
complete_img(img_t *img, bool dummy) override;
|
||||||
|
std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_sdr_capture_formats() override;
|
||||||
|
std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_hdr_capture_formats() override;
|
||||||
|
|
||||||
int init(const ::video::config_t &config, const std::string &display_name);
|
int
|
||||||
|
init(const ::video::config_t &config, const std::string &display_name);
|
||||||
|
|
||||||
cursor_t cursor;
|
cursor_t cursor;
|
||||||
D3D11_MAPPED_SUBRESOURCE img_info;
|
D3D11_MAPPED_SUBRESOURCE img_info;
|
||||||
@@ -178,17 +203,25 @@ public:
|
|||||||
|
|
||||||
class display_vram_t: public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
class display_vram_t: public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
||||||
public:
|
public:
|
||||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
virtual capture_e
|
||||||
|
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override;
|
std::shared_ptr<img_t>
|
||||||
int dummy_img(img_t *img_base) override;
|
alloc_img() override;
|
||||||
int complete_img(img_t *img_base, bool dummy) override;
|
int
|
||||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
dummy_img(img_t *img_base) override;
|
||||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
int
|
||||||
|
complete_img(img_t *img_base, bool dummy) override;
|
||||||
|
std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_sdr_capture_formats() override;
|
||||||
|
std::vector<DXGI_FORMAT>
|
||||||
|
get_supported_hdr_capture_formats() override;
|
||||||
|
|
||||||
int init(const ::video::config_t &config, const std::string &display_name);
|
int
|
||||||
|
init(const ::video::config_t &config, const std::string &display_name);
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override;
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
make_hwdevice(pix_fmt_e pix_fmt) override;
|
||||||
|
|
||||||
sampler_state_t sampler_linear;
|
sampler_state_t sampler_linear;
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ using namespace std::literals;
|
|||||||
namespace platf::dxgi {
|
namespace platf::dxgi {
|
||||||
namespace bp = boost::process;
|
namespace bp = boost::process;
|
||||||
|
|
||||||
capture_e duplication_t::next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p) {
|
capture_e
|
||||||
|
duplication_t::next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p) {
|
||||||
auto capture_status = release_frame();
|
auto capture_status = release_frame();
|
||||||
if (capture_status != capture_e::ok) {
|
if (capture_status != capture_e::ok) {
|
||||||
return capture_status;
|
return capture_status;
|
||||||
@@ -53,7 +54,8 @@ capture_e duplication_t::next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e duplication_t::reset(dup_t::pointer dup_p) {
|
capture_e
|
||||||
|
duplication_t::reset(dup_t::pointer dup_p) {
|
||||||
auto capture_status = release_frame();
|
auto capture_status = release_frame();
|
||||||
|
|
||||||
dup.reset(dup_p);
|
dup.reset(dup_p);
|
||||||
@@ -61,7 +63,8 @@ capture_e duplication_t::reset(dup_t::pointer dup_p) {
|
|||||||
return capture_status;
|
return capture_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e duplication_t::release_frame() {
|
capture_e
|
||||||
|
duplication_t::release_frame() {
|
||||||
if (!has_frame) {
|
if (!has_frame) {
|
||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
@@ -88,7 +91,8 @@ duplication_t::~duplication_t() {
|
|||||||
release_frame();
|
release_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<::platf::img_t> img, bool *cursor) {
|
capture_e
|
||||||
|
display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<::platf::img_t> img, bool *cursor) {
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
auto next_frame = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
|
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
|
||||||
@@ -151,7 +155,8 @@ capture_e display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<:
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_gpu_preference_on_self(int preference) {
|
bool
|
||||||
|
set_gpu_preference_on_self(int preference) {
|
||||||
// The GPU preferences key uses app path as the value name.
|
// The GPU preferences key uses app path as the value name.
|
||||||
WCHAR sunshine_path[MAX_PATH];
|
WCHAR sunshine_path[MAX_PATH];
|
||||||
GetModuleFileNameW(NULL, sunshine_path, ARRAYSIZE(sunshine_path));
|
GetModuleFileNameW(NULL, sunshine_path, ARRAYSIZE(sunshine_path));
|
||||||
@@ -184,7 +189,8 @@ bool set_gpu_preference_on_self(int preference) {
|
|||||||
// (even if you try sneaky stuff like passing the ID3D11Device for the iGPU and the
|
// (even if you try sneaky stuff like passing the ID3D11Device for the iGPU and the
|
||||||
// virtual DXGIOutput from the dGPU). Because the GPU preference is once-per-process,
|
// virtual DXGIOutput from the dGPU). Because the GPU preference is once-per-process,
|
||||||
// we spawn a helper tool to probe for us before we set our own GPU preference.
|
// we spawn a helper tool to probe for us before we set our own GPU preference.
|
||||||
bool probe_for_gpu_preference(const std::string &display_name) {
|
bool
|
||||||
|
probe_for_gpu_preference(const std::string &display_name) {
|
||||||
// If we've already been through here, there's nothing to do this time.
|
// If we've already been through here, there's nothing to do this time.
|
||||||
static bool set_gpu_preference = false;
|
static bool set_gpu_preference = false;
|
||||||
if (set_gpu_preference) {
|
if (set_gpu_preference) {
|
||||||
@@ -235,7 +241,8 @@ bool probe_for_gpu_preference(const std::string &display_name) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool test_dxgi_duplication(adapter_t &adapter, output_t &output) {
|
bool
|
||||||
|
test_dxgi_duplication(adapter_t &adapter, output_t &output) {
|
||||||
D3D_FEATURE_LEVEL featureLevels[] {
|
D3D_FEATURE_LEVEL featureLevels[] {
|
||||||
D3D_FEATURE_LEVEL_11_1,
|
D3D_FEATURE_LEVEL_11_1,
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
D3D_FEATURE_LEVEL_11_0,
|
||||||
@@ -283,7 +290,8 @@ bool test_dxgi_duplication(adapter_t &adapter, output_t &output) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int display_base_t::init(const ::video::config_t &config, const std::string &display_name) {
|
int
|
||||||
|
display_base_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||||
std::once_flag windows_cpp_once_flag;
|
std::once_flag windows_cpp_once_flag;
|
||||||
|
|
||||||
std::call_once(windows_cpp_once_flag, []() {
|
std::call_once(windows_cpp_once_flag, []() {
|
||||||
@@ -588,7 +596,8 @@ int display_base_t::init(const ::video::config_t &config, const std::string &dis
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool display_base_t::is_hdr() {
|
bool
|
||||||
|
display_base_t::is_hdr() {
|
||||||
dxgi::output6_t output6 {};
|
dxgi::output6_t output6 {};
|
||||||
|
|
||||||
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **) &output6);
|
auto status = output->QueryInterface(IID_IDXGIOutput6, (void **) &output6);
|
||||||
@@ -603,7 +612,8 @@ bool display_base_t::is_hdr() {
|
|||||||
return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool display_base_t::get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
bool
|
||||||
|
display_base_t::get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
||||||
dxgi::output6_t output6 {};
|
dxgi::output6_t output6 {};
|
||||||
|
|
||||||
std::memset(&metadata, 0, sizeof(metadata));
|
std::memset(&metadata, 0, sizeof(metadata));
|
||||||
@@ -781,11 +791,13 @@ const char *format_str[] = {
|
|||||||
"DXGI_FORMAT_V408"
|
"DXGI_FORMAT_V408"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *display_base_t::dxgi_format_to_string(DXGI_FORMAT format) {
|
const char *
|
||||||
|
display_base_t::dxgi_format_to_string(DXGI_FORMAT format) {
|
||||||
return format_str[format];
|
return format_str[format];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *display_base_t::colorspace_to_string(DXGI_COLOR_SPACE_TYPE type) {
|
const char *
|
||||||
|
display_base_t::colorspace_to_string(DXGI_COLOR_SPACE_TYPE type) {
|
||||||
const char *type_str[] = {
|
const char *type_str[] = {
|
||||||
"DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709",
|
"DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709",
|
||||||
"DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709",
|
"DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709",
|
||||||
@@ -825,7 +837,8 @@ const char *display_base_t::colorspace_to_string(DXGI_COLOR_SPACE_TYPE type) {
|
|||||||
} // namespace platf::dxgi
|
} // namespace platf::dxgi
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
std::shared_ptr<display_t>
|
||||||
|
display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
|
||||||
if (hwdevice_type == mem_type_e::dxgi) {
|
if (hwdevice_type == mem_type_e::dxgi) {
|
||||||
auto disp = std::make_shared<dxgi::display_vram_t>();
|
auto disp = std::make_shared<dxgi::display_vram_t>();
|
||||||
|
|
||||||
@@ -844,7 +857,8 @@ std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> display_names(mem_type_e) {
|
std::vector<std::string>
|
||||||
|
display_names(mem_type_e) {
|
||||||
std::vector<std::string> display_names;
|
std::vector<std::string> display_names;
|
||||||
|
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ struct img_t : public ::platf::img_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
void
|
||||||
|
blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
||||||
int height = cursor.shape_info.Height / 2;
|
int height = cursor.shape_info.Height / 2;
|
||||||
int width = cursor.shape_info.Width;
|
int width = cursor.shape_info.Width;
|
||||||
int pitch = cursor.shape_info.Pitch;
|
int pitch = cursor.shape_info.Pitch;
|
||||||
@@ -75,7 +76,8 @@ void blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_color_alpha(int *img_pixel_p, int cursor_pixel) {
|
void
|
||||||
|
apply_color_alpha(int *img_pixel_p, int cursor_pixel) {
|
||||||
auto colors_out = (std::uint8_t *) &cursor_pixel;
|
auto colors_out = (std::uint8_t *) &cursor_pixel;
|
||||||
auto colors_in = (std::uint8_t *) img_pixel_p;
|
auto colors_in = (std::uint8_t *) img_pixel_p;
|
||||||
|
|
||||||
@@ -91,7 +93,8 @@ void apply_color_alpha(int *img_pixel_p, int cursor_pixel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_color_masked(int *img_pixel_p, int cursor_pixel) {
|
void
|
||||||
|
apply_color_masked(int *img_pixel_p, int cursor_pixel) {
|
||||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||||
auto alpha = ((std::uint8_t *) &cursor_pixel)[3];
|
auto alpha = ((std::uint8_t *) &cursor_pixel)[3];
|
||||||
if (alpha == 0xFF) {
|
if (alpha == 0xFF) {
|
||||||
@@ -102,7 +105,8 @@ void apply_color_masked(int *img_pixel_p, int cursor_pixel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void blend_cursor_color(const cursor_t &cursor, img_t &img, const bool masked) {
|
void
|
||||||
|
blend_cursor_color(const cursor_t &cursor, img_t &img, const bool masked) {
|
||||||
int height = cursor.shape_info.Height;
|
int height = cursor.shape_info.Height;
|
||||||
int width = cursor.shape_info.Width;
|
int width = cursor.shape_info.Width;
|
||||||
int pitch = cursor.shape_info.Pitch;
|
int pitch = cursor.shape_info.Pitch;
|
||||||
@@ -149,7 +153,8 @@ void blend_cursor_color(const cursor_t &cursor, img_t &img, const bool masked) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void blend_cursor(const cursor_t &cursor, img_t &img) {
|
void
|
||||||
|
blend_cursor(const cursor_t &cursor, img_t &img) {
|
||||||
switch (cursor.shape_info.Type) {
|
switch (cursor.shape_info.Type) {
|
||||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
||||||
blend_cursor_color(cursor, img, false);
|
blend_cursor_color(cursor, img, false);
|
||||||
@@ -165,7 +170,8 @@ void blend_cursor(const cursor_t &cursor, img_t &img) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
capture_e
|
||||||
|
display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
||||||
auto img = (img_t *) img_base;
|
auto img = (img_t *) img_base;
|
||||||
|
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
@@ -301,7 +307,8 @@ capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::millise
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::img_t> display_ram_t::alloc_img() {
|
std::shared_ptr<platf::img_t>
|
||||||
|
display_ram_t::alloc_img() {
|
||||||
auto img = std::make_shared<img_t>();
|
auto img = std::make_shared<img_t>();
|
||||||
|
|
||||||
// Initialize fields that are format-independent
|
// Initialize fields that are format-independent
|
||||||
@@ -311,7 +318,8 @@ std::shared_ptr<platf::img_t> display_ram_t::alloc_img() {
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
int display_ram_t::complete_img(platf::img_t *img, bool dummy) {
|
int
|
||||||
|
display_ram_t::complete_img(platf::img_t *img, bool dummy) {
|
||||||
// If this is not a dummy image, we must know the format by now
|
// If this is not a dummy image, we must know the format by now
|
||||||
if (!dummy && capture_format == DXGI_FORMAT_UNKNOWN) {
|
if (!dummy && capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||||
BOOST_LOG(error) << "display_ram_t::complete_img() called with unknown capture format!";
|
BOOST_LOG(error) << "display_ram_t::complete_img() called with unknown capture format!";
|
||||||
@@ -339,7 +347,8 @@ int display_ram_t::complete_img(platf::img_t *img, bool dummy) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int display_ram_t::dummy_img(platf::img_t *img) {
|
int
|
||||||
|
display_ram_t::dummy_img(platf::img_t *img) {
|
||||||
if (complete_img(img, true)) {
|
if (complete_img(img, true)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -348,16 +357,19 @@ int display_ram_t::dummy_img(platf::img_t *img) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_sdr_capture_formats() {
|
std::vector<DXGI_FORMAT>
|
||||||
|
display_ram_t::get_supported_sdr_capture_formats() {
|
||||||
return { DXGI_FORMAT_B8G8R8A8_UNORM };
|
return { DXGI_FORMAT_B8G8R8A8_UNORM };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_hdr_capture_formats() {
|
std::vector<DXGI_FORMAT>
|
||||||
|
display_ram_t::get_supported_hdr_capture_formats() {
|
||||||
// HDR is unsupported
|
// HDR is unsupported
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
int
|
||||||
|
display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||||
if (display_base_t::init(config, display_name)) {
|
if (display_base_t::init(config, display_name)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ extern "C" {
|
|||||||
#include "src/main.h"
|
#include "src/main.h"
|
||||||
#include "src/video.h"
|
#include "src/video.h"
|
||||||
|
|
||||||
|
|
||||||
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/directx"
|
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/directx"
|
||||||
namespace platf {
|
namespace platf {
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_frame(AVFrame *frame) {
|
static void
|
||||||
|
free_frame(AVFrame *frame) {
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,8 @@ using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
|||||||
namespace platf::dxgi {
|
namespace platf::dxgi {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
buf_t make_buffer(device_t::pointer device, const T &t) {
|
buf_t
|
||||||
|
make_buffer(device_t::pointer device, const T &t) {
|
||||||
static_assert(sizeof(T) % 16 == 0, "Buffer needs to be aligned on a 16-byte alignment");
|
static_assert(sizeof(T) % 16 == 0, "Buffer needs to be aligned on a 16-byte alignment");
|
||||||
|
|
||||||
D3D11_BUFFER_DESC buffer_desc {
|
D3D11_BUFFER_DESC buffer_desc {
|
||||||
@@ -52,7 +53,8 @@ buf_t make_buffer(device_t::pointer device, const T &t) {
|
|||||||
return buf_t { buf_p };
|
return buf_t { buf_p };
|
||||||
}
|
}
|
||||||
|
|
||||||
blend_t make_blend(device_t::pointer device, bool enable, bool invert) {
|
blend_t
|
||||||
|
make_blend(device_t::pointer device, bool enable, bool invert) {
|
||||||
D3D11_BLEND_DESC bdesc {};
|
D3D11_BLEND_DESC bdesc {};
|
||||||
auto &rt = bdesc.RenderTarget[0];
|
auto &rt = bdesc.RenderTarget[0];
|
||||||
rt.BlendEnable = enable;
|
rt.BlendEnable = enable;
|
||||||
@@ -121,7 +123,8 @@ struct img_d3d_t : public platf::img_t {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> make_cursor_xor_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
make_cursor_xor_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info) {
|
||||||
constexpr std::uint32_t inverted = 0xFFFFFFFF;
|
constexpr std::uint32_t inverted = 0xFFFFFFFF;
|
||||||
constexpr std::uint32_t transparent = 0;
|
constexpr std::uint32_t transparent = 0;
|
||||||
|
|
||||||
@@ -191,7 +194,8 @@ util::buffer_t<std::uint8_t> make_cursor_xor_image(const util::buffer_t<std::uin
|
|||||||
return cursor_img;
|
return cursor_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::buffer_t<std::uint8_t> make_cursor_alpha_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info) {
|
util::buffer_t<std::uint8_t>
|
||||||
|
make_cursor_alpha_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info) {
|
||||||
constexpr std::uint32_t black = 0xFF000000;
|
constexpr std::uint32_t black = 0xFF000000;
|
||||||
constexpr std::uint32_t white = 0xFFFFFFFF;
|
constexpr std::uint32_t white = 0xFFFFFFFF;
|
||||||
constexpr std::uint32_t transparent = 0;
|
constexpr std::uint32_t transparent = 0;
|
||||||
@@ -265,7 +269,8 @@ util::buffer_t<std::uint8_t> make_cursor_alpha_image(const util::buffer_t<std::u
|
|||||||
return cursor_img;
|
return cursor_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
blob_t compile_shader(LPCSTR file, LPCSTR entrypoint, LPCSTR shader_model) {
|
blob_t
|
||||||
|
compile_shader(LPCSTR file, LPCSTR entrypoint, LPCSTR shader_model) {
|
||||||
blob_t::pointer msg_p = nullptr;
|
blob_t::pointer msg_p = nullptr;
|
||||||
blob_t::pointer compiled_p;
|
blob_t::pointer compiled_p;
|
||||||
|
|
||||||
@@ -292,17 +297,20 @@ blob_t compile_shader(LPCSTR file, LPCSTR entrypoint, LPCSTR shader_model) {
|
|||||||
return blob_t { compiled_p };
|
return blob_t { compiled_p };
|
||||||
}
|
}
|
||||||
|
|
||||||
blob_t compile_pixel_shader(LPCSTR file) {
|
blob_t
|
||||||
|
compile_pixel_shader(LPCSTR file) {
|
||||||
return compile_shader(file, "main_ps", "ps_5_0");
|
return compile_shader(file, "main_ps", "ps_5_0");
|
||||||
}
|
}
|
||||||
|
|
||||||
blob_t compile_vertex_shader(LPCSTR file) {
|
blob_t
|
||||||
|
compile_vertex_shader(LPCSTR file) {
|
||||||
return compile_shader(file, "main_vs", "vs_5_0");
|
return compile_shader(file, "main_vs", "vs_5_0");
|
||||||
}
|
}
|
||||||
|
|
||||||
class hwdevice_t: public platf::hwdevice_t {
|
class hwdevice_t: public platf::hwdevice_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img_base) override {
|
int
|
||||||
|
convert(platf::img_t &img_base) override {
|
||||||
auto &img = (img_d3d_t &) img_base;
|
auto &img = (img_d3d_t &) img_base;
|
||||||
auto &img_ctx = img_ctx_map[img.id];
|
auto &img_ctx = img_ctx_map[img.id];
|
||||||
|
|
||||||
@@ -341,7 +349,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
||||||
switch (colorspace) {
|
switch (colorspace) {
|
||||||
case 5: // SWS_CS_SMPTE170M
|
case 5: // SWS_CS_SMPTE170M
|
||||||
color_p = &::video::colors[0];
|
color_p = &::video::colors[0];
|
||||||
@@ -373,7 +382,8 @@ public:
|
|||||||
this->color_matrix = std::move(color_matrix);
|
this->color_matrix = std::move(color_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_hwframes(AVHWFramesContext *frames) override {
|
void
|
||||||
|
init_hwframes(AVHWFramesContext *frames) override {
|
||||||
// We may be called with a QSV or D3D11VA context
|
// We may be called with a QSV or D3D11VA context
|
||||||
if (frames->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
|
if (frames->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
|
||||||
auto d3d11_frames = (AVD3D11VAFramesContext *) frames->hwctx;
|
auto d3d11_frames = (AVD3D11VAFramesContext *) frames->hwctx;
|
||||||
@@ -387,7 +397,8 @@ public:
|
|||||||
frames->initial_pool_size = 1;
|
frames->initial_pool_size = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int prepare_to_derive_context(int hw_device_type) override {
|
int
|
||||||
|
prepare_to_derive_context(int hw_device_type) override {
|
||||||
// QuickSync requires our device to be multithread-protected
|
// QuickSync requires our device to be multithread-protected
|
||||||
if (hw_device_type == AV_HWDEVICE_TYPE_QSV) {
|
if (hw_device_type == AV_HWDEVICE_TYPE_QSV) {
|
||||||
multithread_t mt;
|
multithread_t mt;
|
||||||
@@ -404,7 +415,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override {
|
||||||
this->hwframe.reset(frame);
|
this->hwframe.reset(frame);
|
||||||
this->frame = frame;
|
this->frame = frame;
|
||||||
|
|
||||||
@@ -498,10 +510,10 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(
|
int
|
||||||
|
init(
|
||||||
std::shared_ptr<platf::display_t> display, adapter_t::pointer adapter_p,
|
std::shared_ptr<platf::display_t> display, adapter_t::pointer adapter_p,
|
||||||
pix_fmt_e pix_fmt) {
|
pix_fmt_e pix_fmt) {
|
||||||
|
|
||||||
D3D_FEATURE_LEVEL featureLevels[] {
|
D3D_FEATURE_LEVEL featureLevels[] {
|
||||||
D3D_FEATURE_LEVEL_11_1,
|
D3D_FEATURE_LEVEL_11_1,
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
D3D_FEATURE_LEVEL_11_0,
|
||||||
@@ -642,7 +654,8 @@ private:
|
|||||||
shader_res_t encoder_input_res;
|
shader_res_t encoder_input_res;
|
||||||
keyed_mutex_t encoder_mutex;
|
keyed_mutex_t encoder_mutex;
|
||||||
|
|
||||||
void reset() {
|
void
|
||||||
|
reset() {
|
||||||
capture_texture_p = nullptr;
|
capture_texture_p = nullptr;
|
||||||
encoder_texture.reset();
|
encoder_texture.reset();
|
||||||
encoder_input_res.reset();
|
encoder_input_res.reset();
|
||||||
@@ -650,7 +663,8 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int initialize_image_context(const img_d3d_t &img, encoder_img_ctx_t &img_ctx) {
|
int
|
||||||
|
initialize_image_context(const img_d3d_t &img, encoder_img_ctx_t &img_ctx) {
|
||||||
// If we've already opened the shared texture, we're done
|
// If we've already opened the shared texture, we're done
|
||||||
if (img_ctx.encoder_texture && img.capture_texture.get() == img_ctx.capture_texture_p) {
|
if (img_ctx.encoder_texture && img.capture_texture.get() == img_ctx.capture_texture_p) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -733,7 +747,8 @@ public:
|
|||||||
device_ctx_t device_ctx;
|
device_ctx_t device_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::buffer_t<std::uint8_t> &&cursor_img, DXGI_OUTDUPL_POINTER_SHAPE_INFO &shape_info) {
|
bool
|
||||||
|
set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::buffer_t<std::uint8_t> &&cursor_img, DXGI_OUTDUPL_POINTER_SHAPE_INFO &shape_info) {
|
||||||
// This cursor image may not be used
|
// This cursor image may not be used
|
||||||
if (cursor_img.size() == 0) {
|
if (cursor_img.size() == 0) {
|
||||||
cursor.input_res.reset();
|
cursor.input_res.reset();
|
||||||
@@ -777,7 +792,8 @@ bool set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::bu
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
capture_e
|
||||||
|
display_vram_t::snapshot(platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
||||||
auto img = (img_d3d_t *) img_base;
|
auto img = (img_d3d_t *) img_base;
|
||||||
|
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
@@ -965,7 +981,8 @@ capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::millisec
|
|||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int display_vram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
int
|
||||||
|
display_vram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||||
if (display_base_t::init(config, display_name)) {
|
if (display_base_t::init(config, display_name)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1034,7 +1051,8 @@ int display_vram_t::init(const ::video::config_t &config, const std::string &dis
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::img_t> display_vram_t::alloc_img() {
|
std::shared_ptr<platf::img_t>
|
||||||
|
display_vram_t::alloc_img() {
|
||||||
auto img = std::make_shared<img_d3d_t>();
|
auto img = std::make_shared<img_d3d_t>();
|
||||||
|
|
||||||
// Initialize format-independent fields
|
// Initialize format-independent fields
|
||||||
@@ -1047,7 +1065,8 @@ std::shared_ptr<platf::img_t> display_vram_t::alloc_img() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This cannot use ID3D11DeviceContext because it can be called concurrently by the encoding thread
|
// This cannot use ID3D11DeviceContext because it can be called concurrently by the encoding thread
|
||||||
int display_vram_t::complete_img(platf::img_t *img_base, bool dummy) {
|
int
|
||||||
|
display_vram_t::complete_img(platf::img_t *img_base, bool dummy) {
|
||||||
auto img = (img_d3d_t *) img_base;
|
auto img = (img_d3d_t *) img_base;
|
||||||
|
|
||||||
// If this already has a capture texture and it's not switching dummy state, nothing to do
|
// If this already has a capture texture and it's not switching dummy state, nothing to do
|
||||||
@@ -1134,15 +1153,18 @@ int display_vram_t::complete_img(platf::img_t *img_base, bool dummy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This cannot use ID3D11DeviceContext because it can be called concurrently by the encoding thread
|
// This cannot use ID3D11DeviceContext because it can be called concurrently by the encoding thread
|
||||||
int display_vram_t::dummy_img(platf::img_t *img_base) {
|
int
|
||||||
|
display_vram_t::dummy_img(platf::img_t *img_base) {
|
||||||
return complete_img(img_base, true);
|
return complete_img(img_base, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DXGI_FORMAT> display_vram_t::get_supported_sdr_capture_formats() {
|
std::vector<DXGI_FORMAT>
|
||||||
|
display_vram_t::get_supported_sdr_capture_formats() {
|
||||||
return { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM };
|
return { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DXGI_FORMAT> display_vram_t::get_supported_hdr_capture_formats() {
|
std::vector<DXGI_FORMAT>
|
||||||
|
display_vram_t::get_supported_hdr_capture_formats() {
|
||||||
return {
|
return {
|
||||||
// scRGB FP16 is the desired format for HDR content. This will also handle
|
// scRGB FP16 is the desired format for HDR content. This will also handle
|
||||||
// 10-bit SDR displays with the increased precision of FP16 vs 8-bit UNORMs.
|
// 10-bit SDR displays with the increased precision of FP16 vs 8-bit UNORMs.
|
||||||
@@ -1164,7 +1186,8 @@ std::vector<DXGI_FORMAT> display_vram_t::get_supported_hdr_capture_formats() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<platf::hwdevice_t> display_vram_t::make_hwdevice(pix_fmt_e pix_fmt) {
|
std::shared_ptr<platf::hwdevice_t>
|
||||||
|
display_vram_t::make_hwdevice(pix_fmt_e pix_fmt) {
|
||||||
if (pix_fmt != platf::pix_fmt_e::nv12 && pix_fmt != platf::pix_fmt_e::p010) {
|
if (pix_fmt != platf::pix_fmt_e::nv12 && pix_fmt != platf::pix_fmt_e::p010) {
|
||||||
BOOST_LOG(error) << "display_vram_t doesn't support pixel format ["sv << from_pix_fmt(pix_fmt) << ']';
|
BOOST_LOG(error) << "display_vram_t doesn't support pixel format ["sv << from_pix_fmt(pix_fmt) << ']';
|
||||||
|
|
||||||
@@ -1185,7 +1208,8 @@ std::shared_ptr<platf::hwdevice_t> display_vram_t::make_hwdevice(pix_fmt_e pix_f
|
|||||||
return hwdevice;
|
return hwdevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
BOOST_LOG(info) << "Compiling shaders..."sv;
|
BOOST_LOG(info) << "Compiling shaders..."sv;
|
||||||
scene_vs_hlsl = compile_vertex_shader(SUNSHINE_SHADERS_DIR "/SceneVS.hlsl");
|
scene_vs_hlsl = compile_vertex_shader(SUNSHINE_SHADERS_DIR "/SceneVS.hlsl");
|
||||||
if (!scene_vs_hlsl) {
|
if (!scene_vs_hlsl) {
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ constexpr touch_port_t target_touch_port {
|
|||||||
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
||||||
using target_t = util::safe_ptr<_VIGEM_TARGET_T, vigem_target_free>;
|
using target_t = util::safe_ptr<_VIGEM_TARGET_T, vigem_target_free>;
|
||||||
|
|
||||||
static VIGEM_TARGET_TYPE map(const std::string_view &gp) {
|
static VIGEM_TARGET_TYPE
|
||||||
|
map(const std::string_view &gp) {
|
||||||
if (gp == "x360"sv) {
|
if (gp == "x360"sv) {
|
||||||
return Xbox360Wired;
|
return Xbox360Wired;
|
||||||
}
|
}
|
||||||
@@ -30,14 +31,16 @@ static VIGEM_TARGET_TYPE map(const std::string_view &gp) {
|
|||||||
return DualShock4Wired;
|
return DualShock4Wired;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK x360_notify(
|
void CALLBACK
|
||||||
|
x360_notify(
|
||||||
client_t::pointer client,
|
client_t::pointer client,
|
||||||
target_t::pointer target,
|
target_t::pointer target,
|
||||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
std::uint8_t /* led_number */,
|
std::uint8_t /* led_number */,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
void CALLBACK ds4_notify(
|
void CALLBACK
|
||||||
|
ds4_notify(
|
||||||
client_t::pointer client,
|
client_t::pointer client,
|
||||||
target_t::pointer target,
|
target_t::pointer target,
|
||||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
@@ -46,7 +49,8 @@ void CALLBACK ds4_notify(
|
|||||||
|
|
||||||
class vigem_t {
|
class vigem_t {
|
||||||
public:
|
public:
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
VIGEM_ERROR status;
|
VIGEM_ERROR status;
|
||||||
|
|
||||||
client.reset(vigem_alloc());
|
client.reset(vigem_alloc());
|
||||||
@@ -63,7 +67,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad_interal(int nr, rumble_queue_t &rumble_queue, VIGEM_TARGET_TYPE gp_type) {
|
int
|
||||||
|
alloc_gamepad_interal(int nr, rumble_queue_t &rumble_queue, VIGEM_TARGET_TYPE gp_type) {
|
||||||
auto &[rumble, gp] = gamepads[nr];
|
auto &[rumble, gp] = gamepads[nr];
|
||||||
assert(!gp);
|
assert(!gp);
|
||||||
|
|
||||||
@@ -97,7 +102,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_target(int nr) {
|
void
|
||||||
|
free_target(int nr) {
|
||||||
auto &[_, gp] = gamepads[nr];
|
auto &[_, gp] = gamepads[nr];
|
||||||
|
|
||||||
if (gp && vigem_target_is_attached(gp.get())) {
|
if (gp && vigem_target_is_attached(gp.get())) {
|
||||||
@@ -110,7 +116,8 @@ public:
|
|||||||
gp.reset();
|
gp.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rumble(target_t::pointer target, std::uint8_t smallMotor, std::uint8_t largeMotor) {
|
void
|
||||||
|
rumble(target_t::pointer target, std::uint8_t smallMotor, std::uint8_t largeMotor) {
|
||||||
for (int x = 0; x < gamepads.size(); ++x) {
|
for (int x = 0; x < gamepads.size(); ++x) {
|
||||||
auto &[rumble_queue, gp] = gamepads[x];
|
auto &[rumble_queue, gp] = gamepads[x];
|
||||||
|
|
||||||
@@ -142,13 +149,13 @@ public:
|
|||||||
client_t client;
|
client_t client;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CALLBACK x360_notify(
|
void CALLBACK
|
||||||
|
x360_notify(
|
||||||
client_t::pointer client,
|
client_t::pointer client,
|
||||||
target_t::pointer target,
|
target_t::pointer target,
|
||||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
std::uint8_t /* led_number */,
|
std::uint8_t /* led_number */,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||||
<< "smallMotor: "sv << (int) smallMotor;
|
<< "smallMotor: "sv << (int) smallMotor;
|
||||||
@@ -156,13 +163,13 @@ void CALLBACK x360_notify(
|
|||||||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, smallMotor, largeMotor);
|
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, smallMotor, largeMotor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK ds4_notify(
|
void CALLBACK
|
||||||
|
ds4_notify(
|
||||||
client_t::pointer client,
|
client_t::pointer client,
|
||||||
target_t::pointer target,
|
target_t::pointer target,
|
||||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
DS4_LIGHTBAR_COLOR /* led_color */,
|
DS4_LIGHTBAR_COLOR /* led_color */,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||||
<< "smallMotor: "sv << (int) smallMotor;
|
<< "smallMotor: "sv << (int) smallMotor;
|
||||||
@@ -180,7 +187,8 @@ struct input_raw_t {
|
|||||||
HKL active_layout;
|
HKL active_layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
input_t input() {
|
input_t
|
||||||
|
input() {
|
||||||
input_t result { new input_raw_t {} };
|
input_t result { new input_raw_t {} };
|
||||||
auto &raw = *(input_raw_t *) result.get();
|
auto &raw = *(input_raw_t *) result.get();
|
||||||
|
|
||||||
@@ -208,7 +216,8 @@ input_t input() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_input(INPUT &i) {
|
void
|
||||||
|
send_input(INPUT &i) {
|
||||||
retry:
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if (send != 1) {
|
if (send != 1) {
|
||||||
@@ -221,7 +230,8 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
void
|
||||||
|
abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
i.type = INPUT_MOUSE;
|
i.type = INPUT_MOUSE;
|
||||||
@@ -243,7 +253,8 @@ void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y)
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void move_mouse(input_t &input, int deltaX, int deltaY) {
|
void
|
||||||
|
move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
i.type = INPUT_MOUSE;
|
i.type = INPUT_MOUSE;
|
||||||
@@ -256,7 +267,8 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_mouse(input_t &input, int button, bool release) {
|
void
|
||||||
|
button_mouse(input_t &input, int button, bool release) {
|
||||||
constexpr auto KEY_STATE_DOWN = (SHORT) 0x8000;
|
constexpr auto KEY_STATE_DOWN = (SHORT) 0x8000;
|
||||||
|
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
@@ -299,7 +311,8 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scroll(input_t &input, int distance) {
|
void
|
||||||
|
scroll(input_t &input, int distance) {
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
i.type = INPUT_MOUSE;
|
i.type = INPUT_MOUSE;
|
||||||
@@ -311,7 +324,8 @@ void scroll(input_t &input, int distance) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hscroll(input_t &input, int distance) {
|
void
|
||||||
|
hscroll(input_t &input, int distance) {
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
i.type = INPUT_MOUSE;
|
i.type = INPUT_MOUSE;
|
||||||
@@ -323,7 +337,8 @@ void hscroll(input_t &input, int distance) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void keyboard(input_t &input, uint16_t modcode, bool release) {
|
void
|
||||||
|
keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||||
auto raw = (input_raw_t *) input.get();
|
auto raw = (input_raw_t *) input.get();
|
||||||
|
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
@@ -372,7 +387,8 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unicode(input_t &input, char *utf8, int size) {
|
void
|
||||||
|
unicode(input_t &input, char *utf8, int size) {
|
||||||
// We can do no worse than one UTF-16 character per byte of UTF-8
|
// We can do no worse than one UTF-16 character per byte of UTF-8
|
||||||
WCHAR wide[size];
|
WCHAR wide[size];
|
||||||
|
|
||||||
@@ -400,7 +416,8 @@ void unicode(input_t &input, char *utf8, int size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
int
|
||||||
|
alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
||||||
auto raw = (input_raw_t *) input.get();
|
auto raw = (input_raw_t *) input.get();
|
||||||
|
|
||||||
if (!raw->vigem) {
|
if (!raw->vigem) {
|
||||||
@@ -410,7 +427,8 @@ int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {
|
|||||||
return raw->vigem->alloc_gamepad_interal(nr, rumble_queue, map(config::input.gamepad));
|
return raw->vigem->alloc_gamepad_interal(nr, rumble_queue, map(config::input.gamepad));
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_gamepad(input_t &input, int nr) {
|
void
|
||||||
|
free_gamepad(input_t &input, int nr) {
|
||||||
auto raw = (input_raw_t *) input.get();
|
auto raw = (input_raw_t *) input.get();
|
||||||
|
|
||||||
if (!raw->vigem) {
|
if (!raw->vigem) {
|
||||||
@@ -420,13 +438,15 @@ void free_gamepad(input_t &input, int nr) {
|
|||||||
raw->vigem->free_target(nr);
|
raw->vigem->free_target(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VIGEM_ERROR x360_update(client_t::pointer client, target_t::pointer gp, const gamepad_state_t &gamepad_state) {
|
static VIGEM_ERROR
|
||||||
|
x360_update(client_t::pointer client, target_t::pointer gp, const gamepad_state_t &gamepad_state) {
|
||||||
auto &xusb = *(PXUSB_REPORT) &gamepad_state;
|
auto &xusb = *(PXUSB_REPORT) &gamepad_state;
|
||||||
|
|
||||||
return vigem_target_x360_update(client, gp, xusb);
|
return vigem_target_x360_update(client, gp, xusb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DS4_DPAD_DIRECTIONS ds4_dpad(const gamepad_state_t &gamepad_state) {
|
static DS4_DPAD_DIRECTIONS
|
||||||
|
ds4_dpad(const gamepad_state_t &gamepad_state) {
|
||||||
auto flags = gamepad_state.buttonFlags;
|
auto flags = gamepad_state.buttonFlags;
|
||||||
if (flags & DPAD_UP) {
|
if (flags & DPAD_UP) {
|
||||||
if (flags & DPAD_RIGHT) {
|
if (flags & DPAD_RIGHT) {
|
||||||
@@ -463,7 +483,8 @@ static DS4_DPAD_DIRECTIONS ds4_dpad(const gamepad_state_t &gamepad_state) {
|
|||||||
return DS4_BUTTON_DPAD_NONE;
|
return DS4_BUTTON_DPAD_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DS4_BUTTONS ds4_buttons(const gamepad_state_t &gamepad_state) {
|
static DS4_BUTTONS
|
||||||
|
ds4_buttons(const gamepad_state_t &gamepad_state) {
|
||||||
int buttons {};
|
int buttons {};
|
||||||
|
|
||||||
auto flags = gamepad_state.buttonFlags;
|
auto flags = gamepad_state.buttonFlags;
|
||||||
@@ -485,7 +506,8 @@ static DS4_BUTTONS ds4_buttons(const gamepad_state_t &gamepad_state) {
|
|||||||
return (DS4_BUTTONS) buttons;
|
return (DS4_BUTTONS) buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DS4_SPECIAL_BUTTONS ds4_special_buttons(const gamepad_state_t &gamepad_state) {
|
static DS4_SPECIAL_BUTTONS
|
||||||
|
ds4_special_buttons(const gamepad_state_t &gamepad_state) {
|
||||||
int buttons {};
|
int buttons {};
|
||||||
|
|
||||||
if (gamepad_state.buttonFlags & BACK) buttons |= DS4_SPECIAL_BUTTON_TOUCHPAD;
|
if (gamepad_state.buttonFlags & BACK) buttons |= DS4_SPECIAL_BUTTON_TOUCHPAD;
|
||||||
@@ -494,17 +516,20 @@ static DS4_SPECIAL_BUTTONS ds4_special_buttons(const gamepad_state_t &gamepad_st
|
|||||||
return (DS4_SPECIAL_BUTTONS) buttons;
|
return (DS4_SPECIAL_BUTTONS) buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint8_t to_ds4_triggerX(std::int16_t v) {
|
static std::uint8_t
|
||||||
|
to_ds4_triggerX(std::int16_t v) {
|
||||||
return (v + std::numeric_limits<std::uint16_t>::max() / 2 + 1) / 257;
|
return (v + std::numeric_limits<std::uint16_t>::max() / 2 + 1) / 257;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint8_t to_ds4_triggerY(std::int16_t v) {
|
static std::uint8_t
|
||||||
|
to_ds4_triggerY(std::int16_t v) {
|
||||||
auto new_v = -((std::numeric_limits<std::uint16_t>::max() / 2 + v - 1)) / 257;
|
auto new_v = -((std::numeric_limits<std::uint16_t>::max() / 2 + v - 1)) / 257;
|
||||||
|
|
||||||
return new_v == 0 ? 0xFF : (std::uint8_t) new_v;
|
return new_v == 0 ? 0xFF : (std::uint8_t) new_v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VIGEM_ERROR ds4_update(client_t::pointer client, target_t::pointer gp, const gamepad_state_t &gamepad_state) {
|
static VIGEM_ERROR
|
||||||
|
ds4_update(client_t::pointer client, target_t::pointer gp, const gamepad_state_t &gamepad_state) {
|
||||||
DS4_REPORT report;
|
DS4_REPORT report;
|
||||||
|
|
||||||
DS4_REPORT_INIT(&report);
|
DS4_REPORT_INIT(&report);
|
||||||
@@ -524,8 +549,8 @@ static VIGEM_ERROR ds4_update(client_t::pointer client, target_t::pointer gp, co
|
|||||||
return vigem_target_ds4_update(client, gp, report);
|
return vigem_target_ds4_update(client, gp, report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||||
auto vigem = ((input_raw_t *) input.get())->vigem;
|
auto vigem = ((input_raw_t *) input.get())->vigem;
|
||||||
|
|
||||||
// If there is no gamepad support
|
// If there is no gamepad support
|
||||||
@@ -549,13 +574,15 @@ void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeInput(void *p) {
|
void
|
||||||
|
freeInput(void *p) {
|
||||||
auto input = (input_raw_t *) p;
|
auto input = (input_raw_t *) p;
|
||||||
|
|
||||||
delete input;
|
delete input;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string_view> &supported_gamepads() {
|
std::vector<std::string_view> &
|
||||||
|
supported_gamepads() {
|
||||||
// ds4 == ps4
|
// ds4 == ps4
|
||||||
static std::vector<std::string_view> gps {
|
static std::vector<std::string_view> gps {
|
||||||
"x360"sv, "ds4"sv, "ps4"sv
|
"x360"sv, "ds4"sv, "ps4"sv
|
||||||
|
|||||||
@@ -63,13 +63,15 @@ decltype(WlanFreeMemory) *fn_WlanFreeMemory = nullptr;
|
|||||||
decltype(WlanEnumInterfaces) *fn_WlanEnumInterfaces = nullptr;
|
decltype(WlanEnumInterfaces) *fn_WlanEnumInterfaces = nullptr;
|
||||||
decltype(WlanSetInterface) *fn_WlanSetInterface = nullptr;
|
decltype(WlanSetInterface) *fn_WlanSetInterface = nullptr;
|
||||||
|
|
||||||
std::filesystem::path appdata() {
|
std::filesystem::path
|
||||||
|
appdata() {
|
||||||
WCHAR sunshine_path[MAX_PATH];
|
WCHAR sunshine_path[MAX_PATH];
|
||||||
GetModuleFileNameW(NULL, sunshine_path, _countof(sunshine_path));
|
GetModuleFileNameW(NULL, sunshine_path, _countof(sunshine_path));
|
||||||
return std::filesystem::path { sunshine_path }.remove_filename() / L"config"sv;
|
return std::filesystem::path { sunshine_path }.remove_filename() / L"config"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string from_sockaddr(const sockaddr *const socket_address) {
|
std::string
|
||||||
|
from_sockaddr(const sockaddr *const socket_address) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = socket_address->sa_family;
|
auto family = socket_address->sa_family;
|
||||||
@@ -84,7 +86,8 @@ std::string from_sockaddr(const sockaddr *const socket_address) {
|
|||||||
return std::string { data };
|
return std::string { data };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
|
std::pair<std::uint16_t, std::string>
|
||||||
|
from_sockaddr_ex(const sockaddr *const ip_addr) {
|
||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
@@ -102,7 +105,8 @@ std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_
|
|||||||
return { port, std::string { data } };
|
return { port, std::string { data } };
|
||||||
}
|
}
|
||||||
|
|
||||||
adapteraddrs_t get_adapteraddrs() {
|
adapteraddrs_t
|
||||||
|
get_adapteraddrs() {
|
||||||
adapteraddrs_t info { nullptr };
|
adapteraddrs_t info { nullptr };
|
||||||
ULONG size = 0;
|
ULONG size = 0;
|
||||||
|
|
||||||
@@ -113,7 +117,8 @@ adapteraddrs_t get_adapteraddrs() {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mac_address(const std::string_view &address) {
|
std::string
|
||||||
|
get_mac_address(const std::string_view &address) {
|
||||||
adapteraddrs_t info = get_adapteraddrs();
|
adapteraddrs_t info = get_adapteraddrs();
|
||||||
for (auto adapter_pos = info.get(); adapter_pos != nullptr; adapter_pos = adapter_pos->Next) {
|
for (auto adapter_pos = info.get(); adapter_pos != nullptr; adapter_pos = adapter_pos->Next) {
|
||||||
for (auto addr_pos = adapter_pos->FirstUnicastAddress; addr_pos != nullptr; addr_pos = addr_pos->Next) {
|
for (auto addr_pos = adapter_pos->FirstUnicastAddress; addr_pos != nullptr; addr_pos = addr_pos->Next) {
|
||||||
@@ -134,7 +139,8 @@ std::string get_mac_address(const std::string_view &address) {
|
|||||||
return "00:00:00:00:00:00"s;
|
return "00:00:00:00:00:00"s;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDESK syncThreadDesktop() {
|
HDESK
|
||||||
|
syncThreadDesktop() {
|
||||||
auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL);
|
auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL);
|
||||||
if (!hDesk) {
|
if (!hDesk) {
|
||||||
auto err = GetLastError();
|
auto err = GetLastError();
|
||||||
@@ -153,7 +159,8 @@ HDESK syncThreadDesktop() {
|
|||||||
return hDesk;
|
return hDesk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_status(const std::string_view &prefix, HRESULT status) {
|
void
|
||||||
|
print_status(const std::string_view &prefix, HRESULT status) {
|
||||||
char err_string[1024];
|
char err_string[1024];
|
||||||
|
|
||||||
DWORD bytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
DWORD bytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
@@ -167,7 +174,8 @@ void print_status(const std::string_view &prefix, HRESULT status) {
|
|||||||
BOOST_LOG(error) << prefix << ": "sv << std::string_view { err_string, bytes };
|
BOOST_LOG(error) << prefix << ": "sv << std::string_view { err_string, bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring utf8_to_wide_string(const std::string &str) {
|
std::wstring
|
||||||
|
utf8_to_wide_string(const std::string &str) {
|
||||||
// Determine the size required for the destination string
|
// Determine the size required for the destination string
|
||||||
int chars = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), NULL, 0);
|
int chars = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), NULL, 0);
|
||||||
|
|
||||||
@@ -179,7 +187,8 @@ std::wstring utf8_to_wide_string(const std::string &str) {
|
|||||||
return std::wstring(buffer, chars);
|
return std::wstring(buffer, chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string wide_to_utf8_string(const std::wstring &str) {
|
std::string
|
||||||
|
wide_to_utf8_string(const std::wstring &str) {
|
||||||
// Determine the size required for the destination string
|
// Determine the size required for the destination string
|
||||||
int bytes = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.length(), NULL, 0, NULL, NULL);
|
int bytes = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.length(), NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
@@ -191,7 +200,8 @@ std::string wide_to_utf8_string(const std::wstring &str) {
|
|||||||
return std::string(buffer, bytes);
|
return std::string(buffer, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE duplicate_shell_token() {
|
HANDLE
|
||||||
|
duplicate_shell_token() {
|
||||||
// Get the shell window (will usually be owned by explorer.exe)
|
// Get the shell window (will usually be owned by explorer.exe)
|
||||||
HWND shell_window = GetShellWindow();
|
HWND shell_window = GetShellWindow();
|
||||||
if (!shell_window) {
|
if (!shell_window) {
|
||||||
@@ -229,7 +239,8 @@ HANDLE duplicate_shell_token() {
|
|||||||
return new_token;
|
return new_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
PTOKEN_USER get_token_user(HANDLE token) {
|
PTOKEN_USER
|
||||||
|
get_token_user(HANDLE token) {
|
||||||
DWORD return_length;
|
DWORD return_length;
|
||||||
if (GetTokenInformation(token, TokenUser, NULL, 0, &return_length) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
if (GetTokenInformation(token, TokenUser, NULL, 0, &return_length) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
auto winerr = GetLastError();
|
auto winerr = GetLastError();
|
||||||
@@ -252,11 +263,13 @@ PTOKEN_USER get_token_user(HANDLE token) {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_token_user(PTOKEN_USER user) {
|
void
|
||||||
|
free_token_user(PTOKEN_USER user) {
|
||||||
HeapFree(GetProcessHeap(), 0, user);
|
HeapFree(GetProcessHeap(), 0, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_token_same_user_as_process(HANDLE other_token) {
|
bool
|
||||||
|
is_token_same_user_as_process(HANDLE other_token) {
|
||||||
HANDLE process_token;
|
HANDLE process_token;
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) {
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) {
|
||||||
auto winerr = GetLastError();
|
auto winerr = GetLastError();
|
||||||
@@ -284,7 +297,8 @@ bool is_token_same_user_as_process(HANDLE other_token) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool merge_user_environment_block(bp::environment &env, HANDLE shell_token) {
|
bool
|
||||||
|
merge_user_environment_block(bp::environment &env, HANDLE shell_token) {
|
||||||
// Get the target user's environment block
|
// Get the target user's environment block
|
||||||
PVOID env_block;
|
PVOID env_block;
|
||||||
if (!CreateEnvironmentBlock(&env_block, shell_token, FALSE)) {
|
if (!CreateEnvironmentBlock(&env_block, shell_token, FALSE)) {
|
||||||
@@ -321,12 +335,14 @@ bool merge_user_environment_block(bp::environment &env, HANDLE shell_token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: This does NOT append a null terminator
|
// Note: This does NOT append a null terminator
|
||||||
void append_string_to_environment_block(wchar_t *env_block, int &offset, const std::wstring &wstr) {
|
void
|
||||||
|
append_string_to_environment_block(wchar_t *env_block, int &offset, const std::wstring &wstr) {
|
||||||
std::memcpy(&env_block[offset], wstr.data(), wstr.length() * sizeof(wchar_t));
|
std::memcpy(&env_block[offset], wstr.data(), wstr.length() * sizeof(wchar_t));
|
||||||
offset += wstr.length();
|
offset += wstr.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring create_environment_block(bp::environment &env) {
|
std::wstring
|
||||||
|
create_environment_block(bp::environment &env) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
for (const auto &entry : env) {
|
for (const auto &entry : env) {
|
||||||
auto name = entry.get_name();
|
auto name = entry.get_name();
|
||||||
@@ -355,7 +371,8 @@ std::wstring create_environment_block(bp::environment &env) {
|
|||||||
return std::wstring(env_block, offset);
|
return std::wstring(env_block, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
LPPROC_THREAD_ATTRIBUTE_LIST allocate_proc_thread_attr_list(DWORD attribute_count) {
|
LPPROC_THREAD_ATTRIBUTE_LIST
|
||||||
|
allocate_proc_thread_attr_list(DWORD attribute_count) {
|
||||||
SIZE_T size;
|
SIZE_T size;
|
||||||
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
|
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
|
||||||
|
|
||||||
@@ -372,12 +389,14 @@ LPPROC_THREAD_ATTRIBUTE_LIST allocate_proc_thread_attr_list(DWORD attribute_coun
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_proc_thread_attr_list(LPPROC_THREAD_ATTRIBUTE_LIST list) {
|
void
|
||||||
|
free_proc_thread_attr_list(LPPROC_THREAD_ATTRIBUTE_LIST list) {
|
||||||
DeleteProcThreadAttributeList(list);
|
DeleteProcThreadAttributeList(list);
|
||||||
HeapFree(GetProcessHeap(), 0, list);
|
HeapFree(GetProcessHeap(), 0, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
bp::child
|
||||||
|
run_unprivileged(const std::string &cmd, boost::filesystem::path &working_dir, bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
||||||
HANDLE shell_token = duplicate_shell_token();
|
HANDLE shell_token = duplicate_shell_token();
|
||||||
if (!shell_token) {
|
if (!shell_token) {
|
||||||
// This can happen if the shell has crashed. Fail the launch rather than risking launching with
|
// This can happen if the shell has crashed. Fail the launch rather than risking launching with
|
||||||
@@ -542,7 +561,8 @@ bp::child run_unprivileged(const std::string &cmd, boost::filesystem::path &work
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjust_thread_priority(thread_priority_e priority) {
|
void
|
||||||
|
adjust_thread_priority(thread_priority_e priority) {
|
||||||
int win32_priority;
|
int win32_priority;
|
||||||
|
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
@@ -569,7 +589,8 @@ void adjust_thread_priority(thread_priority_e priority) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_start() {
|
void
|
||||||
|
streaming_will_start() {
|
||||||
static std::once_flag load_wlanapi_once_flag;
|
static std::once_flag load_wlanapi_once_flag;
|
||||||
std::call_once(load_wlanapi_once_flag, []() {
|
std::call_once(load_wlanapi_once_flag, []() {
|
||||||
// wlanapi.dll is not installed by default on Windows Server, so we load it dynamically
|
// wlanapi.dll is not installed by default on Windows Server, so we load it dynamically
|
||||||
@@ -671,7 +692,8 @@ void streaming_will_start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void streaming_will_stop() {
|
void
|
||||||
|
streaming_will_stop() {
|
||||||
// Demote ourselves back to normal priority class
|
// Demote ourselves back to normal priority class
|
||||||
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
||||||
|
|
||||||
@@ -697,19 +719,22 @@ void streaming_will_stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart_supported() {
|
bool
|
||||||
|
restart_supported() {
|
||||||
// Restart is supported if we're running from the service
|
// Restart is supported if we're running from the service
|
||||||
return (GetConsoleWindow() == NULL);
|
return (GetConsoleWindow() == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool restart() {
|
bool
|
||||||
|
restart() {
|
||||||
// Raise SIGINT to trigger the graceful exit logic. The service will
|
// Raise SIGINT to trigger the graceful exit logic. The service will
|
||||||
// restart us in a few seconds.
|
// restart us in a few seconds.
|
||||||
std::raise(SIGINT);
|
std::raise(SIGINT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKADDR_IN to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) {
|
SOCKADDR_IN
|
||||||
|
to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) {
|
||||||
SOCKADDR_IN saddr_v4 = {};
|
SOCKADDR_IN saddr_v4 = {};
|
||||||
|
|
||||||
saddr_v4.sin_family = AF_INET;
|
saddr_v4.sin_family = AF_INET;
|
||||||
@@ -721,7 +746,8 @@ SOCKADDR_IN to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) {
|
|||||||
return saddr_v4;
|
return saddr_v4;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKADDR_IN6 to_sockaddr(boost::asio::ip::address_v6 address, uint16_t port) {
|
SOCKADDR_IN6
|
||||||
|
to_sockaddr(boost::asio::ip::address_v6 address, uint16_t port) {
|
||||||
SOCKADDR_IN6 saddr_v6 = {};
|
SOCKADDR_IN6 saddr_v6 = {};
|
||||||
|
|
||||||
saddr_v6.sin6_family = AF_INET6;
|
saddr_v6.sin6_family = AF_INET6;
|
||||||
@@ -736,7 +762,8 @@ SOCKADDR_IN6 to_sockaddr(boost::asio::ip::address_v6 address, uint16_t port) {
|
|||||||
|
|
||||||
// Use UDP segmentation offload if it is supported by the OS. If the NIC is capable, this will use
|
// Use UDP segmentation offload if it is supported by the OS. If the NIC is capable, this will use
|
||||||
// hardware acceleration to reduce CPU usage. Support for USO was introduced in Windows 10 20H1.
|
// hardware acceleration to reduce CPU usage. Support for USO was introduced in Windows 10 20H1.
|
||||||
bool send_batch(batched_send_info_t &send_info) {
|
bool
|
||||||
|
send_batch(batched_send_info_t &send_info) {
|
||||||
WSAMSG msg;
|
WSAMSG msg;
|
||||||
|
|
||||||
// Convert the target address into a SOCKADDR
|
// Convert the target address into a SOCKADDR
|
||||||
@@ -784,7 +811,8 @@ bool send_batch(batched_send_info_t &send_info) {
|
|||||||
|
|
||||||
class qos_t: public deinit_t {
|
class qos_t: public deinit_t {
|
||||||
public:
|
public:
|
||||||
qos_t(QOS_FLOWID flow_id) : flow_id(flow_id) {}
|
qos_t(QOS_FLOWID flow_id):
|
||||||
|
flow_id(flow_id) {}
|
||||||
|
|
||||||
virtual ~qos_t() {
|
virtual ~qos_t() {
|
||||||
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) NULL, flow_id, 0)) {
|
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) NULL, flow_id, 0)) {
|
||||||
@@ -797,7 +825,8 @@ private:
|
|||||||
QOS_FLOWID flow_id;
|
QOS_FLOWID flow_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
std::unique_ptr<deinit_t>
|
||||||
|
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
||||||
SOCKADDR_IN saddr_v4;
|
SOCKADDR_IN saddr_v4;
|
||||||
SOCKADDR_IN6 saddr_v6;
|
SOCKADDR_IN6 saddr_v6;
|
||||||
PSOCKADDR dest_addr;
|
PSOCKADDR dest_addr;
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
|
|
||||||
namespace platf {
|
namespace platf {
|
||||||
void print_status(const std::string_view &prefix, HRESULT status);
|
void
|
||||||
HDESK syncThreadDesktop();
|
print_status(const std::string_view &prefix, HRESULT status);
|
||||||
|
HDESK
|
||||||
|
syncThreadDesktop();
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -59,7 +59,8 @@ typedef struct _DNS_SERVICE_INSTANCE {
|
|||||||
} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE;
|
} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef VOID WINAPI DNS_SERVICE_REGISTER_COMPLETE(
|
typedef VOID WINAPI
|
||||||
|
DNS_SERVICE_REGISTER_COMPLETE(
|
||||||
_In_ DWORD Status,
|
_In_ DWORD Status,
|
||||||
_In_ PVOID pQueryContext,
|
_In_ PVOID pQueryContext,
|
||||||
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||||
@@ -88,7 +89,8 @@ _FN(_DnsServiceRegister, DWORD, (_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest, _I
|
|||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
||||||
namespace platf::publish {
|
namespace platf::publish {
|
||||||
VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
VOID WINAPI
|
||||||
|
register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
||||||
auto alarm = (safe::alarm_t<PDNS_SERVICE_INSTANCE>::element_type *) pQueryContext;
|
auto alarm = (safe::alarm_t<PDNS_SERVICE_INSTANCE>::element_type *) pQueryContext;
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
@@ -98,7 +100,8 @@ VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE
|
|||||||
alarm->ring(pInstance);
|
alarm->ring(pInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) {
|
static int
|
||||||
|
service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) {
|
||||||
auto alarm = safe::make_alarm<PDNS_SERVICE_INSTANCE>();
|
auto alarm = safe::make_alarm<PDNS_SERVICE_INSTANCE>();
|
||||||
|
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
||||||
@@ -154,7 +157,8 @@ static int service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) {
|
|||||||
|
|
||||||
class mdns_registration_t: public ::platf::deinit_t {
|
class mdns_registration_t: public ::platf::deinit_t {
|
||||||
public:
|
public:
|
||||||
mdns_registration_t() : existing_instance(nullptr) {
|
mdns_registration_t():
|
||||||
|
existing_instance(nullptr) {
|
||||||
if (service(true, existing_instance)) {
|
if (service(true, existing_instance)) {
|
||||||
BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv;
|
BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv;
|
||||||
return;
|
return;
|
||||||
@@ -178,7 +182,8 @@ private:
|
|||||||
PDNS_SERVICE_INSTANCE existing_instance;
|
PDNS_SERVICE_INSTANCE existing_instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
int load_funcs(HMODULE handle) {
|
int
|
||||||
|
load_funcs(HMODULE handle) {
|
||||||
auto fg = util::fail_guard([handle]() {
|
auto fg = util::fail_guard([handle]() {
|
||||||
FreeLibrary(handle);
|
FreeLibrary(handle);
|
||||||
});
|
});
|
||||||
@@ -196,7 +201,8 @@ int load_funcs(HMODULE handle) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<::platf::deinit_t> start() {
|
std::unique_ptr<::platf::deinit_t>
|
||||||
|
start() {
|
||||||
HMODULE handle = LoadLibrary("dnsapi.dll");
|
HMODULE handle = LoadLibrary("dnsapi.dll");
|
||||||
|
|
||||||
if (!handle || load_funcs(handle)) {
|
if (!handle || load_funcs(handle)) {
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ namespace pt = boost::property_tree;
|
|||||||
|
|
||||||
proc_t proc;
|
proc_t proc;
|
||||||
|
|
||||||
void process_end(bp::child &proc, bp::group &proc_handle) {
|
void
|
||||||
|
process_end(bp::child &proc, bp::group &proc_handle) {
|
||||||
if (!proc.running()) {
|
if (!proc.running()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,8 @@ void process_end(bp::child &proc, bp::group &proc_handle) {
|
|||||||
proc.wait();
|
proc.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path find_working_directory(const std::string &cmd, bp::environment &env) {
|
boost::filesystem::path
|
||||||
|
find_working_directory(const std::string &cmd, bp::environment &env) {
|
||||||
// Parse the raw command string into parts to get the actual command portion
|
// Parse the raw command string into parts to get the actual command portion
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto parts = boost::program_options::split_winmain(cmd);
|
auto parts = boost::program_options::split_winmain(cmd);
|
||||||
@@ -80,7 +82,8 @@ boost::filesystem::path find_working_directory(const std::string &cmd, bp::envir
|
|||||||
return cmd_path.parent_path();
|
return cmd_path.parent_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_t::execute(int app_id) {
|
int
|
||||||
|
proc_t::execute(int app_id) {
|
||||||
// Ensure starting from a clean slate
|
// Ensure starting from a clean slate
|
||||||
terminate();
|
terminate();
|
||||||
|
|
||||||
@@ -179,7 +182,8 @@ int proc_t::execute(int app_id) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_t::running() {
|
int
|
||||||
|
proc_t::running() {
|
||||||
if (placebo || _process.running()) {
|
if (placebo || _process.running()) {
|
||||||
return _app_id;
|
return _app_id;
|
||||||
}
|
}
|
||||||
@@ -192,7 +196,8 @@ int proc_t::running() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void proc_t::terminate() {
|
void
|
||||||
|
proc_t::terminate() {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
// Ensure child process is terminated
|
// Ensure child process is terminated
|
||||||
@@ -230,10 +235,12 @@ void proc_t::terminate() {
|
|||||||
_pipe.reset();
|
_pipe.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<ctx_t> &proc_t::get_apps() const {
|
const std::vector<ctx_t> &
|
||||||
|
proc_t::get_apps() const {
|
||||||
return _apps;
|
return _apps;
|
||||||
}
|
}
|
||||||
std::vector<ctx_t> &proc_t::get_apps() {
|
std::vector<ctx_t> &
|
||||||
|
proc_t::get_apps() {
|
||||||
return _apps;
|
return _apps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +248,8 @@ std::vector<ctx_t> &proc_t::get_apps() {
|
|||||||
// Returns image from assets directory if found there.
|
// Returns image from assets directory if found there.
|
||||||
// Returns default image if image configuration is not set.
|
// Returns default image if image configuration is not set.
|
||||||
// Returns http content-type header compatible image type.
|
// Returns http content-type header compatible image type.
|
||||||
std::string proc_t::get_app_image(int app_id) {
|
std::string
|
||||||
|
proc_t::get_app_image(int app_id) {
|
||||||
auto iter = std::find_if(_apps.begin(), _apps.end(), [&app_id](const auto app) {
|
auto iter = std::find_if(_apps.begin(), _apps.end(), [&app_id](const auto app) {
|
||||||
return app.id == std::to_string(app_id);
|
return app.id == std::to_string(app_id);
|
||||||
});
|
});
|
||||||
@@ -254,7 +262,8 @@ proc_t::~proc_t() {
|
|||||||
terminate();
|
terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view::iterator find_match(std::string_view::iterator begin, std::string_view::iterator end) {
|
std::string_view::iterator
|
||||||
|
find_match(std::string_view::iterator begin, std::string_view::iterator end) {
|
||||||
int stack = 0;
|
int stack = 0;
|
||||||
|
|
||||||
--begin;
|
--begin;
|
||||||
@@ -275,7 +284,8 @@ std::string_view::iterator find_match(std::string_view::iterator begin, std::str
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parse_env_val(bp::native_environment &env, const std::string_view &val_raw) {
|
std::string
|
||||||
|
parse_env_val(bp::native_environment &env, const std::string_view &val_raw) {
|
||||||
auto pos = std::begin(val_raw);
|
auto pos = std::begin(val_raw);
|
||||||
auto dollar = std::find(pos, std::end(val_raw), '$');
|
auto dollar = std::find(pos, std::end(val_raw), '$');
|
||||||
|
|
||||||
@@ -329,7 +339,8 @@ std::string parse_env_val(bp::native_environment &env, const std::string_view &v
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string validate_app_image_path(std::string app_image_path) {
|
std::string
|
||||||
|
validate_app_image_path(std::string app_image_path) {
|
||||||
if (app_image_path.empty()) {
|
if (app_image_path.empty()) {
|
||||||
return DEFAULT_APP_IMAGE_PATH;
|
return DEFAULT_APP_IMAGE_PATH;
|
||||||
}
|
}
|
||||||
@@ -366,7 +377,8 @@ std::string validate_app_image_path(std::string app_image_path) {
|
|||||||
return app_image_path;
|
return app_image_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> calculate_sha256(const std::string &filename) {
|
std::optional<std::string>
|
||||||
|
calculate_sha256(const std::string &filename) {
|
||||||
crypto::md_ctx_t ctx { EVP_MD_CTX_create() };
|
crypto::md_ctx_t ctx { EVP_MD_CTX_create() };
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -401,13 +413,15 @@ std::optional<std::string> calculate_sha256(const std::string &filename) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t calculate_crc32(const std::string &input) {
|
uint32_t
|
||||||
|
calculate_crc32(const std::string &input) {
|
||||||
boost::crc_32_type result;
|
boost::crc_32_type result;
|
||||||
result.process_bytes(input.data(), input.length());
|
result.process_bytes(input.data(), input.length());
|
||||||
return result.checksum();
|
return result.checksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, std::string> calculate_app_id(const std::string &app_name, std::string app_image_path, int index) {
|
std::tuple<std::string, std::string>
|
||||||
|
calculate_app_id(const std::string &app_name, std::string app_image_path, int index) {
|
||||||
// Generate id by hashing name with image data if present
|
// Generate id by hashing name with image data if present
|
||||||
std::vector<std::string> to_hash;
|
std::vector<std::string> to_hash;
|
||||||
to_hash.push_back(app_name);
|
to_hash.push_back(app_name);
|
||||||
@@ -437,7 +451,8 @@ std::tuple<std::string, std::string> calculate_app_id(const std::string &app_nam
|
|||||||
return std::make_tuple(id_no_index, id_with_index);
|
return std::make_tuple(id_no_index, id_with_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<proc::proc_t> parse(const std::string &file_name) {
|
std::optional<proc::proc_t>
|
||||||
|
parse(const std::string &file_name) {
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -550,7 +565,8 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh(const std::string &file_name) {
|
void
|
||||||
|
refresh(const std::string &file_name) {
|
||||||
auto proc_opt = proc::parse(file_name);
|
auto proc_opt = proc::parse(file_name);
|
||||||
|
|
||||||
if (proc_opt) {
|
if (proc_opt) {
|
||||||
|
|||||||
@@ -56,24 +56,31 @@ public:
|
|||||||
|
|
||||||
proc_t(
|
proc_t(
|
||||||
boost::process::environment &&env,
|
boost::process::environment &&env,
|
||||||
std::vector<ctx_t> &&apps) : _app_id(0),
|
std::vector<ctx_t> &&apps):
|
||||||
|
_app_id(0),
|
||||||
_env(std::move(env)),
|
_env(std::move(env)),
|
||||||
_apps(std::move(apps)) {}
|
_apps(std::move(apps)) {}
|
||||||
|
|
||||||
int execute(int app_id);
|
int
|
||||||
|
execute(int app_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return _app_id if a process is running, otherwise returns 0
|
* @return _app_id if a process is running, otherwise returns 0
|
||||||
*/
|
*/
|
||||||
int running();
|
int
|
||||||
|
running();
|
||||||
|
|
||||||
~proc_t();
|
~proc_t();
|
||||||
|
|
||||||
const std::vector<ctx_t> &get_apps() const;
|
const std::vector<ctx_t> &
|
||||||
std::vector<ctx_t> &get_apps();
|
get_apps() const;
|
||||||
std::string get_app_image(int app_id);
|
std::vector<ctx_t> &
|
||||||
|
get_apps();
|
||||||
|
std::string
|
||||||
|
get_app_image(int app_id);
|
||||||
|
|
||||||
void terminate();
|
void
|
||||||
|
terminate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _app_id;
|
int _app_id;
|
||||||
@@ -97,11 +104,15 @@ private:
|
|||||||
* Calculate a stable id based on name and image data
|
* Calculate a stable id based on name and image data
|
||||||
* @return tuple of id calculated without index (for use if no collision) and one with
|
* @return tuple of id calculated without index (for use if no collision) and one with
|
||||||
*/
|
*/
|
||||||
std::tuple<std::string, std::string> calculate_app_id(const std::string &app_name, std::string app_image_path, int index);
|
std::tuple<std::string, std::string>
|
||||||
|
calculate_app_id(const std::string &app_name, std::string app_image_path, int index);
|
||||||
|
|
||||||
std::string validate_app_image_path(std::string app_image_path);
|
std::string
|
||||||
void refresh(const std::string &file_name);
|
validate_app_image_path(std::string app_image_path);
|
||||||
std::optional<proc::proc_t> parse(const std::string &file_name);
|
void
|
||||||
|
refresh(const std::string &file_name);
|
||||||
|
std::optional<proc::proc_t>
|
||||||
|
parse(const std::string &file_name);
|
||||||
|
|
||||||
extern proc_t proc;
|
extern proc_t proc;
|
||||||
} // namespace proc
|
} // namespace proc
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public:
|
|||||||
typedef T iterator;
|
typedef T iterator;
|
||||||
typedef std::ptrdiff_t diff_t;
|
typedef std::ptrdiff_t diff_t;
|
||||||
|
|
||||||
iterator operator+=(diff_t step) {
|
iterator
|
||||||
|
operator+=(diff_t step) {
|
||||||
while (step-- > 0) {
|
while (step-- > 0) {
|
||||||
++_this();
|
++_this();
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,8 @@ public:
|
|||||||
return _this();
|
return _this();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator-=(diff_t step) {
|
iterator
|
||||||
|
operator-=(diff_t step) {
|
||||||
while (step-- > 0) {
|
while (step-- > 0) {
|
||||||
--_this();
|
--_this();
|
||||||
}
|
}
|
||||||
@@ -32,19 +34,22 @@ public:
|
|||||||
return _this();
|
return _this();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator+(diff_t step) {
|
iterator
|
||||||
|
operator+(diff_t step) {
|
||||||
iterator new_ = _this();
|
iterator new_ = _this();
|
||||||
|
|
||||||
return new_ += step;
|
return new_ += step;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator-(diff_t step) {
|
iterator
|
||||||
|
operator-(diff_t step) {
|
||||||
iterator new_ = _this();
|
iterator new_ = _this();
|
||||||
|
|
||||||
return new_ -= step;
|
return new_ -= step;
|
||||||
}
|
}
|
||||||
|
|
||||||
diff_t operator-(iterator first) {
|
diff_t
|
||||||
|
operator-(iterator first) {
|
||||||
diff_t step = 0;
|
diff_t step = 0;
|
||||||
while (first != _this()) {
|
while (first != _this()) {
|
||||||
++step;
|
++step;
|
||||||
@@ -54,16 +59,19 @@ public:
|
|||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator++() {
|
iterator
|
||||||
|
operator++() {
|
||||||
_this().inc();
|
_this().inc();
|
||||||
return _this();
|
return _this();
|
||||||
}
|
}
|
||||||
iterator operator--() {
|
iterator
|
||||||
|
operator--() {
|
||||||
_this().dec();
|
_this().dec();
|
||||||
return _this();
|
return _this();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator++(int) {
|
iterator
|
||||||
|
operator++(int) {
|
||||||
iterator new_ = _this();
|
iterator new_ = _this();
|
||||||
|
|
||||||
++_this();
|
++_this();
|
||||||
@@ -71,7 +79,8 @@ public:
|
|||||||
return new_;
|
return new_;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator--(int) {
|
iterator
|
||||||
|
operator--(int) {
|
||||||
iterator new_ = _this();
|
iterator new_ = _this();
|
||||||
|
|
||||||
--_this();
|
--_this();
|
||||||
@@ -79,34 +88,46 @@ public:
|
|||||||
return new_;
|
return new_;
|
||||||
}
|
}
|
||||||
|
|
||||||
reference operator*() { return *_this().get(); }
|
reference
|
||||||
const reference operator*() const { return *_this().get(); }
|
operator*() { return *_this().get(); }
|
||||||
|
const reference
|
||||||
|
operator*() const { return *_this().get(); }
|
||||||
|
|
||||||
pointer operator->() { return &*_this(); }
|
pointer
|
||||||
const pointer operator->() const { return &*_this(); }
|
operator->() { return &*_this(); }
|
||||||
|
const pointer
|
||||||
|
operator->() const { return &*_this(); }
|
||||||
|
|
||||||
bool operator!=(const iterator &other) const {
|
bool
|
||||||
|
operator!=(const iterator &other) const {
|
||||||
return !(_this() == other);
|
return !(_this() == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const iterator &other) const {
|
bool
|
||||||
|
operator<(const iterator &other) const {
|
||||||
return !(_this() >= other);
|
return !(_this() >= other);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator>=(const iterator &other) const {
|
bool
|
||||||
|
operator>=(const iterator &other) const {
|
||||||
return _this() == other || _this() > other;
|
return _this() == other || _this() > other;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<=(const iterator &other) const {
|
bool
|
||||||
|
operator<=(const iterator &other) const {
|
||||||
return _this() == other || _this() < other;
|
return _this() == other || _this() < other;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const iterator &other) const { return _this().eq(other); };
|
bool
|
||||||
bool operator>(const iterator &other) const { return _this().gt(other); }
|
operator==(const iterator &other) const { return _this().eq(other); };
|
||||||
|
bool
|
||||||
|
operator>(const iterator &other) const { return _this().gt(other); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iterator &_this() { return *static_cast<iterator *>(this); }
|
iterator &
|
||||||
const iterator &_this() const { return *static_cast<const iterator *>(this); }
|
_this() { return *static_cast<iterator *>(this); }
|
||||||
|
const iterator &
|
||||||
|
_this() const { return *static_cast<const iterator *>(this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class V, class It>
|
template <class V, class It>
|
||||||
@@ -115,9 +136,11 @@ public:
|
|||||||
using iterator = It;
|
using iterator = It;
|
||||||
using pointer = V *;
|
using pointer = V *;
|
||||||
|
|
||||||
round_robin_t(iterator begin, iterator end) : _begin(begin), _end(end), _pos(begin) {}
|
round_robin_t(iterator begin, iterator end):
|
||||||
|
_begin(begin), _end(end), _pos(begin) {}
|
||||||
|
|
||||||
void inc() {
|
void
|
||||||
|
inc() {
|
||||||
++_pos;
|
++_pos;
|
||||||
|
|
||||||
if (_pos == _end) {
|
if (_pos == _end) {
|
||||||
@@ -125,7 +148,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dec() {
|
void
|
||||||
|
dec() {
|
||||||
if (_pos == _begin) {
|
if (_pos == _begin) {
|
||||||
_pos = _end;
|
_pos = _end;
|
||||||
}
|
}
|
||||||
@@ -133,11 +157,13 @@ public:
|
|||||||
--_pos;
|
--_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool eq(const round_robin_t &other) const {
|
bool
|
||||||
|
eq(const round_robin_t &other) const {
|
||||||
return *_pos == *other._pos;
|
return *_pos == *other._pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer get() const {
|
pointer
|
||||||
|
get() const {
|
||||||
return &*_pos;
|
return &*_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +175,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class V, class It>
|
template <class V, class It>
|
||||||
round_robin_t<V, It> make_round_robin(It begin, It end) {
|
round_robin_t<V, It>
|
||||||
|
make_round_robin(It begin, It end) {
|
||||||
return round_robin_t<V, It>(begin, end);
|
return round_robin_t<V, It>(begin, end);
|
||||||
}
|
}
|
||||||
} // namespace round_robin_util
|
} // namespace round_robin_util
|
||||||
|
|||||||
102
src/rtsp.cpp
102
src/rtsp.cpp
@@ -30,7 +30,8 @@ using asio::ip::udp;
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
namespace rtsp_stream {
|
namespace rtsp_stream {
|
||||||
void free_msg(PRTSP_MESSAGE msg) {
|
void
|
||||||
|
free_msg(PRTSP_MESSAGE msg) {
|
||||||
freeMessage(msg);
|
freeMessage(msg);
|
||||||
|
|
||||||
delete msg;
|
delete msg;
|
||||||
@@ -41,16 +42,20 @@ class rtsp_server_t;
|
|||||||
using msg_t = util::safe_ptr<RTSP_MESSAGE, free_msg>;
|
using msg_t = util::safe_ptr<RTSP_MESSAGE, free_msg>;
|
||||||
using cmd_func_t = std::function<void(rtsp_server_t *server, tcp::socket &, msg_t &&)>;
|
using cmd_func_t = std::function<void(rtsp_server_t *server, tcp::socket &, msg_t &&)>;
|
||||||
|
|
||||||
void print_msg(PRTSP_MESSAGE msg);
|
void
|
||||||
void cmd_not_found(tcp::socket &sock, msg_t &&req);
|
print_msg(PRTSP_MESSAGE msg);
|
||||||
void respond(tcp::socket &sock, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload);
|
void
|
||||||
|
cmd_not_found(tcp::socket &sock, msg_t &&req);
|
||||||
|
void
|
||||||
|
respond(tcp::socket &sock, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload);
|
||||||
|
|
||||||
class socket_t: public std::enable_shared_from_this<socket_t> {
|
class socket_t: public std::enable_shared_from_this<socket_t> {
|
||||||
public:
|
public:
|
||||||
socket_t(boost::asio::io_service &ios, std::function<void(tcp::socket &sock, msg_t &&)> &&handle_data_fn)
|
socket_t(boost::asio::io_service &ios, std::function<void(tcp::socket &sock, msg_t &&)> &&handle_data_fn):
|
||||||
: handle_data_fn { std::move(handle_data_fn) }, sock { ios } {}
|
handle_data_fn { std::move(handle_data_fn) }, sock { ios } {}
|
||||||
|
|
||||||
void read() {
|
void
|
||||||
|
read() {
|
||||||
if (begin == std::end(msg_buf)) {
|
if (begin == std::end(msg_buf)) {
|
||||||
BOOST_LOG(error) << "RTSP: read(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
BOOST_LOG(error) << "RTSP: read(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
||||||
|
|
||||||
@@ -69,7 +74,8 @@ public:
|
|||||||
boost::asio::placeholders::bytes_transferred));
|
boost::asio::placeholders::bytes_transferred));
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_payload() {
|
void
|
||||||
|
read_payload() {
|
||||||
if (begin == std::end(msg_buf)) {
|
if (begin == std::end(msg_buf)) {
|
||||||
BOOST_LOG(error) << "RTSP: read_payload(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
BOOST_LOG(error) << "RTSP: read_payload(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
||||||
|
|
||||||
@@ -88,7 +94,8 @@ public:
|
|||||||
boost::asio::placeholders::bytes_transferred));
|
boost::asio::placeholders::bytes_transferred));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_payload(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
static void
|
||||||
|
handle_payload(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||||
BOOST_LOG(debug) << "handle_payload(): Handle read of size: "sv << bytes << " bytes"sv;
|
BOOST_LOG(debug) << "handle_payload(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||||
|
|
||||||
auto sock_close = util::fail_guard([&socket]() {
|
auto sock_close = util::fail_guard([&socket]() {
|
||||||
@@ -150,7 +157,8 @@ public:
|
|||||||
socket->begin = end;
|
socket->begin = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_read(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
static void
|
||||||
|
handle_read(std::shared_ptr<socket_t> &socket, const boost::system::error_code &ec, std::size_t bytes) {
|
||||||
BOOST_LOG(debug) << "handle_read(): Handle read of size: "sv << bytes << " bytes"sv;
|
BOOST_LOG(debug) << "handle_read(): Handle read of size: "sv << bytes << " bytes"sv;
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
@@ -192,7 +200,8 @@ public:
|
|||||||
handle_payload(socket, ec, buf_size);
|
handle_payload(socket, ec, buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_data(msg_t &&req) {
|
void
|
||||||
|
handle_data(msg_t &&req) {
|
||||||
handle_data_fn(sock, std::move(req));
|
handle_data_fn(sock, std::move(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +221,8 @@ public:
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bind(std::uint16_t port, boost::system::error_code &ec) {
|
int
|
||||||
|
bind(std::uint16_t port, boost::system::error_code &ec) {
|
||||||
{
|
{
|
||||||
auto lg = _session_slots.lock();
|
auto lg = _session_slots.lock();
|
||||||
|
|
||||||
@@ -249,11 +259,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
ios.run_one_for(timeout);
|
ios.run_one_for(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_msg(tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
handle_msg(tcp::socket &sock, msg_t &&req) {
|
||||||
auto func = _map_cmd_cb.find(req->message.request.command);
|
auto func = _map_cmd_cb.find(req->message.request.command);
|
||||||
if (func != std::end(_map_cmd_cb)) {
|
if (func != std::end(_map_cmd_cb)) {
|
||||||
func->second(this, sock, std::move(req));
|
func->second(this, sock, std::move(req));
|
||||||
@@ -265,7 +277,8 @@ public:
|
|||||||
sock.shutdown(boost::asio::socket_base::shutdown_type::shutdown_both);
|
sock.shutdown(boost::asio::socket_base::shutdown_type::shutdown_both);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_accept(const boost::system::error_code &ec) {
|
void
|
||||||
|
handle_accept(const boost::system::error_code &ec) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
BOOST_LOG(error) << "Couldn't accept incoming connections: "sv << ec.message();
|
BOOST_LOG(error) << "Couldn't accept incoming connections: "sv << ec.message();
|
||||||
|
|
||||||
@@ -286,11 +299,13 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void map(const std::string_view &type, cmd_func_t cb) {
|
void
|
||||||
|
map(const std::string_view &type, cmd_func_t cb) {
|
||||||
_map_cmd_cb.emplace(type, std::move(cb));
|
_map_cmd_cb.emplace(type, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_raise(rtsp_stream::launch_session_t launch_session) {
|
void
|
||||||
|
session_raise(rtsp_stream::launch_session_t launch_session) {
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
// If a launch event is still pending, don't overwrite it.
|
// If a launch event is still pending, don't overwrite it.
|
||||||
@@ -303,13 +318,15 @@ public:
|
|||||||
launch_event.raise(launch_session);
|
launch_event.raise(launch_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
int session_count() const {
|
int
|
||||||
|
session_count() const {
|
||||||
return config::stream.channels - _slot_count;
|
return config::stream.channels - _slot_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
safe::event_t<rtsp_stream::launch_session_t> launch_event;
|
safe::event_t<rtsp_stream::launch_session_t> launch_event;
|
||||||
|
|
||||||
void clear(bool all = true) {
|
void
|
||||||
|
clear(bool all = true) {
|
||||||
// if a launch event timed out --> Remove it.
|
// if a launch event timed out --> Remove it.
|
||||||
if (raised_timeout < std::chrono::steady_clock::now()) {
|
if (raised_timeout < std::chrono::steady_clock::now()) {
|
||||||
auto discarded = launch_event.pop(0s);
|
auto discarded = launch_event.pop(0s);
|
||||||
@@ -336,7 +353,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear(std::shared_ptr<stream::session_t> *session_p) {
|
void
|
||||||
|
clear(std::shared_ptr<stream::session_t> *session_p) {
|
||||||
auto lg = _session_slots.lock();
|
auto lg = _session_slots.lock();
|
||||||
|
|
||||||
session_p->reset();
|
session_p->reset();
|
||||||
@@ -344,7 +362,8 @@ public:
|
|||||||
++_slot_count;
|
++_slot_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<stream::session_t> *accept(std::shared_ptr<stream::session_t> &session) {
|
std::shared_ptr<stream::session_t> *
|
||||||
|
accept(std::shared_ptr<stream::session_t> &session) {
|
||||||
auto lg = _session_slots.lock();
|
auto lg = _session_slots.lock();
|
||||||
|
|
||||||
for (auto &slot : *_session_slots) {
|
for (auto &slot : *_session_slots) {
|
||||||
@@ -373,18 +392,21 @@ private:
|
|||||||
|
|
||||||
rtsp_server_t server {};
|
rtsp_server_t server {};
|
||||||
|
|
||||||
void launch_session_raise(rtsp_stream::launch_session_t launch_session) {
|
void
|
||||||
|
launch_session_raise(rtsp_stream::launch_session_t launch_session) {
|
||||||
server.session_raise(launch_session);
|
server.session_raise(launch_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
int session_count() {
|
int
|
||||||
|
session_count() {
|
||||||
// Ensure session_count is up-to-date
|
// Ensure session_count is up-to-date
|
||||||
server.clear(false);
|
server.clear(false);
|
||||||
|
|
||||||
return server.session_count();
|
return server.session_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
int send(tcp::socket &sock, const std::string_view &sv) {
|
int
|
||||||
|
send(tcp::socket &sock, const std::string_view &sv) {
|
||||||
std::size_t bytes_send = 0;
|
std::size_t bytes_send = 0;
|
||||||
|
|
||||||
while (bytes_send != sv.size()) {
|
while (bytes_send != sv.size()) {
|
||||||
@@ -400,7 +422,8 @@ int send(tcp::socket &sock, const std::string_view &sv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void respond(tcp::socket &sock, msg_t &resp) {
|
void
|
||||||
|
respond(tcp::socket &sock, msg_t &resp) {
|
||||||
auto payload = std::make_pair(resp->payload, resp->payloadLength);
|
auto payload = std::make_pair(resp->payload, resp->payloadLength);
|
||||||
|
|
||||||
// Restore response message for proper destruction
|
// Restore response message for proper destruction
|
||||||
@@ -429,18 +452,21 @@ void respond(tcp::socket &sock, msg_t &resp) {
|
|||||||
send(sock, std::string_view { payload.first, (std::size_t) payload.second });
|
send(sock, std::string_view { payload.first, (std::size_t) payload.second });
|
||||||
}
|
}
|
||||||
|
|
||||||
void respond(tcp::socket &sock, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload) {
|
void
|
||||||
|
respond(tcp::socket &sock, POPTION_ITEM options, int statuscode, const char *status_msg, int seqn, const std::string_view &payload) {
|
||||||
msg_t resp { new msg_t::element_type };
|
msg_t resp { new msg_t::element_type };
|
||||||
createRtspResponse(resp.get(), nullptr, 0, const_cast<char *>("RTSP/1.0"), statuscode, const_cast<char *>(status_msg), seqn, options, const_cast<char *>(payload.data()), (int) payload.size());
|
createRtspResponse(resp.get(), nullptr, 0, const_cast<char *>("RTSP/1.0"), statuscode, const_cast<char *>(status_msg), seqn, options, const_cast<char *>(payload.data()), (int) payload.size());
|
||||||
|
|
||||||
respond(sock, resp);
|
respond(sock, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_not_found(tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_not_found(tcp::socket &sock, msg_t &&req) {
|
||||||
respond(sock, nullptr, 404, "NOT FOUND", req->sequenceNumber, {});
|
respond(sock, nullptr, 404, "NOT FOUND", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_option(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_option(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||||
OPTION_ITEM option {};
|
OPTION_ITEM option {};
|
||||||
|
|
||||||
// I know these string literals will not be modified
|
// I know these string literals will not be modified
|
||||||
@@ -452,7 +478,8 @@ void cmd_option(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_describe(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_describe(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||||
OPTION_ITEM option {};
|
OPTION_ITEM option {};
|
||||||
|
|
||||||
// I know these string literals will not be modified
|
// I know these string literals will not be modified
|
||||||
@@ -496,7 +523,8 @@ void cmd_describe(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
respond(sock, &option, 200, "OK", req->sequenceNumber, ss.str());
|
respond(sock, &option, 200, "OK", req->sequenceNumber, ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_setup(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_setup(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||||
OPTION_ITEM options[3] {};
|
OPTION_ITEM options[3] {};
|
||||||
|
|
||||||
auto &seqn = options[0];
|
auto &seqn = options[0];
|
||||||
@@ -542,11 +570,11 @@ void cmd_setup(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
port_option.option = const_cast<char *>("Transport");
|
port_option.option = const_cast<char *>("Transport");
|
||||||
port_option.content = port_value.data();
|
port_option.content = port_value.data();
|
||||||
|
|
||||||
|
|
||||||
respond(sock, &seqn, 200, "OK", req->sequenceNumber, {});
|
respond(sock, &seqn, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||||
OPTION_ITEM option {};
|
OPTION_ITEM option {};
|
||||||
|
|
||||||
// I know these string literals will not be modified
|
// I know these string literals will not be modified
|
||||||
@@ -645,7 +673,6 @@ void cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
config.monitor.dynamicRange = util::from_view(args.at("x-nv-video[0].dynamicRangeMode"sv));
|
config.monitor.dynamicRange = util::from_view(args.at("x-nv-video[0].dynamicRangeMode"sv));
|
||||||
}
|
}
|
||||||
catch (std::out_of_range &) {
|
catch (std::out_of_range &) {
|
||||||
|
|
||||||
respond(sock, &option, 400, "BAD REQUEST", req->sequenceNumber, {});
|
respond(sock, &option, 400, "BAD REQUEST", req->sequenceNumber, {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -691,7 +718,8 @@ void cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_play(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
void
|
||||||
|
cmd_play(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||||
OPTION_ITEM option {};
|
OPTION_ITEM option {};
|
||||||
|
|
||||||
// I know these string literals will not be modified
|
// I know these string literals will not be modified
|
||||||
@@ -703,7 +731,8 @@ void cmd_play(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
|||||||
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
respond(sock, &option, 200, "OK", req->sequenceNumber, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtpThread() {
|
void
|
||||||
|
rtpThread() {
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||||
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||||
|
|
||||||
@@ -737,7 +766,8 @@ void rtpThread() {
|
|||||||
server.clear();
|
server.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_msg(PRTSP_MESSAGE msg) {
|
void
|
||||||
|
print_msg(PRTSP_MESSAGE msg) {
|
||||||
std::string_view type = msg->type == TYPE_RESPONSE ? "RESPONSE"sv : "REQUEST"sv;
|
std::string_view type = msg->type == TYPE_RESPONSE ? "RESPONSE"sv : "REQUEST"sv;
|
||||||
|
|
||||||
std::string_view payload { msg->payload, (size_t) msg->payloadLength };
|
std::string_view payload { msg->payload, (size_t) msg->payloadLength };
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ struct launch_session_t {
|
|||||||
bool host_audio;
|
bool host_audio;
|
||||||
};
|
};
|
||||||
|
|
||||||
void launch_session_raise(launch_session_t launch_session);
|
void
|
||||||
int session_count();
|
launch_session_raise(launch_session_t launch_session);
|
||||||
|
int
|
||||||
|
session_count();
|
||||||
|
|
||||||
void rtpThread();
|
void
|
||||||
|
rtpThread();
|
||||||
|
|
||||||
} // namespace rtsp_stream
|
} // namespace rtsp_stream
|
||||||
|
|
||||||
|
|||||||
140
src/stream.cpp
140
src/stream.cpp
@@ -68,7 +68,8 @@ enum class socket_e : int {
|
|||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct video_short_frame_header_t {
|
struct video_short_frame_header_t {
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,8 @@ static_assert(
|
|||||||
"Short frame header must be 8 bytes");
|
"Short frame header must be 8 bytes");
|
||||||
|
|
||||||
struct video_packet_raw_t {
|
struct video_packet_raw_t {
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +103,8 @@ struct video_packet_raw_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct audio_packet_raw_t {
|
struct audio_packet_raw_t {
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +115,8 @@ struct control_header_v2 {
|
|||||||
std::uint16_t type;
|
std::uint16_t type;
|
||||||
std::uint16_t payloadLength;
|
std::uint16_t payloadLength;
|
||||||
|
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -149,14 +153,16 @@ typedef struct control_encrypted_t {
|
|||||||
// seq is accepted as an arbitrary value in Moonlight
|
// seq is accepted as an arbitrary value in Moonlight
|
||||||
std::uint32_t seq; // Monotonically increasing sequence number (used as IV for AES-GCM)
|
std::uint32_t seq; // Monotonically increasing sequence number (used as IV for AES-GCM)
|
||||||
|
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
// encrypted control_header_v2 and payload data follow
|
// encrypted control_header_v2 and payload data follow
|
||||||
} *control_encrypted_p;
|
} *control_encrypted_p;
|
||||||
|
|
||||||
struct audio_fec_packet_raw_t {
|
struct audio_fec_packet_raw_t {
|
||||||
uint8_t *payload() {
|
uint8_t *
|
||||||
|
payload() {
|
||||||
return (uint8_t *) (this + 1);
|
return (uint8_t *) (this + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +172,8 @@ struct audio_fec_packet_raw_t {
|
|||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
constexpr std::size_t round_to_pkcs7_padded(std::size_t size) {
|
constexpr std::size_t
|
||||||
|
round_to_pkcs7_padded(std::size_t size) {
|
||||||
return ((size + 15) / 16) * 16;
|
return ((size + 15) / 16) * 16;
|
||||||
}
|
}
|
||||||
constexpr std::size_t MAX_AUDIO_PACKET_SIZE = 1400;
|
constexpr std::size_t MAX_AUDIO_PACKET_SIZE = 1400;
|
||||||
@@ -182,7 +189,8 @@ using message_queue_queue_t = std::shared_ptr<safe::queue_t<std::tuple<socket_e,
|
|||||||
|
|
||||||
// return bytes written on success
|
// return bytes written on success
|
||||||
// return -1 on error
|
// return -1 on error
|
||||||
static inline int encode_audio(int featureSet, const audio::buffer_t &plaintext, audio_packet_t &destination, std::uint32_t avRiKeyIv, crypto::cipher::cbc_t &cbc) {
|
static inline int
|
||||||
|
encode_audio(int featureSet, const audio::buffer_t &plaintext, audio_packet_t &destination, std::uint32_t avRiKeyIv, crypto::cipher::cbc_t &cbc) {
|
||||||
// If encryption isn't enabled
|
// If encryption isn't enabled
|
||||||
if (!(featureSet & 0x20)) {
|
if (!(featureSet & 0x20)) {
|
||||||
std::copy(std::begin(plaintext), std::end(plaintext), destination->payload());
|
std::copy(std::begin(plaintext), std::end(plaintext), destination->payload());
|
||||||
@@ -195,7 +203,8 @@ static inline int encode_audio(int featureSet, const audio::buffer_t &plaintext,
|
|||||||
return cbc.encrypt(std::string_view { (char *) std::begin(plaintext), plaintext.size() }, destination->payload(), &iv);
|
return cbc.encrypt(std::string_view { (char *) std::begin(plaintext), plaintext.size() }, destination->payload(), &iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void while_starting_do_nothing(std::atomic<session::state_e> &state) {
|
static inline void
|
||||||
|
while_starting_do_nothing(std::atomic<session::state_e> &state) {
|
||||||
while (state.load(std::memory_order_acquire) == session::state_e::STARTING) {
|
while (state.load(std::memory_order_acquire) == session::state_e::STARTING) {
|
||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
}
|
}
|
||||||
@@ -203,13 +212,15 @@ static inline void while_starting_do_nothing(std::atomic<session::state_e> &stat
|
|||||||
|
|
||||||
class control_server_t {
|
class control_server_t {
|
||||||
public:
|
public:
|
||||||
int bind(std::uint16_t port) {
|
int
|
||||||
|
bind(std::uint16_t port) {
|
||||||
_host = net::host_create(_addr, config::stream.channels, port);
|
_host = net::host_create(_addr, config::stream.channels, port);
|
||||||
|
|
||||||
return !(bool) _host;
|
return !(bool) _host;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emplace_addr_to_session(const std::string &addr, session_t &session) {
|
void
|
||||||
|
emplace_addr_to_session(const std::string &addr, session_t &session) {
|
||||||
auto lg = _map_addr_session.lock();
|
auto lg = _map_addr_session.lock();
|
||||||
|
|
||||||
_map_addr_session->emplace(addr, std::make_pair(0u, &session));
|
_map_addr_session->emplace(addr, std::make_pair(0u, &session));
|
||||||
@@ -218,22 +229,27 @@ public:
|
|||||||
// Get session associated with address.
|
// Get session associated with address.
|
||||||
// If none are found, try to find a session not yet claimed. (It will be marked by a port of value 0
|
// If none are found, try to find a session not yet claimed. (It will be marked by a port of value 0
|
||||||
// If none of those are found, return nullptr
|
// If none of those are found, return nullptr
|
||||||
session_t *get_session(const net::peer_t peer);
|
session_t *
|
||||||
|
get_session(const net::peer_t peer);
|
||||||
|
|
||||||
// Circular dependency:
|
// Circular dependency:
|
||||||
// iterate refers to session
|
// iterate refers to session
|
||||||
// session refers to broadcast_ctx_t
|
// session refers to broadcast_ctx_t
|
||||||
// broadcast_ctx_t refers to control_server_t
|
// broadcast_ctx_t refers to control_server_t
|
||||||
// Therefore, iterate is implemented further down the source file
|
// Therefore, iterate is implemented further down the source file
|
||||||
void iterate(std::chrono::milliseconds timeout);
|
void
|
||||||
|
iterate(std::chrono::milliseconds timeout);
|
||||||
|
|
||||||
void call(std::uint16_t type, session_t *session, const std::string_view &payload);
|
void
|
||||||
|
call(std::uint16_t type, session_t *session, const std::string_view &payload);
|
||||||
|
|
||||||
void map(uint16_t type, std::function<void(session_t *, const std::string_view &)> cb) {
|
void
|
||||||
|
map(uint16_t type, std::function<void(session_t *, const std::string_view &)> cb) {
|
||||||
_map_type_cb.emplace(type, std::move(cb));
|
_map_type_cb.emplace(type, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
int send(const std::string_view &payload, net::peer_t peer) {
|
int
|
||||||
|
send(const std::string_view &payload, net::peer_t peer) {
|
||||||
auto packet = enet_packet_create(payload.data(), payload.size(), ENET_PACKET_FLAG_RELIABLE);
|
auto packet = enet_packet_create(payload.data(), payload.size(), ENET_PACKET_FLAG_RELIABLE);
|
||||||
if (enet_peer_send(peer, 0, packet)) {
|
if (enet_peer_send(peer, 0, packet)) {
|
||||||
enet_packet_destroy(packet);
|
enet_packet_destroy(packet);
|
||||||
@@ -244,7 +260,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void
|
||||||
|
flush() {
|
||||||
enet_host_flush(_host.get());
|
enet_host_flush(_host.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,12 +358,12 @@ struct session_t {
|
|||||||
* returns string_view pointing to payload data
|
* returns string_view pointing to payload data
|
||||||
*/
|
*/
|
||||||
template <std::size_t max_payload_size>
|
template <std::size_t max_payload_size>
|
||||||
static inline std::string_view encode_control(session_t *session, const std::string_view &plaintext, std::array<std::uint8_t, max_payload_size> &tagged_cipher) {
|
static inline std::string_view
|
||||||
|
encode_control(session_t *session, const std::string_view &plaintext, std::array<std::uint8_t, max_payload_size> &tagged_cipher) {
|
||||||
static_assert(
|
static_assert(
|
||||||
max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size),
|
max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size),
|
||||||
"max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size)");
|
"max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size)");
|
||||||
|
|
||||||
|
|
||||||
if (session->config.controlProtocolType != 13) {
|
if (session->config.controlProtocolType != 13) {
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
@@ -372,13 +389,15 @@ static inline std::string_view encode_control(session_t *session, const std::str
|
|||||||
return std::string_view { (char *) tagged_cipher.data(), packet_length + sizeof(control_encrypted_t) - sizeof(control_encrypted_t::seq) };
|
return std::string_view { (char *) tagged_cipher.data(), packet_length + sizeof(control_encrypted_t) - sizeof(control_encrypted_t::seq) };
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_broadcast(broadcast_ctx_t &ctx);
|
int
|
||||||
void end_broadcast(broadcast_ctx_t &ctx);
|
start_broadcast(broadcast_ctx_t &ctx);
|
||||||
|
void
|
||||||
|
end_broadcast(broadcast_ctx_t &ctx);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
session_t *control_server_t::get_session(const net::peer_t peer) {
|
session_t *
|
||||||
|
control_server_t::get_session(const net::peer_t peer) {
|
||||||
TUPLE_2D(port, addr_string, platf::from_sockaddr_ex((sockaddr *) &peer->address.address));
|
TUPLE_2D(port, addr_string, platf::from_sockaddr_ex((sockaddr *) &peer->address.address));
|
||||||
|
|
||||||
auto lg = _map_addr_session.lock();
|
auto lg = _map_addr_session.lock();
|
||||||
@@ -408,7 +427,8 @@ session_t *control_server_t::get_session(const net::peer_t peer) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void control_server_t::call(std::uint16_t type, session_t *session, const std::string_view &payload) {
|
void
|
||||||
|
control_server_t::call(std::uint16_t type, session_t *session, const std::string_view &payload) {
|
||||||
auto cb = _map_type_cb.find(type);
|
auto cb = _map_type_cb.find(type);
|
||||||
if (cb == std::end(_map_type_cb)) {
|
if (cb == std::end(_map_type_cb)) {
|
||||||
BOOST_LOG(debug)
|
BOOST_LOG(debug)
|
||||||
@@ -422,7 +442,8 @@ void control_server_t::call(std::uint16_t type, session_t *session, const std::s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void control_server_t::iterate(std::chrono::milliseconds timeout) {
|
void
|
||||||
|
control_server_t::iterate(std::chrono::milliseconds timeout) {
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
auto res = enet_host_service(_host.get(), &event, timeout.count());
|
auto res = enet_host_service(_host.get(), &event, timeout.count());
|
||||||
|
|
||||||
@@ -473,20 +494,24 @@ struct fec_t {
|
|||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
util::buffer_t<char> shards;
|
util::buffer_t<char> shards;
|
||||||
|
|
||||||
char *data(size_t el) {
|
char *
|
||||||
|
data(size_t el) {
|
||||||
return &shards[el * blocksize];
|
return &shards[el * blocksize];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view operator[](size_t el) const {
|
std::string_view
|
||||||
|
operator[](size_t el) const {
|
||||||
return { &shards[el * blocksize], blocksize };
|
return { &shards[el * blocksize], blocksize };
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t
|
||||||
|
size() const {
|
||||||
return nr_shards;
|
return nr_shards;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static fec_t encode(const std::string_view &payload, size_t blocksize, size_t fecpercentage, size_t minparityshards) {
|
static fec_t
|
||||||
|
encode(const std::string_view &payload, size_t blocksize, size_t fecpercentage, size_t minparityshards) {
|
||||||
auto payload_size = payload.size();
|
auto payload_size = payload.size();
|
||||||
|
|
||||||
auto pad = payload_size % blocksize != 0;
|
auto pad = payload_size % blocksize != 0;
|
||||||
@@ -542,7 +567,8 @@ static fec_t encode(const std::string_view &payload, size_t blocksize, size_t fe
|
|||||||
} // namespace fec
|
} // namespace fec
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
std::vector<uint8_t> insert(uint64_t insert_size, uint64_t slice_size, const std::string_view &data, F &&f) {
|
std::vector<uint8_t>
|
||||||
|
insert(uint64_t insert_size, uint64_t slice_size, const std::string_view &data, F &&f) {
|
||||||
auto pad = data.size() % slice_size != 0;
|
auto pad = data.size() % slice_size != 0;
|
||||||
auto elements = data.size() / slice_size + (pad ? 1 : 0);
|
auto elements = data.size() / slice_size + (pad ? 1 : 0);
|
||||||
|
|
||||||
@@ -569,7 +595,8 @@ std::vector<uint8_t> insert(uint64_t insert_size, uint64_t slice_size, const std
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> replace(const std::string_view &original, const std::string_view &old, const std::string_view &_new) {
|
std::vector<uint8_t>
|
||||||
|
replace(const std::string_view &original, const std::string_view &old, const std::string_view &_new) {
|
||||||
std::vector<uint8_t> replaced;
|
std::vector<uint8_t> replaced;
|
||||||
|
|
||||||
auto begin = std::begin(original);
|
auto begin = std::begin(original);
|
||||||
@@ -585,7 +612,8 @@ std::vector<uint8_t> replace(const std::string_view &original, const std::string
|
|||||||
return replaced;
|
return replaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_rumble(session_t *session, std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq) {
|
int
|
||||||
|
send_rumble(session_t *session, std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq) {
|
||||||
if (!session->control.peer) {
|
if (!session->control.peer) {
|
||||||
BOOST_LOG(warning) << "Couldn't send rumble data, still waiting for PING from Moonlight"sv;
|
BOOST_LOG(warning) << "Couldn't send rumble data, still waiting for PING from Moonlight"sv;
|
||||||
// Still waiting for PING from Moonlight
|
// Still waiting for PING from Moonlight
|
||||||
@@ -619,7 +647,8 @@ int send_rumble(session_t *session, std::uint16_t id, std::uint16_t lowfreq, std
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_hdr_mode(session_t *session, video::hdr_info_t hdr_info) {
|
int
|
||||||
|
send_hdr_mode(session_t *session, video::hdr_info_t hdr_info) {
|
||||||
if (!session->control.peer) {
|
if (!session->control.peer) {
|
||||||
BOOST_LOG(warning) << "Couldn't send HDR mode, still waiting for PING from Moonlight"sv;
|
BOOST_LOG(warning) << "Couldn't send HDR mode, still waiting for PING from Moonlight"sv;
|
||||||
// Still waiting for PING from Moonlight
|
// Still waiting for PING from Moonlight
|
||||||
@@ -649,7 +678,8 @@ int send_hdr_mode(session_t *session, video::hdr_info_t hdr_info) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void controlBroadcastThread(control_server_t *server) {
|
void
|
||||||
|
controlBroadcastThread(control_server_t *server) {
|
||||||
server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) {
|
server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) {
|
||||||
BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
|
BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
|
||||||
});
|
});
|
||||||
@@ -874,7 +904,8 @@ void controlBroadcastThread(control_server_t *server) {
|
|||||||
server->flush();
|
server->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void recvThread(broadcast_ctx_t &ctx) {
|
void
|
||||||
|
recvThread(broadcast_ctx_t &ctx) {
|
||||||
std::map<asio::ip::address, message_queue_t> peer_to_video_session;
|
std::map<asio::ip::address, message_queue_t> peer_to_video_session;
|
||||||
std::map<asio::ip::address, message_queue_t> peer_to_audio_session;
|
std::map<asio::ip::address, message_queue_t> peer_to_audio_session;
|
||||||
|
|
||||||
@@ -926,7 +957,6 @@ void recvThread(broadcast_ctx_t &ctx) {
|
|||||||
auto type_str = buf_elem ? "AUDIO"sv : "VIDEO"sv;
|
auto type_str = buf_elem ? "AUDIO"sv : "VIDEO"sv;
|
||||||
BOOST_LOG(verbose) << "Recv: "sv << peer.address().to_string() << ':' << peer.port() << " :: " << type_str;
|
BOOST_LOG(verbose) << "Recv: "sv << peer.address().to_string() << ':' << peer.port() << " :: " << type_str;
|
||||||
|
|
||||||
|
|
||||||
populate_peer_to_session();
|
populate_peer_to_session();
|
||||||
|
|
||||||
// No data, yet no error
|
// No data, yet no error
|
||||||
@@ -958,7 +988,8 @@ void recvThread(broadcast_ctx_t &ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void videoBroadcastThread(udp::socket &sock) {
|
void
|
||||||
|
videoBroadcastThread(udp::socket &sock) {
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||||
auto packets = mail::man->queue<video::packet_t>(mail::video_packets);
|
auto packets = mail::man->queue<video::packet_t>(mail::video_packets);
|
||||||
auto timebase = boost::posix_time::microsec_clock::universal_time();
|
auto timebase = boost::posix_time::microsec_clock::universal_time();
|
||||||
@@ -1135,7 +1166,8 @@ void videoBroadcastThread(udp::socket &sock) {
|
|||||||
shutdown_event->raise(true);
|
shutdown_event->raise(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioBroadcastThread(udp::socket &sock) {
|
void
|
||||||
|
audioBroadcastThread(udp::socket &sock) {
|
||||||
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||||
auto packets = mail::man->queue<audio::packet_t>(mail::audio_packets);
|
auto packets = mail::man->queue<audio::packet_t>(mail::audio_packets);
|
||||||
|
|
||||||
@@ -1192,7 +1224,6 @@ void audioBroadcastThread(udp::socket &sock) {
|
|||||||
try {
|
try {
|
||||||
sock.send_to(asio::buffer((char *) audio_packet.get(), sizeof(audio_packet_raw_t) + bytes), session->audio.peer);
|
sock.send_to(asio::buffer((char *) audio_packet.get(), sizeof(audio_packet_raw_t) + bytes), session->audio.peer);
|
||||||
|
|
||||||
|
|
||||||
BOOST_LOG(verbose) << "Audio ["sv << sequenceNumber << "] :: send..."sv;
|
BOOST_LOG(verbose) << "Audio ["sv << sequenceNumber << "] :: send..."sv;
|
||||||
|
|
||||||
auto &fec_packet = session->audio.fec_packet;
|
auto &fec_packet = session->audio.fec_packet;
|
||||||
@@ -1224,7 +1255,8 @@ void audioBroadcastThread(udp::socket &sock) {
|
|||||||
shutdown_event->raise(true);
|
shutdown_event->raise(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_broadcast(broadcast_ctx_t &ctx) {
|
int
|
||||||
|
start_broadcast(broadcast_ctx_t &ctx) {
|
||||||
auto control_port = map_port(CONTROL_PORT);
|
auto control_port = map_port(CONTROL_PORT);
|
||||||
auto video_port = map_port(VIDEO_STREAM_PORT);
|
auto video_port = map_port(VIDEO_STREAM_PORT);
|
||||||
auto audio_port = map_port(AUDIO_STREAM_PORT);
|
auto audio_port = map_port(AUDIO_STREAM_PORT);
|
||||||
@@ -1275,7 +1307,8 @@ int start_broadcast(broadcast_ctx_t &ctx) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end_broadcast(broadcast_ctx_t &ctx) {
|
void
|
||||||
|
end_broadcast(broadcast_ctx_t &ctx) {
|
||||||
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||||
|
|
||||||
broadcast_shutdown_event->raise(true);
|
broadcast_shutdown_event->raise(true);
|
||||||
@@ -1309,7 +1342,8 @@ void end_broadcast(broadcast_ctx_t &ctx) {
|
|||||||
broadcast_shutdown_event->reset();
|
broadcast_shutdown_event->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, udp::endpoint &peer, std::chrono::milliseconds timeout) {
|
int
|
||||||
|
recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, udp::endpoint &peer, std::chrono::milliseconds timeout) {
|
||||||
auto constexpr ping = "PING"sv;
|
auto constexpr ping = "PING"sv;
|
||||||
|
|
||||||
auto messages = std::make_shared<message_queue_t::element_type>(30);
|
auto messages = std::make_shared<message_queue_t::element_type>(30);
|
||||||
@@ -1378,7 +1412,8 @@ int recv_ping(decltype(broadcast)::ptr_t ref, socket_e type, udp::endpoint &peer
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void videoThread(session_t *session) {
|
void
|
||||||
|
videoThread(session_t *session) {
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
session::stop(*session);
|
session::stop(*session);
|
||||||
});
|
});
|
||||||
@@ -1402,7 +1437,8 @@ void videoThread(session_t *session) {
|
|||||||
video::capture(session->mail, session->config.monitor, session);
|
video::capture(session->mail, session->config.monitor, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioThread(session_t *session) {
|
void
|
||||||
|
audioThread(session_t *session) {
|
||||||
auto fg = util::fail_guard([&]() {
|
auto fg = util::fail_guard([&]() {
|
||||||
session::stop(*session);
|
session::stop(*session);
|
||||||
});
|
});
|
||||||
@@ -1429,11 +1465,13 @@ void audioThread(session_t *session) {
|
|||||||
namespace session {
|
namespace session {
|
||||||
std::atomic_uint running_sessions;
|
std::atomic_uint running_sessions;
|
||||||
|
|
||||||
state_e state(session_t &session) {
|
state_e
|
||||||
|
state(session_t &session) {
|
||||||
return session.state.load(std::memory_order_relaxed);
|
return session.state.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop(session_t &session) {
|
void
|
||||||
|
stop(session_t &session) {
|
||||||
while_starting_do_nothing(session.state);
|
while_starting_do_nothing(session.state);
|
||||||
auto expected = state_e::RUNNING;
|
auto expected = state_e::RUNNING;
|
||||||
auto already_stopping = !session.state.compare_exchange_strong(expected, state_e::STOPPING);
|
auto already_stopping = !session.state.compare_exchange_strong(expected, state_e::STOPPING);
|
||||||
@@ -1444,7 +1482,8 @@ void stop(session_t &session) {
|
|||||||
session.shutdown_event->raise(true);
|
session.shutdown_event->raise(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void join(session_t &session) {
|
void
|
||||||
|
join(session_t &session) {
|
||||||
// Current Nvidia drivers have a bug where NVENC can deadlock the encoder thread with hardware-accelerated
|
// Current Nvidia drivers have a bug where NVENC can deadlock the encoder thread with hardware-accelerated
|
||||||
// GPU scheduling enabled. If this happens, we will terminate ourselves and the service can restart.
|
// GPU scheduling enabled. If this happens, we will terminate ourselves and the service can restart.
|
||||||
// The alternative is that Sunshine can never start another session until it's manually restarted.
|
// The alternative is that Sunshine can never start another session until it's manually restarted.
|
||||||
@@ -1512,7 +1551,8 @@ void join(session_t &session) {
|
|||||||
BOOST_LOG(debug) << "Session ended"sv;
|
BOOST_LOG(debug) << "Session ended"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start(session_t &session, const std::string &addr_string) {
|
int
|
||||||
|
start(session_t &session, const std::string &addr_string) {
|
||||||
session.input = input::alloc(session.mail);
|
session.input = input::alloc(session.mail);
|
||||||
|
|
||||||
session.broadcast_ref = broadcast.ref();
|
session.broadcast_ref = broadcast.ref();
|
||||||
@@ -1539,7 +1579,6 @@ int start(session_t &session, const std::string &addr_string) {
|
|||||||
connections->emplace_back(addr_string, 0);
|
connections->emplace_back(addr_string, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 };
|
session.audioThread = std::thread { audioThread, &session };
|
||||||
@@ -1555,7 +1594,8 @@ int start(session_t &session, const std::string &addr_string) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<session_t> alloc(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>();
|
||||||
|
|
||||||
auto mail = std::make_shared<safe::mail_raw_t>();
|
auto mail = std::make_shared<safe::mail_raw_t>();
|
||||||
|
|||||||
15
src/stream.h
15
src/stream.h
@@ -37,11 +37,16 @@ enum class state_e : int {
|
|||||||
RUNNING,
|
RUNNING,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
std::shared_ptr<session_t>
|
||||||
int start(session_t &session, const std::string &addr_string);
|
alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
||||||
void stop(session_t &session);
|
int
|
||||||
void join(session_t &session);
|
start(session_t &session, const std::string &addr_string);
|
||||||
state_e state(session_t &session);
|
void
|
||||||
|
stop(session_t &session);
|
||||||
|
void
|
||||||
|
join(session_t &session);
|
||||||
|
state_e
|
||||||
|
state(session_t &session);
|
||||||
} // namespace session
|
} // namespace session
|
||||||
} // namespace stream
|
} // namespace stream
|
||||||
|
|
||||||
|
|||||||
31
src/sync.h
31
src/sync.h
@@ -15,14 +15,17 @@ public:
|
|||||||
using value_t = T;
|
using value_t = T;
|
||||||
using mutex_t = M;
|
using mutex_t = M;
|
||||||
|
|
||||||
std::lock_guard<mutex_t> lock() {
|
std::lock_guard<mutex_t>
|
||||||
|
lock() {
|
||||||
return std::lock_guard { _lock };
|
return std::lock_guard { _lock };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
sync_t(Args &&...args) : raw { std::forward<Args>(args)... } {}
|
sync_t(Args &&...args):
|
||||||
|
raw { std::forward<Args>(args)... } {}
|
||||||
|
|
||||||
sync_t &operator=(sync_t &&other) noexcept {
|
sync_t &
|
||||||
|
operator=(sync_t &&other) noexcept {
|
||||||
std::lock(_lock, other._lock);
|
std::lock(_lock, other._lock);
|
||||||
|
|
||||||
raw = std::move(other.raw);
|
raw = std::move(other.raw);
|
||||||
@@ -33,7 +36,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_t &operator=(sync_t &other) noexcept {
|
sync_t &
|
||||||
|
operator=(sync_t &other) noexcept {
|
||||||
std::lock(_lock, other._lock);
|
std::lock(_lock, other._lock);
|
||||||
|
|
||||||
raw = other.raw;
|
raw = other.raw;
|
||||||
@@ -45,7 +49,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
sync_t &operator=(V &&val) {
|
sync_t &
|
||||||
|
operator=(V &&val) {
|
||||||
auto lg = lock();
|
auto lg = lock();
|
||||||
|
|
||||||
raw = val;
|
raw = val;
|
||||||
@@ -53,7 +58,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_t &operator=(const value_t &val) noexcept {
|
sync_t &
|
||||||
|
operator=(const value_t &val) noexcept {
|
||||||
auto lg = lock();
|
auto lg = lock();
|
||||||
|
|
||||||
raw = val;
|
raw = val;
|
||||||
@@ -61,7 +67,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_t &operator=(value_t &&val) noexcept {
|
sync_t &
|
||||||
|
operator=(value_t &&val) noexcept {
|
||||||
auto lg = lock();
|
auto lg = lock();
|
||||||
|
|
||||||
raw = std::move(val);
|
raw = std::move(val);
|
||||||
@@ -69,15 +76,18 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t *operator->() {
|
value_t *
|
||||||
|
operator->() {
|
||||||
return &raw;
|
return &raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t &operator*() {
|
value_t &
|
||||||
|
operator*() {
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value_t &operator*() const {
|
const value_t &
|
||||||
|
operator*() const {
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,5 +99,4 @@ private:
|
|||||||
|
|
||||||
} // namespace sync_util
|
} // namespace sync_util
|
||||||
|
|
||||||
|
|
||||||
#endif // SUNSHINE_SYNC_H
|
#endif // SUNSHINE_SYNC_H
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ namespace system_tray {
|
|||||||
* @brief Open a url in the default web browser.
|
* @brief Open a url in the default web browser.
|
||||||
* @param url The url to open.
|
* @param url The url to open.
|
||||||
*/
|
*/
|
||||||
void open_url(const std::string &url) {
|
void
|
||||||
|
open_url(const std::string &url) {
|
||||||
boost::filesystem::path working_dir;
|
boost::filesystem::path working_dir;
|
||||||
|
|
||||||
// if windows
|
// if windows
|
||||||
@@ -70,7 +71,8 @@ void open_url(const std::string &url) {
|
|||||||
* @brief Callback for opening the UI from the system tray.
|
* @brief Callback for opening the UI from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_open_ui_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_open_ui_cb(struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
BOOST_LOG(info) << "Opening UI from system tray"sv;
|
||||||
|
|
||||||
// create the url with the port
|
// create the url with the port
|
||||||
@@ -84,7 +86,8 @@ void tray_open_ui_cb(struct tray_menu *item) {
|
|||||||
* @brief Callback for opening GitHub Sponsors from the system tray.
|
* @brief Callback for opening GitHub Sponsors from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_github_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_donate_github_cb(struct tray_menu *item) {
|
||||||
open_url("https://github.com/sponsors/LizardByte");
|
open_url("https://github.com/sponsors/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +95,8 @@ void tray_donate_github_cb(struct tray_menu *item) {
|
|||||||
* @brief Callback for opening MEE6 donation from the system tray.
|
* @brief Callback for opening MEE6 donation from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_mee6_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_donate_mee6_cb(struct tray_menu *item) {
|
||||||
open_url("https://mee6.xyz/m/804382334370578482");
|
open_url("https://mee6.xyz/m/804382334370578482");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +104,8 @@ void tray_donate_mee6_cb(struct tray_menu *item) {
|
|||||||
* @brief Callback for opening Patreon from the system tray.
|
* @brief Callback for opening Patreon from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_patreon_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_donate_patreon_cb(struct tray_menu *item) {
|
||||||
open_url("https://www.patreon.com/LizardByte");
|
open_url("https://www.patreon.com/LizardByte");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +113,8 @@ void tray_donate_patreon_cb(struct tray_menu *item) {
|
|||||||
* @brief Callback for opening PayPal donation from the system tray.
|
* @brief Callback for opening PayPal donation from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_donate_paypal_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_donate_paypal_cb(struct tray_menu *item) {
|
||||||
open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
open_url("https://www.paypal.com/paypalme/ReenigneArcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +122,8 @@ void tray_donate_paypal_cb(struct tray_menu *item) {
|
|||||||
* @brief Callback for exiting Sunshine from the system tray.
|
* @brief Callback for exiting Sunshine from the system tray.
|
||||||
* @param item The tray menu item.
|
* @param item The tray menu item.
|
||||||
*/
|
*/
|
||||||
void tray_quit_cb(struct tray_menu *item) {
|
void
|
||||||
|
tray_quit_cb(struct tray_menu *item) {
|
||||||
BOOST_LOG(info) << "Quiting from system tray"sv;
|
BOOST_LOG(info) << "Quiting from system tray"sv;
|
||||||
|
|
||||||
std::raise(SIGINT);
|
std::raise(SIGINT);
|
||||||
@@ -146,13 +153,13 @@ static struct tray tray = {
|
|||||||
{ .text = nullptr } },
|
{ .text = nullptr } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create the system tray.
|
* @brief Create the system tray.
|
||||||
* @details This function has an endless loop, so it should be run in a separate thread.
|
* @details This function has an endless loop, so it should be run in a separate thread.
|
||||||
* @return 1 if the system tray failed to create, otherwise 0 once the tray has been terminated.
|
* @return 1 if the system tray failed to create, otherwise 0 once the tray has been terminated.
|
||||||
*/
|
*/
|
||||||
int system_tray() {
|
int
|
||||||
|
system_tray() {
|
||||||
if (tray_init(&tray) < 0) {
|
if (tray_init(&tray) < 0) {
|
||||||
BOOST_LOG(warning) << "Failed to create system tray"sv;
|
BOOST_LOG(warning) << "Failed to create system tray"sv;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -172,7 +179,8 @@ int system_tray() {
|
|||||||
* @brief Run the system tray with platform specific options.
|
* @brief Run the system tray with platform specific options.
|
||||||
* @note macOS requires that UI elements be created on the main thread, so the system tray is not implemented for macOS.
|
* @note macOS requires that UI elements be created on the main thread, so the system tray is not implemented for macOS.
|
||||||
*/
|
*/
|
||||||
void run_tray() {
|
void
|
||||||
|
run_tray() {
|
||||||
// create the system tray
|
// create the system tray
|
||||||
#if defined(__APPLE__) || defined(__MACH__)
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
// macOS requires that UI elements be created on the main thread
|
// macOS requires that UI elements be created on the main thread
|
||||||
@@ -194,7 +202,8 @@ void run_tray() {
|
|||||||
* @brief Exit the system tray.
|
* @brief Exit the system tray.
|
||||||
* @return 0 after exiting the system tray.
|
* @return 0 after exiting the system tray.
|
||||||
*/
|
*/
|
||||||
int end_tray() {
|
int
|
||||||
|
end_tray() {
|
||||||
tray_exit();
|
tray_exit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,27 @@
|
|||||||
// system_tray namespace
|
// system_tray namespace
|
||||||
namespace system_tray {
|
namespace system_tray {
|
||||||
|
|
||||||
void open_url(const std::string &url);
|
void
|
||||||
void tray_open_ui_cb(struct tray_menu *item);
|
open_url(const std::string &url);
|
||||||
void tray_donate_github_cb(struct tray_menu *item);
|
void
|
||||||
void tray_donate_mee6_cb(struct tray_menu *item);
|
tray_open_ui_cb(struct tray_menu *item);
|
||||||
void tray_donate_patreon_cb(struct tray_menu *item);
|
void
|
||||||
void tray_donate_paypal_cb(struct tray_menu *item);
|
tray_donate_github_cb(struct tray_menu *item);
|
||||||
void tray_quit_cb(struct tray_menu *item);
|
void
|
||||||
|
tray_donate_mee6_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
tray_donate_patreon_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
tray_donate_paypal_cb(struct tray_menu *item);
|
||||||
|
void
|
||||||
|
tray_quit_cb(struct tray_menu *item);
|
||||||
|
|
||||||
int system_tray();
|
int
|
||||||
int run_tray();
|
system_tray();
|
||||||
int end_tray();
|
int
|
||||||
|
run_tray();
|
||||||
|
int
|
||||||
|
end_tray();
|
||||||
|
|
||||||
} // namespace system_tray
|
} // namespace system_tray
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ public:
|
|||||||
|
|
||||||
inline virtual ~_ImplBase() = default;
|
inline virtual ~_ImplBase() = default;
|
||||||
|
|
||||||
virtual void run() = 0;
|
virtual void
|
||||||
|
run() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Function>
|
template <class Function>
|
||||||
@@ -29,9 +30,11 @@ class _Impl : public _ImplBase {
|
|||||||
Function _func;
|
Function _func;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
_Impl(Function &&f) : _func(std::forward<Function>(f)) {}
|
_Impl(Function &&f):
|
||||||
|
_func(std::forward<Function>(f)) {}
|
||||||
|
|
||||||
void run() override {
|
void
|
||||||
|
run() override {
|
||||||
_func();
|
_func();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -41,7 +44,6 @@ public:
|
|||||||
typedef std::unique_ptr<_ImplBase> __task;
|
typedef std::unique_ptr<_ImplBase> __task;
|
||||||
typedef _ImplBase *task_id_t;
|
typedef _ImplBase *task_id_t;
|
||||||
|
|
||||||
|
|
||||||
typedef std::chrono::steady_clock::time_point __time_point;
|
typedef std::chrono::steady_clock::time_point __time_point;
|
||||||
|
|
||||||
template <class R>
|
template <class R>
|
||||||
@@ -50,7 +52,8 @@ public:
|
|||||||
task_id_t task_id;
|
task_id_t task_id;
|
||||||
std::future<R> future;
|
std::future<R> future;
|
||||||
|
|
||||||
timer_task_t(task_id_t task_id, std::future<R> &future) : task_id { task_id }, future { std::move(future) } {}
|
timer_task_t(task_id_t task_id, std::future<R> &future):
|
||||||
|
task_id { task_id }, future { std::move(future) } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -60,9 +63,11 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
TaskPool() = default;
|
TaskPool() = default;
|
||||||
TaskPool(TaskPool &&other) noexcept : _tasks { std::move(other._tasks) }, _timer_tasks { std::move(other._timer_tasks) } {}
|
TaskPool(TaskPool &&other) noexcept:
|
||||||
|
_tasks { std::move(other._tasks) }, _timer_tasks { std::move(other._timer_tasks) } {}
|
||||||
|
|
||||||
TaskPool &operator=(TaskPool &&other) noexcept {
|
TaskPool &
|
||||||
|
operator=(TaskPool &&other) noexcept {
|
||||||
std::swap(_tasks, other._tasks);
|
std::swap(_tasks, other._tasks);
|
||||||
std::swap(_timer_tasks, other._timer_tasks);
|
std::swap(_timer_tasks, other._timer_tasks);
|
||||||
|
|
||||||
@@ -70,7 +75,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Function, class... Args>
|
template <class Function, class... Args>
|
||||||
auto push(Function &&newTask, Args &&...args) {
|
auto
|
||||||
|
push(Function &&newTask, Args &&...args) {
|
||||||
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
||||||
|
|
||||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||||
@@ -90,7 +96,8 @@ public:
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
void
|
||||||
|
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::lock_guard lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.cbegin();
|
auto it = _timer_tasks.cbegin();
|
||||||
@@ -107,7 +114,8 @@ public:
|
|||||||
* @return an id to potentially delay the task
|
* @return an id to potentially delay the task
|
||||||
*/
|
*/
|
||||||
template <class Function, class X, class Y, class... Args>
|
template <class Function, class X, class Y, class... Args>
|
||||||
auto pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
auto
|
||||||
|
pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
||||||
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
static_assert(std::is_invocable_v<Function, Args &&...>, "arguments don't match the function");
|
||||||
|
|
||||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||||
@@ -141,7 +149,8 @@ public:
|
|||||||
* @param duration The delay before executing the task
|
* @param duration The delay before executing the task
|
||||||
*/
|
*/
|
||||||
template <class X, class Y>
|
template <class X, class Y>
|
||||||
void delay(task_id_t task_id, std::chrono::duration<X, Y> duration) {
|
void
|
||||||
|
delay(task_id_t task_id, std::chrono::duration<X, Y> duration) {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.begin();
|
auto it = _timer_tasks.begin();
|
||||||
@@ -171,7 +180,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cancel(task_id_t task_id) {
|
bool
|
||||||
|
cancel(task_id_t task_id) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::lock_guard lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.begin();
|
auto it = _timer_tasks.begin();
|
||||||
@@ -188,7 +198,8 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::pair<__time_point, __task>> pop(task_id_t task_id) {
|
std::optional<std::pair<__time_point, __task>>
|
||||||
|
pop(task_id_t task_id) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::lock_guard lg(_task_mutex);
|
||||||
|
|
||||||
auto pos = std::find_if(std::begin(_timer_tasks), std::end(_timer_tasks), [&task_id](const auto &t) { return t.second.get() == task_id; });
|
auto pos = std::find_if(std::begin(_timer_tasks), std::end(_timer_tasks), [&task_id](const auto &t) { return t.second.get() == task_id; });
|
||||||
@@ -200,7 +211,8 @@ public:
|
|||||||
return std::move(*pos);
|
return std::move(*pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<__task> pop() {
|
std::optional<__task>
|
||||||
|
pop() {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::lock_guard lg(_task_mutex);
|
||||||
|
|
||||||
if (!_tasks.empty()) {
|
if (!_tasks.empty()) {
|
||||||
@@ -219,13 +231,15 @@ public:
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ready() {
|
bool
|
||||||
|
ready() {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||||
|
|
||||||
return !_tasks.empty() || (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now());
|
return !_tasks.empty() || (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<__time_point> next() {
|
std::optional<__time_point>
|
||||||
|
next() {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||||
|
|
||||||
if (_timer_tasks.empty()) {
|
if (_timer_tasks.empty()) {
|
||||||
@@ -237,7 +251,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <class Function>
|
template <class Function>
|
||||||
std::unique_ptr<_ImplBase> toRunnable(Function &&f) {
|
std::unique_ptr<_ImplBase>
|
||||||
|
toRunnable(Function &&f) {
|
||||||
return std::make_unique<_Impl<Function>>(std::forward<Function &&>(f));
|
return std::make_unique<_Impl<Function>>(std::forward<Function &&>(f));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ private:
|
|||||||
bool _continue;
|
bool _continue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ThreadPool() : _continue { false } {}
|
ThreadPool():
|
||||||
|
_continue { false } {}
|
||||||
|
|
||||||
explicit ThreadPool(int threads) : _thread(threads), _continue { true } {
|
explicit ThreadPool(int threads):
|
||||||
|
_thread(threads), _continue { true } {
|
||||||
for (auto &t : _thread) {
|
for (auto &t : _thread) {
|
||||||
t = std::thread(&ThreadPool::_main, this);
|
t = std::thread(&ThreadPool::_main, this);
|
||||||
}
|
}
|
||||||
@@ -38,7 +40,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Function, class... Args>
|
template <class Function, class... Args>
|
||||||
auto push(Function &&newTask, Args &&...args) {
|
auto
|
||||||
|
push(Function &&newTask, Args &&...args) {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
auto future = TaskPool::push(std::forward<Function>(newTask), std::forward<Args>(args)...);
|
auto future = TaskPool::push(std::forward<Function>(newTask), std::forward<Args>(args)...);
|
||||||
|
|
||||||
@@ -46,14 +49,16 @@ public:
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
void
|
||||||
|
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
|
|
||||||
TaskPool::pushDelayed(std::move(task));
|
TaskPool::pushDelayed(std::move(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function, class X, class Y, class... Args>
|
template <class Function, class X, class Y, class... Args>
|
||||||
auto pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
auto
|
||||||
|
pushDelayed(Function &&newTask, std::chrono::duration<X, Y> duration, Args &&...args) {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
auto future = TaskPool::pushDelayed(std::forward<Function>(newTask), duration, std::forward<Args>(args)...);
|
auto future = TaskPool::pushDelayed(std::forward<Function>(newTask), duration, std::forward<Args>(args)...);
|
||||||
|
|
||||||
@@ -62,7 +67,8 @@ public:
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(int threads) {
|
void
|
||||||
|
start(int threads) {
|
||||||
_continue = true;
|
_continue = true;
|
||||||
|
|
||||||
_thread.resize(threads);
|
_thread.resize(threads);
|
||||||
@@ -72,21 +78,24 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void
|
||||||
|
stop() {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
|
|
||||||
_continue = false;
|
_continue = false;
|
||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void join() {
|
void
|
||||||
|
join() {
|
||||||
for (auto &t : _thread) {
|
for (auto &t : _thread) {
|
||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void _main() {
|
void
|
||||||
|
_main() {
|
||||||
while (_continue) {
|
while (_continue) {
|
||||||
if (auto task = this->pop()) {
|
if (auto task = this->pop()) {
|
||||||
(*task)->run();
|
(*task)->run();
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ public:
|
|||||||
using status_t = util::optional_t<T>;
|
using status_t = util::optional_t<T>;
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
void raise(Args &&...args) {
|
void
|
||||||
|
raise(Args &&...args) {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
return;
|
return;
|
||||||
@@ -36,7 +37,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pop and view shoud not be used interchangeably
|
// pop and view shoud not be used interchangeably
|
||||||
status_t pop() {
|
status_t
|
||||||
|
pop() {
|
||||||
std::unique_lock ul { _lock };
|
std::unique_lock ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -58,7 +60,8 @@ public:
|
|||||||
|
|
||||||
// pop and view shoud not be used interchangeably
|
// pop and view shoud not be used interchangeably
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
status_t pop(std::chrono::duration<Rep, Period> delay) {
|
status_t
|
||||||
|
pop(std::chrono::duration<Rep, Period> delay) {
|
||||||
std::unique_lock ul { _lock };
|
std::unique_lock ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -77,7 +80,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pop and view shoud not be used interchangeably
|
// pop and view shoud not be used interchangeably
|
||||||
const status_t &view() {
|
const status_t &
|
||||||
|
view() {
|
||||||
std::unique_lock ul { _lock };
|
std::unique_lock ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -95,11 +99,13 @@ public:
|
|||||||
return _status;
|
return _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek() {
|
bool
|
||||||
|
peek() {
|
||||||
return _continue && (bool) _status;
|
return _continue && (bool) _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void
|
||||||
|
stop() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
_continue = false;
|
_continue = false;
|
||||||
@@ -107,7 +113,8 @@ public:
|
|||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void
|
||||||
|
reset() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
_continue = true;
|
_continue = true;
|
||||||
@@ -115,7 +122,8 @@ public:
|
|||||||
_status = util::false_v<status_t>;
|
_status = util::false_v<status_t>;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool running() const {
|
[[nodiscard]] bool
|
||||||
|
running() const {
|
||||||
return _continue;
|
return _continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,16 +140,19 @@ class alarm_raw_t {
|
|||||||
public:
|
public:
|
||||||
using status_t = util::optional_t<T>;
|
using status_t = util::optional_t<T>;
|
||||||
|
|
||||||
alarm_raw_t() : _status { util::false_v<status_t> } {}
|
alarm_raw_t():
|
||||||
|
_status { util::false_v<status_t> } {}
|
||||||
|
|
||||||
void ring(const status_t &status) {
|
void
|
||||||
|
ring(const status_t &status) {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
|
|
||||||
_status = status;
|
_status = status;
|
||||||
_cv.notify_one();
|
_cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ring(status_t &&status) {
|
void
|
||||||
|
ring(status_t &&status) {
|
||||||
std::lock_guard lg(_lock);
|
std::lock_guard lg(_lock);
|
||||||
|
|
||||||
_status = std::move(status);
|
_status = std::move(status);
|
||||||
@@ -149,53 +160,62 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
auto wait_for(const std::chrono::duration<Rep, Period> &rel_time) {
|
auto
|
||||||
|
wait_for(const std::chrono::duration<Rep, Period> &rel_time) {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
|
|
||||||
return _cv.wait_for(ul, rel_time, [this]() { return (bool) status(); });
|
return _cv.wait_for(ul, rel_time, [this]() { return (bool) status(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period, class Pred>
|
template <class Rep, class Period, class Pred>
|
||||||
auto wait_for(const std::chrono::duration<Rep, Period> &rel_time, Pred &&pred) {
|
auto
|
||||||
|
wait_for(const std::chrono::duration<Rep, Period> &rel_time, Pred &&pred) {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
|
|
||||||
return _cv.wait_for(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
return _cv.wait_for(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
auto wait_until(const std::chrono::duration<Rep, Period> &rel_time) {
|
auto
|
||||||
|
wait_until(const std::chrono::duration<Rep, Period> &rel_time) {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
|
|
||||||
return _cv.wait_until(ul, rel_time, [this]() { return (bool) status(); });
|
return _cv.wait_until(ul, rel_time, [this]() { return (bool) status(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period, class Pred>
|
template <class Rep, class Period, class Pred>
|
||||||
auto wait_until(const std::chrono::duration<Rep, Period> &rel_time, Pred &&pred) {
|
auto
|
||||||
|
wait_until(const std::chrono::duration<Rep, Period> &rel_time, Pred &&pred) {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
|
|
||||||
return _cv.wait_until(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
return _cv.wait_until(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wait() {
|
auto
|
||||||
|
wait() {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
_cv.wait(ul, [this]() { return (bool) status(); });
|
_cv.wait(ul, [this]() { return (bool) status(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Pred>
|
template <class Pred>
|
||||||
auto wait(Pred &&pred) {
|
auto
|
||||||
|
wait(Pred &&pred) {
|
||||||
std::unique_lock ul(_lock);
|
std::unique_lock ul(_lock);
|
||||||
_cv.wait(ul, [this, &pred]() { return (bool) status() || pred(); });
|
_cv.wait(ul, [this, &pred]() { return (bool) status() || pred(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
const status_t &status() const {
|
const status_t &
|
||||||
|
status() const {
|
||||||
return _status;
|
return _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t &status() {
|
status_t &
|
||||||
|
status() {
|
||||||
return _status;
|
return _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void
|
||||||
|
reset() {
|
||||||
_status = status_t {};
|
_status = status_t {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +230,8 @@ template<class T>
|
|||||||
using alarm_t = std::shared_ptr<alarm_raw_t<T>>;
|
using alarm_t = std::shared_ptr<alarm_raw_t<T>>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
alarm_t<T> make_alarm() {
|
alarm_t<T>
|
||||||
|
make_alarm() {
|
||||||
return std::make_shared<alarm_raw_t<T>>();
|
return std::make_shared<alarm_raw_t<T>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,10 +240,12 @@ class queue_t {
|
|||||||
public:
|
public:
|
||||||
using status_t = util::optional_t<T>;
|
using status_t = util::optional_t<T>;
|
||||||
|
|
||||||
queue_t(std::uint32_t max_elements = 32) : _max_elements { max_elements } {}
|
queue_t(std::uint32_t max_elements = 32):
|
||||||
|
_max_elements { max_elements } {}
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
void raise(Args &&...args) {
|
void
|
||||||
|
raise(Args &&...args) {
|
||||||
std::lock_guard ul { _lock };
|
std::lock_guard ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -238,12 +261,14 @@ public:
|
|||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek() {
|
bool
|
||||||
|
peek() {
|
||||||
return _continue && !_queue.empty();
|
return _continue && !_queue.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
status_t pop(std::chrono::duration<Rep, Period> delay) {
|
status_t
|
||||||
|
pop(std::chrono::duration<Rep, Period> delay) {
|
||||||
std::unique_lock ul { _lock };
|
std::unique_lock ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -262,7 +287,8 @@ public:
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t pop() {
|
status_t
|
||||||
|
pop() {
|
||||||
std::unique_lock ul { _lock };
|
std::unique_lock ul { _lock };
|
||||||
|
|
||||||
if (!_continue) {
|
if (!_continue) {
|
||||||
@@ -283,11 +309,13 @@ public:
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<T> &unsafe() {
|
std::vector<T> &
|
||||||
|
unsafe() {
|
||||||
return _queue;
|
return _queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void
|
||||||
|
stop() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
_continue = false;
|
_continue = false;
|
||||||
@@ -295,7 +323,8 @@ public:
|
|||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool running() const {
|
[[nodiscard]] bool
|
||||||
|
running() const {
|
||||||
return _continue;
|
return _continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,14 +349,18 @@ public:
|
|||||||
struct ptr_t {
|
struct ptr_t {
|
||||||
shared_t *owner;
|
shared_t *owner;
|
||||||
|
|
||||||
ptr_t() : owner { nullptr } {}
|
ptr_t():
|
||||||
explicit ptr_t(shared_t *owner) : owner { owner } {}
|
owner { nullptr } {}
|
||||||
|
explicit ptr_t(shared_t *owner):
|
||||||
|
owner { owner } {}
|
||||||
|
|
||||||
ptr_t(ptr_t &&ptr) noexcept : owner { ptr.owner } {
|
ptr_t(ptr_t &&ptr) noexcept:
|
||||||
|
owner { ptr.owner } {
|
||||||
ptr.owner = nullptr;
|
ptr.owner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_t(const ptr_t &ptr) noexcept : owner { ptr.owner } {
|
ptr_t(const ptr_t &ptr) noexcept:
|
||||||
|
owner { ptr.owner } {
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -336,7 +369,8 @@ public:
|
|||||||
tmp.owner = nullptr;
|
tmp.owner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_t &operator=(const ptr_t &ptr) noexcept {
|
ptr_t &
|
||||||
|
operator=(const ptr_t &ptr) noexcept {
|
||||||
if (!ptr.owner) {
|
if (!ptr.owner) {
|
||||||
release();
|
release();
|
||||||
|
|
||||||
@@ -346,7 +380,8 @@ public:
|
|||||||
return *this = std::move(*ptr.owner->ref());
|
return *this = std::move(*ptr.owner->ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_t &operator=(ptr_t &&ptr) noexcept {
|
ptr_t &
|
||||||
|
operator=(ptr_t &&ptr) noexcept {
|
||||||
if (owner) {
|
if (owner) {
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
@@ -366,7 +401,8 @@ public:
|
|||||||
return owner != nullptr;
|
return owner != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release() {
|
void
|
||||||
|
release() {
|
||||||
std::lock_guard lg { owner->_lock };
|
std::lock_guard lg { owner->_lock };
|
||||||
|
|
||||||
if (!--owner->_count) {
|
if (!--owner->_count) {
|
||||||
@@ -377,18 +413,22 @@ public:
|
|||||||
owner = nullptr;
|
owner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
element_type *get() const {
|
element_type *
|
||||||
|
get() const {
|
||||||
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
element_type *operator->() {
|
element_type *
|
||||||
|
operator->() {
|
||||||
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class FC, class FD>
|
template <class FC, class FD>
|
||||||
shared_t(FC &&fc, FD &&fd) : _construct { std::forward<FC>(fc) }, _destruct { std::forward<FD>(fd) } {}
|
shared_t(FC &&fc, FD &&fd):
|
||||||
[[nodiscard]] ptr_t ref() {
|
_construct { std::forward<FC>(fc) }, _destruct { std::forward<FD>(fd) } {}
|
||||||
|
[[nodiscard]] ptr_t
|
||||||
|
ref() {
|
||||||
std::lock_guard lg { _lock };
|
std::lock_guard lg { _lock };
|
||||||
|
|
||||||
if (!_count) {
|
if (!_count) {
|
||||||
@@ -414,7 +454,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class F_Construct, class F_Destruct>
|
template <class T, class F_Construct, class F_Destruct>
|
||||||
auto make_shared(F_Construct &&fc, F_Destruct &&fd) {
|
auto
|
||||||
|
make_shared(F_Construct &&fc, F_Destruct &&fd) {
|
||||||
return shared_t<T> {
|
return shared_t<T> {
|
||||||
std::forward<F_Construct>(fc), std::forward<F_Destruct>(fd)
|
std::forward<F_Construct>(fc), std::forward<F_Destruct>(fd)
|
||||||
};
|
};
|
||||||
@@ -425,12 +466,14 @@ using signal_t = event_t<bool>;
|
|||||||
class mail_raw_t;
|
class mail_raw_t;
|
||||||
using mail_t = std::shared_ptr<mail_raw_t>;
|
using mail_t = std::shared_ptr<mail_raw_t>;
|
||||||
|
|
||||||
void cleanup(mail_raw_t *);
|
void
|
||||||
|
cleanup(mail_raw_t *);
|
||||||
template <class T>
|
template <class T>
|
||||||
class post_t: public T {
|
class post_t: public T {
|
||||||
public:
|
public:
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
post_t(mail_t mail, Args &&...args) : T(std::forward<Args>(args)...), mail { std::move(mail) } {}
|
post_t(mail_t mail, Args &&...args):
|
||||||
|
T(std::forward<Args>(args)...), mail { std::move(mail) } {}
|
||||||
|
|
||||||
mail_t mail;
|
mail_t mail;
|
||||||
|
|
||||||
@@ -440,7 +483,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline auto lock(const std::weak_ptr<void> &wp) {
|
inline auto
|
||||||
|
lock(const std::weak_ptr<void> &wp) {
|
||||||
return std::reinterpret_pointer_cast<typename T::element_type>(wp.lock());
|
return std::reinterpret_pointer_cast<typename T::element_type>(wp.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +497,8 @@ public:
|
|||||||
using queue_t = std::shared_ptr<post_t<queue_t<T>>>;
|
using queue_t = std::shared_ptr<post_t<queue_t<T>>>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
event_t<T> event(const std::string_view &id) {
|
event_t<T>
|
||||||
|
event(const std::string_view &id) {
|
||||||
std::lock_guard lg { mutex };
|
std::lock_guard lg { mutex };
|
||||||
|
|
||||||
auto it = id_to_post.find(id);
|
auto it = id_to_post.find(id);
|
||||||
@@ -468,7 +513,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
queue_t<T> queue(const std::string_view &id) {
|
queue_t<T>
|
||||||
|
queue(const std::string_view &id) {
|
||||||
std::lock_guard lg { mutex };
|
std::lock_guard lg { mutex };
|
||||||
|
|
||||||
auto it = id_to_post.find(id);
|
auto it = id_to_post.find(id);
|
||||||
@@ -482,7 +528,8 @@ public:
|
|||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup() {
|
void
|
||||||
|
cleanup() {
|
||||||
std::lock_guard lg { mutex };
|
std::lock_guard lg { mutex };
|
||||||
|
|
||||||
for (auto it = std::begin(id_to_post); it != std::end(id_to_post); ++it) {
|
for (auto it = std::begin(id_to_post); it != std::end(id_to_post); ++it) {
|
||||||
@@ -501,7 +548,8 @@ public:
|
|||||||
std::map<std::string, std::weak_ptr<void>, std::less<>> id_to_post;
|
std::map<std::string, std::weak_ptr<void>, std::less<>> id_to_post;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void cleanup(mail_raw_t *mail) {
|
inline void
|
||||||
|
cleanup(mail_raw_t *mail) {
|
||||||
mail->cleanup();
|
mail->cleanup();
|
||||||
}
|
}
|
||||||
} // namespace safe
|
} // namespace safe
|
||||||
|
|||||||
14
src/upnp.cpp
14
src/upnp.cpp
@@ -35,12 +35,12 @@ struct mapping_t {
|
|||||||
bool tcp;
|
bool tcp;
|
||||||
};
|
};
|
||||||
|
|
||||||
void unmap(
|
void
|
||||||
|
unmap(
|
||||||
const urls_t &urls,
|
const urls_t &urls,
|
||||||
const IGDdatas &data,
|
const IGDdatas &data,
|
||||||
std::vector<mapping_t>::const_reverse_iterator begin,
|
std::vector<mapping_t>::const_reverse_iterator begin,
|
||||||
std::vector<mapping_t>::const_reverse_iterator end) {
|
std::vector<mapping_t>::const_reverse_iterator end) {
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Unmapping UPNP ports"sv;
|
BOOST_LOG(debug) << "Unmapping UPNP ports"sv;
|
||||||
|
|
||||||
for (auto it = begin; it != end; ++it) {
|
for (auto it = begin; it != end; ++it) {
|
||||||
@@ -61,8 +61,8 @@ void unmap(
|
|||||||
class deinit_t: public platf::deinit_t {
|
class deinit_t: public platf::deinit_t {
|
||||||
public:
|
public:
|
||||||
using iter_t = std::vector<mapping_t>::const_reverse_iterator;
|
using iter_t = std::vector<mapping_t>::const_reverse_iterator;
|
||||||
deinit_t(urls_t &&urls, IGDdatas data, std::vector<mapping_t> &&mapping)
|
deinit_t(urls_t &&urls, IGDdatas data, std::vector<mapping_t> &&mapping):
|
||||||
: urls { std::move(urls) }, data { data }, mapping { std::move(mapping) } {}
|
urls { std::move(urls) }, data { data }, mapping { std::move(mapping) } {}
|
||||||
|
|
||||||
~deinit_t() {
|
~deinit_t() {
|
||||||
BOOST_LOG(info) << "Unmapping UPNP ports..."sv;
|
BOOST_LOG(info) << "Unmapping UPNP ports..."sv;
|
||||||
@@ -75,7 +75,8 @@ public:
|
|||||||
std::vector<mapping_t> mapping;
|
std::vector<mapping_t> mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string_view status_string(int status) {
|
static std::string_view
|
||||||
|
status_string(int status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
return "No IGD device found"sv;
|
return "No IGD device found"sv;
|
||||||
@@ -90,7 +91,8 @@ static std::string_view status_string(int status) {
|
|||||||
return "Unknown status"sv;
|
return "Unknown status"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<platf::deinit_t> start() {
|
std::unique_ptr<platf::deinit_t>
|
||||||
|
start() {
|
||||||
if (!config::sunshine.flags[config::flag::UPNP]) {
|
if (!config::sunshine.flags[config::flag::UPNP]) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
|
|
||||||
namespace upnp {
|
namespace upnp {
|
||||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> start();
|
[[nodiscard]] std::unique_ptr<platf::deinit_t>
|
||||||
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
315
src/utility.h
315
src/utility.h
@@ -40,16 +40,21 @@ struct argument_type<T(U)> {
|
|||||||
other.el = element_type { init_val }; \
|
other.el = element_type { init_val }; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
move_t &operator=(const move_t &) = delete; \
|
move_t & \
|
||||||
|
operator=(const move_t &) = delete; \
|
||||||
\
|
\
|
||||||
move_t &operator=(move_t &&other) { \
|
move_t & \
|
||||||
|
operator=(move_t &&other) { \
|
||||||
std::swap(el, other.el); \
|
std::swap(el, other.el); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
element_type *operator->() { return ⪙ } \
|
element_type * \
|
||||||
const element_type *operator->() const { return ⪙ } \
|
operator->() { return ⪙ } \
|
||||||
|
const element_type * \
|
||||||
|
operator->() const { return ⪙ } \
|
||||||
\
|
\
|
||||||
inline element_type release() { \
|
inline element_type \
|
||||||
|
release() { \
|
||||||
element_type val = std::move(el); \
|
element_type val = std::move(el); \
|
||||||
el = element_type { init_val }; \
|
el = element_type { init_val }; \
|
||||||
return val; \
|
return val; \
|
||||||
@@ -146,8 +151,10 @@ template<class T>
|
|||||||
class FailGuard {
|
class FailGuard {
|
||||||
public:
|
public:
|
||||||
FailGuard() = delete;
|
FailGuard() = delete;
|
||||||
FailGuard(T &&f) noexcept : _func { std::forward<T>(f) } {}
|
FailGuard(T &&f) noexcept:
|
||||||
FailGuard(FailGuard &&other) noexcept : _func { std::move(other._func) } {
|
_func { std::forward<T>(f) } {}
|
||||||
|
FailGuard(FailGuard &&other) noexcept:
|
||||||
|
_func { std::move(other._func) } {
|
||||||
this->failure = other.failure;
|
this->failure = other.failure;
|
||||||
|
|
||||||
other.failure = false;
|
other.failure = false;
|
||||||
@@ -155,8 +162,10 @@ public:
|
|||||||
|
|
||||||
FailGuard(const FailGuard &) = delete;
|
FailGuard(const FailGuard &) = delete;
|
||||||
|
|
||||||
FailGuard &operator=(const FailGuard &) = delete;
|
FailGuard &
|
||||||
FailGuard &operator=(FailGuard &&other) = delete;
|
operator=(const FailGuard &) = delete;
|
||||||
|
FailGuard &
|
||||||
|
operator=(FailGuard &&other) = delete;
|
||||||
|
|
||||||
~FailGuard() noexcept {
|
~FailGuard() noexcept {
|
||||||
if (failure) {
|
if (failure) {
|
||||||
@@ -164,7 +173,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() { failure = false; }
|
void
|
||||||
|
disable() { failure = false; }
|
||||||
bool failure { true };
|
bool failure { true };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -172,12 +182,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
[[nodiscard]] auto fail_guard(T &&f) {
|
[[nodiscard]] auto
|
||||||
|
fail_guard(T &&f) {
|
||||||
return FailGuard<T> { std::forward<T>(f) };
|
return FailGuard<T> { std::forward<T>(f) };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void append_struct(std::vector<uint8_t> &buf, const T &_struct) {
|
void
|
||||||
|
append_struct(std::vector<uint8_t> &buf, const T &_struct) {
|
||||||
constexpr size_t data_len = sizeof(_struct);
|
constexpr size_t data_len = sizeof(_struct);
|
||||||
|
|
||||||
buf.reserve(data_len);
|
buf.reserve(data_len);
|
||||||
@@ -219,34 +231,43 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *begin() { return _hex; }
|
char *
|
||||||
char *end() { return _hex + sizeof(elem_type) * 2; }
|
begin() { return _hex; }
|
||||||
|
char *
|
||||||
|
end() { return _hex + sizeof(elem_type) * 2; }
|
||||||
|
|
||||||
const char *begin() const { return _hex; }
|
const char *
|
||||||
const char *end() const { return _hex + sizeof(elem_type) * 2; }
|
begin() const { return _hex; }
|
||||||
|
const char *
|
||||||
|
end() const { return _hex + sizeof(elem_type) * 2; }
|
||||||
|
|
||||||
const char *cbegin() const { return _hex; }
|
const char *
|
||||||
const char *cend() const { return _hex + sizeof(elem_type) * 2; }
|
cbegin() const { return _hex; }
|
||||||
|
const char *
|
||||||
|
cend() const { return _hex + sizeof(elem_type) * 2; }
|
||||||
|
|
||||||
std::string to_string() const {
|
std::string
|
||||||
|
to_string() const {
|
||||||
return { begin(), end() };
|
return { begin(), end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view to_string_view() const {
|
std::string_view
|
||||||
|
to_string_view() const {
|
||||||
return { begin(), sizeof(elem_type) * 2 };
|
return { begin(), sizeof(elem_type) * 2 };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Hex<T> hex(const T &elem, bool rev = false) {
|
Hex<T>
|
||||||
|
hex(const T &elem, bool rev = false) {
|
||||||
return Hex<T>(elem, rev);
|
return Hex<T>(elem, rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class It>
|
template <class It>
|
||||||
std::string hex_vec(It begin, It end, bool rev = false) {
|
std::string
|
||||||
|
hex_vec(It begin, It end, bool rev = false) {
|
||||||
auto str_size = 2 * std::distance(begin, end);
|
auto str_size = 2 * std::distance(begin, end);
|
||||||
|
|
||||||
|
|
||||||
std::string hex;
|
std::string hex;
|
||||||
hex.resize(str_size);
|
hex.resize(str_size);
|
||||||
|
|
||||||
@@ -268,17 +289,18 @@ std::string hex_vec(It begin, It end, bool rev = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class C>
|
template <class C>
|
||||||
std::string hex_vec(C &&c, bool rev = false) {
|
std::string
|
||||||
|
hex_vec(C &&c, bool rev = false) {
|
||||||
return hex_vec(std::begin(c), std::end(c), rev);
|
return hex_vec(std::begin(c), std::end(c), rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T from_hex(const std::string_view &hex, bool rev = false) {
|
T
|
||||||
|
from_hex(const std::string_view &hex, bool rev = false) {
|
||||||
std::uint8_t buf[sizeof(T)];
|
std::uint8_t buf[sizeof(T)];
|
||||||
|
|
||||||
static char constexpr shift_bit = 'a' - 'A';
|
static char constexpr shift_bit = 'a' - 'A';
|
||||||
@@ -329,7 +351,8 @@ T from_hex(const std::string_view &hex, bool rev = false) {
|
|||||||
return *reinterpret_cast<T *>(buf);
|
return *reinterpret_cast<T *>(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string from_hex_vec(const std::string &hex, bool rev = false) {
|
inline std::string
|
||||||
|
from_hex_vec(const std::string &hex, bool rev = false) {
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
|
||||||
static char constexpr shift_bit = 'a' - 'A';
|
static char constexpr shift_bit = 'a' - 'A';
|
||||||
@@ -381,7 +404,8 @@ template<class T>
|
|||||||
class hash {
|
class hash {
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
std::size_t operator()(const value_type &value) const {
|
std::size_t
|
||||||
|
operator()(const value_type &value) const {
|
||||||
const auto *p = reinterpret_cast<const char *>(&value);
|
const auto *p = reinterpret_cast<const char *>(&value);
|
||||||
|
|
||||||
return std::hash<std::string_view> {}(std::string_view { p, sizeof(value_type) });
|
return std::hash<std::string_view> {}(std::string_view { p, sizeof(value_type) });
|
||||||
@@ -389,16 +413,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
auto enm(const T &val) -> const std::underlying_type_t<T> & {
|
auto
|
||||||
|
enm(const T &val) -> const std::underlying_type_t<T> & {
|
||||||
return *reinterpret_cast<const std::underlying_type_t<T> *>(&val);
|
return *reinterpret_cast<const std::underlying_type_t<T> *>(&val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
auto enm(T &val) -> std::underlying_type_t<T> & {
|
auto
|
||||||
|
enm(T &val) -> std::underlying_type_t<T> & {
|
||||||
return *reinterpret_cast<std::underlying_type_t<T> *>(&val);
|
return *reinterpret_cast<std::underlying_type_t<T> *>(&val);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::int64_t from_chars(const char *begin, const char *end) {
|
inline std::int64_t
|
||||||
|
from_chars(const char *begin, const char *end) {
|
||||||
if (begin == end) {
|
if (begin == end) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -414,7 +441,8 @@ inline std::int64_t from_chars(const char *begin, const char *end) {
|
|||||||
return *begin != '-' ? res + (std::int64_t)(*begin - '0') * mul : -res;
|
return *begin != '-' ? res + (std::int64_t)(*begin - '0') * mul : -res;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::int64_t from_view(const std::string_view &number) {
|
inline std::int64_t
|
||||||
|
from_view(const std::string_view &number) {
|
||||||
return from_chars(std::begin(number), std::end(number));
|
return from_chars(std::begin(number), std::end(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,26 +451,32 @@ class Either : public std::variant<std::monostate, X, Y> {
|
|||||||
public:
|
public:
|
||||||
using std::variant<std::monostate, X, Y>::variant;
|
using std::variant<std::monostate, X, Y>::variant;
|
||||||
|
|
||||||
constexpr bool has_left() const {
|
constexpr bool
|
||||||
|
has_left() const {
|
||||||
return std::holds_alternative<X>(*this);
|
return std::holds_alternative<X>(*this);
|
||||||
}
|
}
|
||||||
constexpr bool has_right() const {
|
constexpr bool
|
||||||
|
has_right() const {
|
||||||
return std::holds_alternative<Y>(*this);
|
return std::holds_alternative<Y>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
X &left() {
|
X &
|
||||||
|
left() {
|
||||||
return std::get<X>(*this);
|
return std::get<X>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Y &right() {
|
Y &
|
||||||
|
right() {
|
||||||
return std::get<Y>(*this);
|
return std::get<Y>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const X &left() const {
|
const X &
|
||||||
|
left() const {
|
||||||
return std::get<X>(*this);
|
return std::get<X>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Y &right() const {
|
const Y &
|
||||||
|
right() const {
|
||||||
return std::get<Y>(*this);
|
return std::get<Y>(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -455,29 +489,36 @@ public:
|
|||||||
using pointer = element_type *;
|
using pointer = element_type *;
|
||||||
using deleter_type = D;
|
using deleter_type = D;
|
||||||
|
|
||||||
constexpr uniq_ptr() noexcept : _p { nullptr } {}
|
constexpr uniq_ptr() noexcept:
|
||||||
constexpr uniq_ptr(std::nullptr_t) noexcept : _p { nullptr } {}
|
_p { nullptr } {}
|
||||||
|
constexpr uniq_ptr(std::nullptr_t) noexcept:
|
||||||
|
_p { nullptr } {}
|
||||||
|
|
||||||
uniq_ptr(const uniq_ptr &other) noexcept = delete;
|
uniq_ptr(const uniq_ptr &other) noexcept = delete;
|
||||||
uniq_ptr &operator=(const uniq_ptr &other) noexcept = delete;
|
uniq_ptr &
|
||||||
|
operator=(const uniq_ptr &other) noexcept = delete;
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
uniq_ptr(V *p) noexcept : _p { p } {
|
uniq_ptr(V *p) noexcept:
|
||||||
|
_p { p } {
|
||||||
static_assert(std::is_same_v<element_type, void> || std::is_same_v<element_type, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_same_v<element_type, void> || std::is_same_v<element_type, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq) noexcept : _p { uniq.release() } {
|
uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq) noexcept:
|
||||||
|
_p { uniq.release() } {
|
||||||
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
uniq_ptr(uniq_ptr<V, deleter_type> &&other) noexcept : _p { other.release() } {
|
uniq_ptr(uniq_ptr<V, deleter_type> &&other) noexcept:
|
||||||
|
_p { other.release() } {
|
||||||
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
uniq_ptr &operator=(uniq_ptr<V, deleter_type> &&other) noexcept {
|
uniq_ptr &
|
||||||
|
operator=(uniq_ptr<V, deleter_type> &&other) noexcept {
|
||||||
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
reset(other.release());
|
reset(other.release());
|
||||||
|
|
||||||
@@ -485,7 +526,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
uniq_ptr &operator=(std::unique_ptr<V, deleter_type> &&uniq) noexcept {
|
uniq_ptr &
|
||||||
|
operator=(std::unique_ptr<V, deleter_type> &&uniq) noexcept {
|
||||||
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
|
|
||||||
reset(uniq.release());
|
reset(uniq.release());
|
||||||
@@ -497,7 +539,8 @@ public:
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(pointer p = pointer()) {
|
void
|
||||||
|
reset(pointer p = pointer()) {
|
||||||
if (_p) {
|
if (_p) {
|
||||||
_deleter(_p);
|
_deleter(_p);
|
||||||
}
|
}
|
||||||
@@ -505,45 +548,56 @@ public:
|
|||||||
_p = p;
|
_p = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer release() {
|
pointer
|
||||||
|
release() {
|
||||||
auto tmp = _p;
|
auto tmp = _p;
|
||||||
_p = nullptr;
|
_p = nullptr;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer get() {
|
pointer
|
||||||
|
get() {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointer get() const {
|
const pointer
|
||||||
|
get() const {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::add_lvalue_reference_t<element_type> operator*() const {
|
const std::add_lvalue_reference_t<element_type>
|
||||||
|
operator*() const {
|
||||||
return *_p;
|
return *_p;
|
||||||
}
|
}
|
||||||
std::add_lvalue_reference_t<element_type> operator*() {
|
std::add_lvalue_reference_t<element_type>
|
||||||
|
operator*() {
|
||||||
return *_p;
|
return *_p;
|
||||||
}
|
}
|
||||||
const pointer operator->() const {
|
const pointer
|
||||||
|
operator->() const {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
pointer operator->() {
|
pointer
|
||||||
|
operator->() {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
pointer *operator&() const {
|
pointer *
|
||||||
|
operator&() const {
|
||||||
return &_p;
|
return &_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer *operator&() {
|
pointer *
|
||||||
|
operator&() {
|
||||||
return &_p;
|
return &_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleter_type &get_deleter() {
|
deleter_type &
|
||||||
|
get_deleter() {
|
||||||
return _deleter;
|
return _deleter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleter_type &get_deleter() const {
|
const deleter_type &
|
||||||
|
get_deleter() const {
|
||||||
return _deleter;
|
return _deleter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,52 +611,62 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator==(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
bool
|
||||||
|
operator==(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
||||||
return x.get() == y.get();
|
return x.get() == y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator!=(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
bool
|
||||||
|
operator!=(const uniq_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
||||||
return x.get() != y.get();
|
return x.get() != y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator==(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
bool
|
||||||
|
operator==(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
||||||
return x.get() == y.get();
|
return x.get() == y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator!=(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
bool
|
||||||
|
operator!=(const std::unique_ptr<T1, D1> &x, const uniq_ptr<T2, D2> &y) {
|
||||||
return x.get() != y.get();
|
return x.get() != y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator==(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
|
bool
|
||||||
|
operator==(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
|
||||||
return x.get() == y.get();
|
return x.get() == y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class D1, class T2, class D2>
|
template <class T1, class D1, class T2, class D2>
|
||||||
bool operator!=(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
|
bool
|
||||||
|
operator!=(const uniq_ptr<T1, D1> &x, const std::unique_ptr<T1, D1> &y) {
|
||||||
return x.get() != y.get();
|
return x.get() != y.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class D>
|
template <class T, class D>
|
||||||
bool operator==(const uniq_ptr<T, D> &x, std::nullptr_t) {
|
bool
|
||||||
|
operator==(const uniq_ptr<T, D> &x, std::nullptr_t) {
|
||||||
return !(bool) x;
|
return !(bool) x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class D>
|
template <class T, class D>
|
||||||
bool operator!=(const uniq_ptr<T, D> &x, std::nullptr_t) {
|
bool
|
||||||
|
operator!=(const uniq_ptr<T, D> &x, std::nullptr_t) {
|
||||||
return (bool) x;
|
return (bool) x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class D>
|
template <class T, class D>
|
||||||
bool operator==(std::nullptr_t, const uniq_ptr<T, D> &y) {
|
bool
|
||||||
|
operator==(std::nullptr_t, const uniq_ptr<T, D> &y) {
|
||||||
return !(bool) y;
|
return !(bool) y;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class D>
|
template <class T, class D>
|
||||||
bool operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
|
bool
|
||||||
|
operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
|
||||||
return (bool) y;
|
return (bool) y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +674,8 @@ template<class P>
|
|||||||
using shared_t = std::shared_ptr<typename P::element_type>;
|
using shared_t = std::shared_ptr<typename P::element_type>;
|
||||||
|
|
||||||
template <class P, class T>
|
template <class P, class T>
|
||||||
shared_t<P> make_shared(T *pointer) {
|
shared_t<P>
|
||||||
|
make_shared(T *pointer) {
|
||||||
return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
|
return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,14 +686,19 @@ public:
|
|||||||
using pointer = element_type *;
|
using pointer = element_type *;
|
||||||
using reference = element_type &;
|
using reference = element_type &;
|
||||||
|
|
||||||
wrap_ptr() : _own_ptr { false }, _p { nullptr } {}
|
wrap_ptr():
|
||||||
wrap_ptr(pointer p) : _own_ptr { false }, _p { p } {}
|
_own_ptr { false }, _p { nullptr } {}
|
||||||
wrap_ptr(std::unique_ptr<element_type> &&uniq_p) : _own_ptr { true }, _p { uniq_p.release() } {}
|
wrap_ptr(pointer p):
|
||||||
wrap_ptr(wrap_ptr &&other) : _own_ptr { other._own_ptr }, _p { other._p } {
|
_own_ptr { false }, _p { p } {}
|
||||||
|
wrap_ptr(std::unique_ptr<element_type> &&uniq_p):
|
||||||
|
_own_ptr { true }, _p { uniq_p.release() } {}
|
||||||
|
wrap_ptr(wrap_ptr &&other):
|
||||||
|
_own_ptr { other._own_ptr }, _p { other._p } {
|
||||||
other._own_ptr = false;
|
other._own_ptr = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap_ptr &operator=(wrap_ptr &&other) noexcept {
|
wrap_ptr &
|
||||||
|
operator=(wrap_ptr &&other) noexcept {
|
||||||
if (_own_ptr) {
|
if (_own_ptr) {
|
||||||
delete _p;
|
delete _p;
|
||||||
}
|
}
|
||||||
@@ -642,7 +712,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <class V>
|
||||||
wrap_ptr &operator=(std::unique_ptr<V> &&uniq_ptr) {
|
wrap_ptr &
|
||||||
|
operator=(std::unique_ptr<V> &&uniq_ptr) {
|
||||||
static_assert(std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
static_assert(std::is_base_of_v<element_type, V>, "element_type must be base class of V");
|
||||||
_own_ptr = true;
|
_own_ptr = true;
|
||||||
_p = uniq_ptr.release();
|
_p = uniq_ptr.release();
|
||||||
@@ -650,7 +721,8 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap_ptr &operator=(pointer p) {
|
wrap_ptr &
|
||||||
|
operator=(pointer p) {
|
||||||
if (_own_ptr) {
|
if (_own_ptr) {
|
||||||
delete _p;
|
delete _p;
|
||||||
}
|
}
|
||||||
@@ -669,16 +741,20 @@ public:
|
|||||||
_own_ptr = false;
|
_own_ptr = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reference operator*() const {
|
const reference
|
||||||
|
operator*() const {
|
||||||
return *_p;
|
return *_p;
|
||||||
}
|
}
|
||||||
reference operator*() {
|
reference
|
||||||
|
operator*() {
|
||||||
return *_p;
|
return *_p;
|
||||||
}
|
}
|
||||||
const pointer operator->() const {
|
const pointer
|
||||||
|
operator->() const {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
pointer operator->() {
|
pointer
|
||||||
|
operator->() {
|
||||||
return _p;
|
return _p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,54 +799,68 @@ using optional_t = either_t<
|
|||||||
template <class T>
|
template <class T>
|
||||||
class buffer_t {
|
class buffer_t {
|
||||||
public:
|
public:
|
||||||
buffer_t() : _els { 0 } {};
|
buffer_t():
|
||||||
buffer_t(buffer_t &&o) noexcept : _els { o._els }, _buf { std::move(o._buf) } {
|
_els { 0 } {};
|
||||||
|
buffer_t(buffer_t &&o) noexcept:
|
||||||
|
_els { o._els }, _buf { std::move(o._buf) } {
|
||||||
o._els = 0;
|
o._els = 0;
|
||||||
}
|
}
|
||||||
buffer_t(const buffer_t &o) : _els { o._els }, _buf { std::make_unique<T[]>(_els) } {
|
buffer_t(const buffer_t &o):
|
||||||
|
_els { o._els }, _buf { std::make_unique<T[]>(_els) } {
|
||||||
std::copy(o.begin(), o.end(), begin());
|
std::copy(o.begin(), o.end(), begin());
|
||||||
}
|
}
|
||||||
buffer_t &operator=(buffer_t &&o) noexcept {
|
buffer_t &
|
||||||
|
operator=(buffer_t &&o) noexcept {
|
||||||
std::swap(_els, o._els);
|
std::swap(_els, o._els);
|
||||||
std::swap(_buf, o._buf);
|
std::swap(_buf, o._buf);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit buffer_t(size_t elements) : _els { elements }, _buf { std::make_unique<T[]>(elements) } {}
|
explicit buffer_t(size_t elements):
|
||||||
explicit buffer_t(size_t elements, const T &t) : _els { elements }, _buf { std::make_unique<T[]>(elements) } {
|
_els { elements }, _buf { std::make_unique<T[]>(elements) } {}
|
||||||
|
explicit buffer_t(size_t elements, const T &t):
|
||||||
|
_els { elements }, _buf { std::make_unique<T[]>(elements) } {
|
||||||
std::fill_n(_buf.get(), elements, t);
|
std::fill_n(_buf.get(), elements, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
T &operator[](size_t el) {
|
T &
|
||||||
|
operator[](size_t el) {
|
||||||
return _buf[el];
|
return _buf[el];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &operator[](size_t el) const {
|
const T &
|
||||||
|
operator[](size_t el) const {
|
||||||
return _buf[el];
|
return _buf[el];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t
|
||||||
|
size() const {
|
||||||
return _els;
|
return _els;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fake_resize(std::size_t els) {
|
void
|
||||||
|
fake_resize(std::size_t els) {
|
||||||
_els = els;
|
_els = els;
|
||||||
}
|
}
|
||||||
|
|
||||||
T *begin() {
|
T *
|
||||||
|
begin() {
|
||||||
return _buf.get();
|
return _buf.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *begin() const {
|
const T *
|
||||||
|
begin() const {
|
||||||
return _buf.get();
|
return _buf.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
T *end() {
|
T *
|
||||||
|
end() {
|
||||||
return _buf.get() + _els;
|
return _buf.get() + _els;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T *end() const {
|
const T *
|
||||||
|
end() const {
|
||||||
return _buf.get() + _els;
|
return _buf.get() + _els;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,7 +870,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T either(std::optional<T> &&l, T &&r) {
|
T
|
||||||
|
either(std::optional<T> &&l, T &&r) {
|
||||||
if (l) {
|
if (l) {
|
||||||
return std::move(*l);
|
return std::move(*l);
|
||||||
}
|
}
|
||||||
@@ -797,7 +888,8 @@ template<class T, class ReturnType, typename Function<ReturnType, T>::type funct
|
|||||||
struct Destroy {
|
struct Destroy {
|
||||||
typedef T pointer;
|
typedef T pointer;
|
||||||
|
|
||||||
void operator()(pointer p) {
|
void
|
||||||
|
operator()(pointer p) {
|
||||||
function(p);
|
function(p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -810,12 +902,14 @@ template<class T, class ReturnType, typename Function<ReturnType, T *>::type fun
|
|||||||
using safe_ptr_v2 = uniq_ptr<T, Destroy<T *, ReturnType, function>>;
|
using safe_ptr_v2 = uniq_ptr<T, Destroy<T *, ReturnType, function>>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void c_free(T *p) {
|
void
|
||||||
|
c_free(T *p) {
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class ReturnType, ReturnType (**function)(T *)>
|
template <class T, class ReturnType, ReturnType (**function)(T *)>
|
||||||
void dynamic(T *p) {
|
void
|
||||||
|
dynamic(T *p) {
|
||||||
(*function)(p);
|
(*function)(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,12 +923,14 @@ template<class T>
|
|||||||
using c_ptr = safe_ptr<T, c_free<T>>;
|
using c_ptr = safe_ptr<T, c_free<T>>;
|
||||||
|
|
||||||
template <class It>
|
template <class It>
|
||||||
std::string_view view(It begin, It end) {
|
std::string_view
|
||||||
|
view(It begin, It end) {
|
||||||
return std::string_view { (const char *) begin, (std::size_t)(end - begin) };
|
return std::string_view { (const char *) begin, (std::size_t)(end - begin) };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::string_view view(const T &data) {
|
std::string_view
|
||||||
|
view(const T &data) {
|
||||||
return std::string_view((const char *) &data, sizeof(T));
|
return std::string_view((const char *) &data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +968,8 @@ struct endian_helper {};
|
|||||||
template <class T>
|
template <class T>
|
||||||
struct endian_helper<T, std::enable_if_t<
|
struct endian_helper<T, std::enable_if_t<
|
||||||
!(instantiation_of_v<std::optional, T>)>> {
|
!(instantiation_of_v<std::optional, T>)>> {
|
||||||
static inline T big(T x) {
|
static inline T
|
||||||
|
big(T x) {
|
||||||
if constexpr (endianness<T>::little) {
|
if constexpr (endianness<T>::little) {
|
||||||
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
||||||
|
|
||||||
@@ -882,7 +979,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline T little(T x) {
|
static inline T
|
||||||
|
little(T x) {
|
||||||
if constexpr (endianness<T>::big) {
|
if constexpr (endianness<T>::big) {
|
||||||
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
||||||
|
|
||||||
@@ -896,7 +994,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||||||
template <class T>
|
template <class T>
|
||||||
struct endian_helper<T, std::enable_if_t<
|
struct endian_helper<T, std::enable_if_t<
|
||||||
instantiation_of_v<std::optional, T>>> {
|
instantiation_of_v<std::optional, T>>> {
|
||||||
static inline T little(T x) {
|
static inline T
|
||||||
|
little(T x) {
|
||||||
if (!x) return x;
|
if (!x) return x;
|
||||||
|
|
||||||
if constexpr (endianness<T>::big) {
|
if constexpr (endianness<T>::big) {
|
||||||
@@ -908,8 +1007,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline T
|
||||||
static inline T big(T x) {
|
big(T x) {
|
||||||
if (!x) return x;
|
if (!x) return x;
|
||||||
|
|
||||||
if constexpr (endianness<T>::little) {
|
if constexpr (endianness<T>::little) {
|
||||||
@@ -923,10 +1022,12 @@ struct endian_helper<T, std::enable_if_t<
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline auto little(T x) { return endian_helper<T>::little(x); }
|
inline auto
|
||||||
|
little(T x) { return endian_helper<T>::little(x); }
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline auto big(T x) { return endian_helper<T>::big(x); }
|
inline auto
|
||||||
|
big(T x) { return endian_helper<T>::big(x); }
|
||||||
} // namespace endian
|
} // namespace endian
|
||||||
} // namespace util
|
} // namespace util
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
src/uuid.h
18
src/uuid.h
@@ -12,7 +12,8 @@ union uuid_t {
|
|||||||
std::uint32_t b32[4];
|
std::uint32_t b32[4];
|
||||||
std::uint64_t b64[2];
|
std::uint64_t b64[2];
|
||||||
|
|
||||||
static uuid_t generate(std::default_random_engine &engine) {
|
static uuid_t
|
||||||
|
generate(std::default_random_engine &engine) {
|
||||||
std::uniform_int_distribution<std::uint8_t> dist(0, std::numeric_limits<std::uint8_t>::max());
|
std::uniform_int_distribution<std::uint8_t> dist(0, std::numeric_limits<std::uint8_t>::max());
|
||||||
|
|
||||||
uuid_t buf;
|
uuid_t buf;
|
||||||
@@ -26,7 +27,8 @@ union uuid_t {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uuid_t generate() {
|
static uuid_t
|
||||||
|
generate() {
|
||||||
std::random_device r;
|
std::random_device r;
|
||||||
|
|
||||||
std::default_random_engine engine { r() };
|
std::default_random_engine engine { r() };
|
||||||
@@ -34,7 +36,8 @@ union uuid_t {
|
|||||||
return generate(engine);
|
return generate(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string string() const {
|
[[nodiscard]] std::string
|
||||||
|
string() const {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
result.reserve(sizeof(uuid_t) * 2 + 4);
|
result.reserve(sizeof(uuid_t) * 2 + 4);
|
||||||
@@ -61,15 +64,18 @@ union uuid_t {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const uuid_t &other) const {
|
constexpr bool
|
||||||
|
operator==(const uuid_t &other) const {
|
||||||
return b64[0] == other.b64[0] && b64[1] == other.b64[1];
|
return b64[0] == other.b64[0] && b64[1] == other.b64[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator<(const uuid_t &other) const {
|
constexpr bool
|
||||||
|
operator<(const uuid_t &other) const {
|
||||||
return (b64[0] < other.b64[0] || (b64[0] == other.b64[0] && b64[1] < other.b64[1]));
|
return (b64[0] < other.b64[0] || (b64[0] == other.b64[0] && b64[1] < other.b64[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator>(const uuid_t &other) const {
|
constexpr bool
|
||||||
|
operator>(const uuid_t &other) const {
|
||||||
return (b64[0] > other.b64[0] || (b64[0] == other.b64[0] && b64[1] > other.b64[1]));
|
return (b64[0] > other.b64[0] || (b64[0] == other.b64[0] && b64[1] > other.b64[1]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
157
src/video.cpp
157
src/video.cpp
@@ -30,15 +30,18 @@ namespace video {
|
|||||||
constexpr auto hevc_nalu = "\000\000\000\001("sv;
|
constexpr auto hevc_nalu = "\000\000\000\001("sv;
|
||||||
constexpr auto h264_nalu = "\000\000\000\001e"sv;
|
constexpr auto h264_nalu = "\000\000\000\001e"sv;
|
||||||
|
|
||||||
void free_ctx(AVCodecContext *ctx) {
|
void
|
||||||
|
free_ctx(AVCodecContext *ctx) {
|
||||||
avcodec_free_context(&ctx);
|
avcodec_free_context(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_frame(AVFrame *frame) {
|
void
|
||||||
|
free_frame(AVFrame *frame) {
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_buffer(AVBufferRef *ref) {
|
void
|
||||||
|
free_buffer(AVBufferRef *ref) {
|
||||||
av_buffer_unref(&ref);
|
av_buffer_unref(&ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,19 +81,25 @@ enum class profile_hevc_e : int {
|
|||||||
};
|
};
|
||||||
} // namespace qsv
|
} // namespace qsv
|
||||||
|
|
||||||
|
platf::mem_type_e
|
||||||
|
map_base_dev_type(AVHWDeviceType type);
|
||||||
|
platf::pix_fmt_e
|
||||||
|
map_pix_fmt(AVPixelFormat fmt);
|
||||||
|
|
||||||
platf::mem_type_e map_base_dev_type(AVHWDeviceType type);
|
util::Either<buffer_t, int>
|
||||||
platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt);
|
dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
||||||
|
util::Either<buffer_t, int>
|
||||||
|
vaapi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
||||||
|
util::Either<buffer_t, int>
|
||||||
|
cuda_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
||||||
|
|
||||||
util::Either<buffer_t, int> dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
int
|
||||||
util::Either<buffer_t, int> vaapi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
hwframe_ctx(ctx_t &ctx, platf::hwdevice_t *hwdevice, buffer_t &hwdevice_ctx, AVPixelFormat format);
|
||||||
util::Either<buffer_t, int> cuda_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx);
|
|
||||||
|
|
||||||
int hwframe_ctx(ctx_t &ctx, platf::hwdevice_t *hwdevice, buffer_t &hwdevice_ctx, AVPixelFormat format);
|
|
||||||
|
|
||||||
class swdevice_t: public platf::hwdevice_t {
|
class swdevice_t: public platf::hwdevice_t {
|
||||||
public:
|
public:
|
||||||
int convert(platf::img_t &img) override {
|
int
|
||||||
|
convert(platf::img_t &img) override {
|
||||||
av_frame_make_writable(sw_frame.get());
|
av_frame_make_writable(sw_frame.get());
|
||||||
|
|
||||||
const int linesizes[2] {
|
const int linesizes[2] {
|
||||||
@@ -131,7 +140,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
int
|
||||||
|
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||||
this->frame = frame;
|
this->frame = frame;
|
||||||
|
|
||||||
// If it's a hwframe, allocate buffers for hardware
|
// If it's a hwframe, allocate buffers for hardware
|
||||||
@@ -147,7 +157,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
void
|
||||||
|
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range) override {
|
||||||
sws_setColorspaceDetails(sws.get(),
|
sws_setColorspaceDetails(sws.get(),
|
||||||
sws_getCoefficients(SWS_CS_DEFAULT), 0,
|
sws_getCoefficients(SWS_CS_DEFAULT), 0,
|
||||||
sws_getCoefficients(colorspace), color_range - 1,
|
sws_getCoefficients(colorspace), color_range - 1,
|
||||||
@@ -157,7 +168,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* When preserving aspect ratio, ensure that padding is black
|
* When preserving aspect ratio, ensure that padding is black
|
||||||
*/
|
*/
|
||||||
int prefill() {
|
int
|
||||||
|
prefill() {
|
||||||
auto frame = sw_frame ? sw_frame.get() : this->frame;
|
auto frame = sw_frame ? sw_frame.get() : this->frame;
|
||||||
auto width = frame->width;
|
auto width = frame->width;
|
||||||
auto height = frame->height;
|
auto height = frame->height;
|
||||||
@@ -195,7 +207,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(int in_width, int in_height, AVFrame *frame, AVPixelFormat format, bool hardware) {
|
int
|
||||||
|
init(int in_width, int in_height, AVFrame *frame, AVPixelFormat format, bool hardware) {
|
||||||
// If the device used is hardware, yet the image resides on main memory
|
// If the device used is hardware, yet the image resides on main memory
|
||||||
if (hardware) {
|
if (hardware) {
|
||||||
sw_frame.reset(av_frame_alloc());
|
sw_frame.reset(av_frame_alloc());
|
||||||
@@ -273,7 +286,8 @@ struct encoder_t {
|
|||||||
MAX_FLAGS
|
MAX_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string_view from_flag(flag_e flag) {
|
static std::string_view
|
||||||
|
from_flag(flag_e flag) {
|
||||||
#define _CONVERT(x) \
|
#define _CONVERT(x) \
|
||||||
case flag_e::x: \
|
case flag_e::x: \
|
||||||
return #x##sv
|
return #x##sv
|
||||||
@@ -300,7 +314,8 @@ struct encoder_t {
|
|||||||
std::string name;
|
std::string name;
|
||||||
std::variant<int, int *, std::optional<int> *, std::string, std::string *> value;
|
std::variant<int, int *, std::optional<int> *, std::string, std::string *> value;
|
||||||
|
|
||||||
option_t(std::string &&name, decltype(value) &&value) : name { std::move(name) }, value { std::move(value) } {}
|
option_t(std::string &&name, decltype(value) &&value):
|
||||||
|
name { std::move(name) }, value { std::move(value) } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
AVHWDeviceType base_dev_type, derived_dev_type;
|
AVHWDeviceType base_dev_type, derived_dev_type;
|
||||||
@@ -317,11 +332,13 @@ struct encoder_t {
|
|||||||
std::string name;
|
std::string name;
|
||||||
std::bitset<MAX_FLAGS> capabilities;
|
std::bitset<MAX_FLAGS> capabilities;
|
||||||
|
|
||||||
bool operator[](flag_e flag) const {
|
bool
|
||||||
|
operator[](flag_e flag) const {
|
||||||
return capabilities[(std::size_t) flag];
|
return capabilities[(std::size_t) flag];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::bitset<MAX_FLAGS>::reference operator[](flag_e flag) {
|
std::bitset<MAX_FLAGS>::reference
|
||||||
|
operator[](flag_e flag) {
|
||||||
return capabilities[(std::size_t) flag];
|
return capabilities[(std::size_t) flag];
|
||||||
}
|
}
|
||||||
} hevc, h264;
|
} hevc, h264;
|
||||||
@@ -334,7 +351,8 @@ struct encoder_t {
|
|||||||
class session_t {
|
class session_t {
|
||||||
public:
|
public:
|
||||||
session_t() = default;
|
session_t() = default;
|
||||||
session_t(ctx_t &&ctx, std::shared_ptr<platf::hwdevice_t> &&device, int inject) : ctx { std::move(ctx) }, device { std::move(device) }, inject { inject } {}
|
session_t(ctx_t &&ctx, std::shared_ptr<platf::hwdevice_t> &&device, int inject):
|
||||||
|
ctx { std::move(ctx) }, device { std::move(device) }, inject { inject } {}
|
||||||
|
|
||||||
session_t(session_t &&other) noexcept = default;
|
session_t(session_t &&other) noexcept = default;
|
||||||
~session_t() {
|
~session_t() {
|
||||||
@@ -344,7 +362,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure objects are destroyed in the correct order
|
// Ensure objects are destroyed in the correct order
|
||||||
session_t &operator=(session_t &&other) {
|
session_t &
|
||||||
|
operator=(session_t &&other) {
|
||||||
device = std::move(other.device);
|
device = std::move(other.device);
|
||||||
ctx = std::move(other.ctx);
|
ctx = std::move(other.ctx);
|
||||||
replacements = std::move(other.replacements);
|
replacements = std::move(other.replacements);
|
||||||
@@ -409,10 +428,14 @@ struct capture_thread_sync_ctx_t {
|
|||||||
encode_session_ctx_queue_t encode_session_ctx_queue { 30 };
|
encode_session_ctx_queue_t encode_session_ctx_queue { 30 };
|
||||||
};
|
};
|
||||||
|
|
||||||
int start_capture_sync(capture_thread_sync_ctx_t &ctx);
|
int
|
||||||
void end_capture_sync(capture_thread_sync_ctx_t &ctx);
|
start_capture_sync(capture_thread_sync_ctx_t &ctx);
|
||||||
int start_capture_async(capture_thread_async_ctx_t &ctx);
|
void
|
||||||
void end_capture_async(capture_thread_async_ctx_t &ctx);
|
end_capture_sync(capture_thread_sync_ctx_t &ctx);
|
||||||
|
int
|
||||||
|
start_capture_async(capture_thread_async_ctx_t &ctx);
|
||||||
|
void
|
||||||
|
end_capture_async(capture_thread_async_ctx_t &ctx);
|
||||||
|
|
||||||
// Keep a reference counter to ensure the capture thread only runs when other threads have a reference to the capture thread
|
// Keep a reference counter to ensure the capture thread only runs when other threads have a reference to the capture thread
|
||||||
auto capture_thread_async = safe::make_shared<capture_thread_async_ctx_t>(start_capture_async, end_capture_async);
|
auto capture_thread_async = safe::make_shared<capture_thread_async_ctx_t>(start_capture_async, end_capture_async);
|
||||||
@@ -704,7 +727,8 @@ static std::vector<encoder_t> encoders {
|
|||||||
software
|
software
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type, const std::string &display_name, const config_t &config) {
|
void
|
||||||
|
reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type, const std::string &display_name, const config_t &config) {
|
||||||
// We try this twice, in case we still get an error on reinitialization
|
// We try this twice, in case we still get an error on reinitialization
|
||||||
for (int x = 0; x < 2; ++x) {
|
for (int x = 0; x < 2; ++x) {
|
||||||
disp.reset();
|
disp.reset();
|
||||||
@@ -718,7 +742,8 @@ void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void captureThread(
|
void
|
||||||
|
captureThread(
|
||||||
std::shared_ptr<safe::queue_t<capture_ctx_t>> capture_ctx_queue,
|
std::shared_ptr<safe::queue_t<capture_ctx_t>> capture_ctx_queue,
|
||||||
sync_util::sync_t<std::weak_ptr<platf::display_t>> &display_wp,
|
sync_util::sync_t<std::weak_ptr<platf::display_t>> &display_wp,
|
||||||
safe::signal_t &reinit_event,
|
safe::signal_t &reinit_event,
|
||||||
@@ -822,7 +847,6 @@ void captureThread(
|
|||||||
},
|
},
|
||||||
*round_robin++, &display_cursor);
|
*round_robin++, &display_cursor);
|
||||||
|
|
||||||
|
|
||||||
if (artificial_reinit && status != platf::capture_e::error) {
|
if (artificial_reinit && status != platf::capture_e::error) {
|
||||||
status = platf::capture_e::reinit;
|
status = platf::capture_e::reinit;
|
||||||
|
|
||||||
@@ -898,7 +922,8 @@ void captureThread(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::mail_raw_t::queue_t<packet_t> &packets, void *channel_data) {
|
int
|
||||||
|
encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::mail_raw_t::queue_t<packet_t> &packets, void *channel_data) {
|
||||||
frame->pts = frame_nr;
|
frame->pts = frame_nr;
|
||||||
|
|
||||||
auto &ctx = session.ctx;
|
auto &ctx = session.ctx;
|
||||||
@@ -946,7 +971,6 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m
|
|||||||
|
|
||||||
session.inject = 0;
|
session.inject = 0;
|
||||||
|
|
||||||
|
|
||||||
session.replacements.emplace_back(
|
session.replacements.emplace_back(
|
||||||
std::string_view((char *) std::begin(sps.old), sps.old.size()),
|
std::string_view((char *) std::begin(sps.old), sps.old.size()),
|
||||||
std::string_view((char *) std::begin(sps._new), sps._new.size()));
|
std::string_view((char *) std::begin(sps._new), sps._new.size()));
|
||||||
@@ -960,7 +984,8 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<session_t> make_session(platf::display_t *disp, const encoder_t &encoder, const config_t &config, int width, int height, std::shared_ptr<platf::hwdevice_t> &&hwdevice) {
|
std::optional<session_t>
|
||||||
|
make_session(platf::display_t *disp, const encoder_t &encoder, const config_t &config, int width, int height, std::shared_ptr<platf::hwdevice_t> &&hwdevice) {
|
||||||
bool hardware = encoder.base_dev_type != AV_HWDEVICE_TYPE_NONE;
|
bool hardware = encoder.base_dev_type != AV_HWDEVICE_TYPE_NONE;
|
||||||
|
|
||||||
auto &video_format = config.videoFormat == 0 ? encoder.h264 : encoder.hevc;
|
auto &video_format = config.videoFormat == 0 ? encoder.h264 : encoder.hevc;
|
||||||
@@ -1270,7 +1295,8 @@ std::optional<session_t> make_session(platf::display_t *disp, const encoder_t &e
|
|||||||
return std::make_optional(std::move(session));
|
return std::make_optional(std::move(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
void encode_run(
|
void
|
||||||
|
encode_run(
|
||||||
int &frame_nr, // Store progress of the frame number
|
int &frame_nr, // Store progress of the frame number
|
||||||
safe::mail_t mail,
|
safe::mail_t mail,
|
||||||
img_event_t images,
|
img_event_t images,
|
||||||
@@ -1280,7 +1306,6 @@ void encode_run(
|
|||||||
safe::signal_t &reinit_event,
|
safe::signal_t &reinit_event,
|
||||||
const encoder_t &encoder,
|
const encoder_t &encoder,
|
||||||
void *channel_data) {
|
void *channel_data) {
|
||||||
|
|
||||||
auto session = make_session(disp.get(), encoder, config, disp->width, disp->height, std::move(hwdevice));
|
auto session = make_session(disp.get(), encoder, config, disp->width, disp->height, std::move(hwdevice));
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return;
|
return;
|
||||||
@@ -1334,7 +1359,8 @@ void encode_run(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input::touch_port_t make_port(platf::display_t *display, const config_t &config) {
|
input::touch_port_t
|
||||||
|
make_port(platf::display_t *display, const config_t &config) {
|
||||||
float wd = display->width;
|
float wd = display->width;
|
||||||
float hd = display->height;
|
float hd = display->height;
|
||||||
|
|
||||||
@@ -1362,7 +1388,8 @@ input::touch_port_t make_port(platf::display_t *display, const config_t &config)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sync_session_t> make_synced_session(platf::display_t *disp, const encoder_t &encoder, platf::img_t &img, sync_session_ctx_t &ctx) {
|
std::optional<sync_session_t>
|
||||||
|
make_synced_session(platf::display_t *disp, const encoder_t &encoder, platf::img_t &img, sync_session_ctx_t &ctx) {
|
||||||
sync_session_t encode_session;
|
sync_session_t encode_session;
|
||||||
|
|
||||||
encode_session.ctx = &ctx;
|
encode_session.ctx = &ctx;
|
||||||
@@ -1394,10 +1421,10 @@ std::optional<sync_session_t> make_synced_session(platf::display_t *disp, const
|
|||||||
return std::move(encode_session);
|
return std::move(encode_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
encode_e encode_run_sync(
|
encode_e
|
||||||
|
encode_run_sync(
|
||||||
std::vector<std::unique_ptr<sync_session_ctx_t>> &synced_session_ctxs,
|
std::vector<std::unique_ptr<sync_session_ctx_t>> &synced_session_ctxs,
|
||||||
encode_session_ctx_queue_t &encode_session_ctx_queue) {
|
encode_session_ctx_queue_t &encode_session_ctx_queue) {
|
||||||
|
|
||||||
const auto &encoder = encoders.front();
|
const auto &encoder = encoders.front();
|
||||||
auto display_names = platf::display_names(map_base_dev_type(encoder.base_dev_type));
|
auto display_names = platf::display_names(map_base_dev_type(encoder.base_dev_type));
|
||||||
int display_p = 0;
|
int display_p = 0;
|
||||||
@@ -1543,7 +1570,8 @@ encode_e encode_run_sync(
|
|||||||
return encode_e::ok;
|
return encode_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void captureThreadSync() {
|
void
|
||||||
|
captureThreadSync() {
|
||||||
auto ref = capture_thread_sync.ref();
|
auto ref = capture_thread_sync.ref();
|
||||||
|
|
||||||
std::vector<std::unique_ptr<sync_session_ctx_t>> synced_session_ctxs;
|
std::vector<std::unique_ptr<sync_session_ctx_t>> synced_session_ctxs;
|
||||||
@@ -1569,11 +1597,11 @@ void captureThreadSync() {
|
|||||||
while (encode_run_sync(synced_session_ctxs, ctx) == encode_e::reinit) {}
|
while (encode_run_sync(synced_session_ctxs, ctx) == encode_e::reinit) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void capture_async(
|
void
|
||||||
|
capture_async(
|
||||||
safe::mail_t mail,
|
safe::mail_t mail,
|
||||||
config_t &config,
|
config_t &config,
|
||||||
void *channel_data) {
|
void *channel_data) {
|
||||||
|
|
||||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||||
|
|
||||||
auto images = std::make_shared<img_event_t::element_type>();
|
auto images = std::make_shared<img_event_t::element_type>();
|
||||||
@@ -1646,11 +1674,11 @@ void capture_async(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void capture(
|
void
|
||||||
|
capture(
|
||||||
safe::mail_t mail,
|
safe::mail_t mail,
|
||||||
config_t config,
|
config_t config,
|
||||||
void *channel_data) {
|
void *channel_data) {
|
||||||
|
|
||||||
auto idr_events = mail->event<bool>(mail::idr);
|
auto idr_events = mail->event<bool>(mail::idr);
|
||||||
|
|
||||||
idr_events->raise(true);
|
idr_events->raise(true);
|
||||||
@@ -1682,7 +1710,8 @@ enum validate_flag_e {
|
|||||||
NALU_PREFIX_5b = 0x02,
|
NALU_PREFIX_5b = 0x02,
|
||||||
};
|
};
|
||||||
|
|
||||||
int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &encoder, const config_t &config) {
|
int
|
||||||
|
validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &encoder, const config_t &config) {
|
||||||
reset_display(disp, encoder.base_dev_type, config::video.output_name, config);
|
reset_display(disp, encoder.base_dev_type, config::video.output_name, config);
|
||||||
if (!disp) {
|
if (!disp) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1740,7 +1769,8 @@ int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &en
|
|||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_encoder(encoder_t &encoder) {
|
bool
|
||||||
|
validate_encoder(encoder_t &encoder) {
|
||||||
std::shared_ptr<platf::display_t> disp;
|
std::shared_ptr<platf::display_t> disp;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Trying encoder ["sv << encoder.name << ']';
|
BOOST_LOG(info) << "Trying encoder ["sv << encoder.name << ']';
|
||||||
@@ -1868,7 +1898,8 @@ retry:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init() {
|
int
|
||||||
|
init() {
|
||||||
bool encoder_found = false;
|
bool encoder_found = false;
|
||||||
if (!config::video.encoder.empty()) {
|
if (!config::video.encoder.empty()) {
|
||||||
// If there is a specific encoder specified, use it if it passes validation
|
// If there is a specific encoder specified, use it if it passes validation
|
||||||
@@ -1985,7 +2016,8 @@ int init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hwframe_ctx(ctx_t &ctx, platf::hwdevice_t *hwdevice, buffer_t &hwdevice_ctx, AVPixelFormat format) {
|
int
|
||||||
|
hwframe_ctx(ctx_t &ctx, platf::hwdevice_t *hwdevice, buffer_t &hwdevice_ctx, AVPixelFormat format) {
|
||||||
buffer_t frame_ref { av_hwframe_ctx_alloc(hwdevice_ctx.get()) };
|
buffer_t frame_ref { av_hwframe_ctx_alloc(hwdevice_ctx.get()) };
|
||||||
|
|
||||||
auto frame_ctx = (AVHWFramesContext *) frame_ref->data;
|
auto frame_ctx = (AVHWFramesContext *) frame_ref->data;
|
||||||
@@ -2010,7 +2042,8 @@ int hwframe_ctx(ctx_t &ctx, platf::hwdevice_t *hwdevice, buffer_t &hwdevice_ctx,
|
|||||||
// Linux only declaration
|
// Linux only declaration
|
||||||
typedef int (*vaapi_make_hwdevice_ctx_fn)(platf::hwdevice_t *base, AVBufferRef **hw_device_buf);
|
typedef int (*vaapi_make_hwdevice_ctx_fn)(platf::hwdevice_t *base, AVBufferRef **hw_device_buf);
|
||||||
|
|
||||||
util::Either<buffer_t, int> vaapi_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
util::Either<buffer_t, int>
|
||||||
|
vaapi_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
||||||
buffer_t hw_device_buf;
|
buffer_t hw_device_buf;
|
||||||
|
|
||||||
// If an egl hwdevice
|
// If an egl hwdevice
|
||||||
@@ -2034,7 +2067,8 @@ util::Either<buffer_t, int> vaapi_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
|||||||
return hw_device_buf;
|
return hw_device_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Either<buffer_t, int> cuda_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
util::Either<buffer_t, int>
|
||||||
|
cuda_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
||||||
buffer_t hw_device_buf;
|
buffer_t hw_device_buf;
|
||||||
|
|
||||||
auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_CUDA, nullptr, nullptr, 1 /* AV_CUDA_USE_PRIMARY_CONTEXT */);
|
auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_CUDA, nullptr, nullptr, 1 /* AV_CUDA_USE_PRIMARY_CONTEXT */);
|
||||||
@@ -2050,10 +2084,12 @@ util::Either<buffer_t, int> cuda_make_hwdevice_ctx(platf::hwdevice_t *base) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_nothing(void *) {}
|
void
|
||||||
|
do_nothing(void *) {}
|
||||||
|
|
||||||
namespace video {
|
namespace video {
|
||||||
util::Either<buffer_t, int> dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) {
|
util::Either<buffer_t, int>
|
||||||
|
dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) {
|
||||||
buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) };
|
buffer_t ctx_buf { av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA) };
|
||||||
auto ctx = (AVD3D11VADeviceContext *) ((AVHWDeviceContext *) ctx_buf->data)->hwctx;
|
auto ctx = (AVD3D11VADeviceContext *) ((AVHWDeviceContext *) ctx_buf->data)->hwctx;
|
||||||
|
|
||||||
@@ -2080,7 +2116,8 @@ util::Either<buffer_t, int> dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_c
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
int
|
||||||
|
start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
||||||
capture_thread_ctx.encoder_p = &encoders.front();
|
capture_thread_ctx.encoder_p = &encoders.front();
|
||||||
capture_thread_ctx.reinit_event.reset();
|
capture_thread_ctx.reinit_event.reset();
|
||||||
|
|
||||||
@@ -2096,19 +2133,23 @@ int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void end_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
void
|
||||||
|
end_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
||||||
capture_thread_ctx.capture_ctx_queue->stop();
|
capture_thread_ctx.capture_ctx_queue->stop();
|
||||||
|
|
||||||
capture_thread_ctx.capture_thread.join();
|
capture_thread_ctx.capture_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_capture_sync(capture_thread_sync_ctx_t &ctx) {
|
int
|
||||||
|
start_capture_sync(capture_thread_sync_ctx_t &ctx) {
|
||||||
std::thread { &captureThreadSync }.detach();
|
std::thread { &captureThreadSync }.detach();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void end_capture_sync(capture_thread_sync_ctx_t &ctx) {}
|
void
|
||||||
|
end_capture_sync(capture_thread_sync_ctx_t &ctx) {}
|
||||||
|
|
||||||
platf::mem_type_e map_base_dev_type(AVHWDeviceType type) {
|
platf::mem_type_e
|
||||||
|
map_base_dev_type(AVHWDeviceType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AV_HWDEVICE_TYPE_D3D11VA:
|
case AV_HWDEVICE_TYPE_D3D11VA:
|
||||||
return platf::mem_type_e::dxgi;
|
return platf::mem_type_e::dxgi;
|
||||||
@@ -2125,7 +2166,8 @@ platf::mem_type_e map_base_dev_type(AVHWDeviceType type) {
|
|||||||
return platf::mem_type_e::unknown;
|
return platf::mem_type_e::unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt) {
|
platf::pix_fmt_e
|
||||||
|
map_pix_fmt(AVPixelFormat fmt) {
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case AV_PIX_FMT_YUV420P10:
|
case AV_PIX_FMT_YUV420P10:
|
||||||
return platf::pix_fmt_e::yuv420p10;
|
return platf::pix_fmt_e::yuv420p10;
|
||||||
@@ -2142,7 +2184,8 @@ platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt) {
|
|||||||
return platf::pix_fmt_e::unknown;
|
return platf::pix_fmt_e::unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
color_t make_color_matrix(float Cr, float Cb, const float2 &range_Y, const float2 &range_UV) {
|
color_t
|
||||||
|
make_color_matrix(float Cr, float Cb, const float2 &range_Y, const float2 &range_UV) {
|
||||||
float Cg = 1.0f - Cr - Cb;
|
float Cg = 1.0f - Cr - Cb;
|
||||||
|
|
||||||
float Cr_i = 1.0f - Cr;
|
float Cr_i = 1.0f - Cr;
|
||||||
|
|||||||
24
src/video.h
24
src/video.h
@@ -15,16 +15,19 @@ struct AVPacket;
|
|||||||
namespace video {
|
namespace video {
|
||||||
|
|
||||||
struct packet_raw_t {
|
struct packet_raw_t {
|
||||||
void init_packet() {
|
void
|
||||||
|
init_packet() {
|
||||||
this->av_packet = av_packet_alloc();
|
this->av_packet = av_packet_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
explicit packet_raw_t(P *user_data) : channel_data { user_data } {
|
explicit packet_raw_t(P *user_data):
|
||||||
|
channel_data { user_data } {
|
||||||
init_packet();
|
init_packet();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit packet_raw_t(std::nullptr_t) : channel_data { nullptr } {
|
explicit packet_raw_t(std::nullptr_t):
|
||||||
|
channel_data { nullptr } {
|
||||||
init_packet();
|
init_packet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +41,8 @@ struct packet_raw_t {
|
|||||||
|
|
||||||
KITTY_DEFAULT_CONSTR_MOVE(replace_t)
|
KITTY_DEFAULT_CONSTR_MOVE(replace_t)
|
||||||
|
|
||||||
replace_t(std::string_view old, std::string_view _new) noexcept : old { std::move(old) }, _new { std::move(_new) } {}
|
replace_t(std::string_view old, std::string_view _new) noexcept:
|
||||||
|
old { std::move(old) }, _new { std::move(_new) } {}
|
||||||
};
|
};
|
||||||
|
|
||||||
AVPacket *av_packet;
|
AVPacket *av_packet;
|
||||||
@@ -49,8 +53,10 @@ struct packet_raw_t {
|
|||||||
using packet_t = std::unique_ptr<packet_raw_t>;
|
using packet_t = std::unique_ptr<packet_raw_t>;
|
||||||
|
|
||||||
struct hdr_info_raw_t {
|
struct hdr_info_raw_t {
|
||||||
explicit hdr_info_raw_t(bool enabled) : enabled { enabled }, metadata {} {};
|
explicit hdr_info_raw_t(bool enabled):
|
||||||
explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata) : enabled { enabled }, metadata { metadata } {};
|
enabled { enabled }, metadata {} {};
|
||||||
|
explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata):
|
||||||
|
enabled { enabled }, metadata { metadata } {};
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
SS_HDR_METADATA metadata;
|
SS_HDR_METADATA metadata;
|
||||||
@@ -84,12 +90,14 @@ struct alignas(16) color_t {
|
|||||||
|
|
||||||
extern color_t colors[6];
|
extern color_t colors[6];
|
||||||
|
|
||||||
void capture(
|
void
|
||||||
|
capture(
|
||||||
safe::mail_t mail,
|
safe::mail_t mail,
|
||||||
config_t config,
|
config_t config,
|
||||||
void *channel_data);
|
void *channel_data);
|
||||||
|
|
||||||
int init();
|
int
|
||||||
|
init();
|
||||||
} // namespace video
|
} // namespace video
|
||||||
|
|
||||||
#endif // SUNSHINE_VIDEO_H
|
#endif // SUNSHINE_VIDEO_H
|
||||||
|
|||||||
2
third-party/ViGEmClient
vendored
2
third-party/ViGEmClient
vendored
Submodule third-party/ViGEmClient updated: 726404ef55...9e842ba1c3
2
third-party/ffmpeg-linux-aarch64
vendored
2
third-party/ffmpeg-linux-aarch64
vendored
Submodule third-party/ffmpeg-linux-aarch64 updated: 4a29f4eeaf...22034b2baf
2
third-party/ffmpeg-linux-x86_64
vendored
2
third-party/ffmpeg-linux-x86_64
vendored
Submodule third-party/ffmpeg-linux-x86_64 updated: 05eff50663...d8f29a064c
2
third-party/ffmpeg-macos-aarch64
vendored
2
third-party/ffmpeg-macos-aarch64
vendored
Submodule third-party/ffmpeg-macos-aarch64 updated: 645dcc5666...5876c4b765
2
third-party/ffmpeg-macos-x86_64
vendored
2
third-party/ffmpeg-macos-x86_64
vendored
Submodule third-party/ffmpeg-macos-x86_64 updated: 759f5fc216...d75ce5ffee
2
third-party/ffmpeg-windows-x86_64
vendored
2
third-party/ffmpeg-windows-x86_64
vendored
Submodule third-party/ffmpeg-windows-x86_64 updated: b05f94a92e...c4d6360a59
2
third-party/glad/include/EGL/eglplatform.h
vendored
2
third-party/glad/include/EGL/eglplatform.h
vendored
@@ -148,7 +148,6 @@ typedef EGLNativeDisplayType NativeDisplayType;
|
|||||||
typedef EGLNativePixmapType NativePixmapType;
|
typedef EGLNativePixmapType NativePixmapType;
|
||||||
typedef EGLNativeWindowType NativeWindowType;
|
typedef EGLNativeWindowType NativeWindowType;
|
||||||
|
|
||||||
|
|
||||||
/* Define EGLint. This must be a signed integral type large enough to contain
|
/* Define EGLint. This must be a signed integral type large enough to contain
|
||||||
* all legal attribute names and values passed into and out of EGL, whether
|
* all legal attribute names and values passed into and out of EGL, whether
|
||||||
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
|
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
|
||||||
@@ -158,7 +157,6 @@ typedef EGLNativeWindowType NativeWindowType;
|
|||||||
*/
|
*/
|
||||||
typedef khronos_int32_t EGLint;
|
typedef khronos_int32_t EGLint;
|
||||||
|
|
||||||
|
|
||||||
/* C++ / C typecast macros for special EGL handle values */
|
/* C++ / C typecast macros for special EGL handle values */
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
#define EGL_CAST(type, value) (static_cast<type>(value))
|
#define EGL_CAST(type, value) (static_cast<type>(value))
|
||||||
|
|||||||
2
third-party/glad/include/KHR/khrplatform.h
vendored
2
third-party/glad/include/KHR/khrplatform.h
vendored
@@ -142,7 +142,6 @@
|
|||||||
*-----------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------*/
|
||||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using <stdint.h>
|
* Using <stdint.h>
|
||||||
*/
|
*/
|
||||||
@@ -221,7 +220,6 @@ typedef uint64_t khronos_uint64_t;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types that are (so far) the same on all platforms
|
* Types that are (so far) the same on all platforms
|
||||||
*/
|
*/
|
||||||
|
|||||||
19
third-party/glad/include/glad/egl.h
vendored
19
third-party/glad/include/glad/egl.h
vendored
@@ -28,7 +28,6 @@
|
|||||||
#ifndef GLAD_EGL_H_
|
#ifndef GLAD_EGL_H_
|
||||||
#define GLAD_EGL_H_
|
#define GLAD_EGL_H_
|
||||||
|
|
||||||
|
|
||||||
#define GLAD_EGL
|
#define GLAD_EGL
|
||||||
#define GLAD_OPTION_EGL_LOADER
|
#define GLAD_OPTION_EGL_LOADER
|
||||||
|
|
||||||
@@ -316,12 +315,10 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
|
|||||||
#define EGL_WIDTH 0x3057
|
#define EGL_WIDTH 0x3057
|
||||||
#define EGL_WINDOW_BIT 0x0004
|
#define EGL_WINDOW_BIT 0x0004
|
||||||
|
|
||||||
|
|
||||||
#include <KHR/khrplatform.h>
|
#include <KHR/khrplatform.h>
|
||||||
|
|
||||||
#include <EGL/eglplatform.h>
|
#include <EGL/eglplatform.h>
|
||||||
|
|
||||||
|
|
||||||
struct AHardwareBuffer;
|
struct AHardwareBuffer;
|
||||||
|
|
||||||
struct wl_buffer;
|
struct wl_buffer;
|
||||||
@@ -330,7 +327,6 @@ struct wl_display;
|
|||||||
|
|
||||||
struct wl_resource;
|
struct wl_resource;
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned int EGLBoolean;
|
typedef unsigned int EGLBoolean;
|
||||||
|
|
||||||
typedef unsigned int EGLenum;
|
typedef unsigned int EGLenum;
|
||||||
@@ -410,7 +406,6 @@ typedef void(GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error, const char *command,
|
|||||||
|
|
||||||
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
|
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
|
||||||
|
|
||||||
|
|
||||||
#define EGL_VERSION_1_0 1
|
#define EGL_VERSION_1_0 1
|
||||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_0;
|
GLAD_API_CALL int GLAD_EGL_VERSION_1_0;
|
||||||
#define EGL_VERSION_1_1 1
|
#define EGL_VERSION_1_1 1
|
||||||
@@ -424,7 +419,6 @@ GLAD_API_CALL int GLAD_EGL_VERSION_1_4;
|
|||||||
#define EGL_VERSION_1_5 1
|
#define EGL_VERSION_1_5 1
|
||||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
|
GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
|
||||||
|
|
||||||
|
|
||||||
typedef EGLBoolean(GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api);
|
typedef EGLBoolean(GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api);
|
||||||
typedef EGLBoolean(GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
typedef EGLBoolean(GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
||||||
typedef EGLBoolean(GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
|
typedef EGLBoolean(GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
|
||||||
@@ -567,15 +561,18 @@ GLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative;
|
|||||||
GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync;
|
GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync;
|
||||||
#define eglWaitSync glad_eglWaitSync
|
#define eglWaitSync glad_eglWaitSync
|
||||||
|
|
||||||
|
GLAD_API_CALL int
|
||||||
GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
|
gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
|
||||||
GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load);
|
GLAD_API_CALL int
|
||||||
|
gladLoadEGL(EGLDisplay display, GLADloadfunc load);
|
||||||
|
|
||||||
#ifdef GLAD_EGL
|
#ifdef GLAD_EGL
|
||||||
|
|
||||||
GLAD_API_CALL int gladLoaderLoadEGL(EGLDisplay display);
|
GLAD_API_CALL int
|
||||||
|
gladLoaderLoadEGL(EGLDisplay display);
|
||||||
|
|
||||||
GLAD_API_CALL void gladLoaderUnloadEGL(void);
|
GLAD_API_CALL void
|
||||||
|
gladLoaderUnloadEGL(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
16
third-party/glad/include/glad/gl.h
vendored
16
third-party/glad/include/glad/gl.h
vendored
@@ -1983,7 +1983,6 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
|
|||||||
#define GL_ZOOM_X 0x0D16
|
#define GL_ZOOM_X 0x0D16
|
||||||
#define GL_ZOOM_Y 0x0D17
|
#define GL_ZOOM_Y 0x0D17
|
||||||
|
|
||||||
|
|
||||||
#include <KHR/khrplatform.h>
|
#include <KHR/khrplatform.h>
|
||||||
|
|
||||||
typedef unsigned int GLenum;
|
typedef unsigned int GLenum;
|
||||||
@@ -2090,7 +2089,6 @@ typedef GLintptr GLvdpauSurfaceNV;
|
|||||||
|
|
||||||
typedef void(GLAD_API_PTR *GLVULKANPROCNV)(void);
|
typedef void(GLAD_API_PTR *GLVULKANPROCNV)(void);
|
||||||
|
|
||||||
|
|
||||||
#define GL_VERSION_1_0 1
|
#define GL_VERSION_1_0 1
|
||||||
#define GL_VERSION_1_1 1
|
#define GL_VERSION_1_1 1
|
||||||
#define GL_VERSION_1_2 1
|
#define GL_VERSION_1_2 1
|
||||||
@@ -4235,15 +4233,17 @@ typedef struct GladGLContext {
|
|||||||
PFNGLWINDOWPOS3SVPROC WindowPos3sv;
|
PFNGLWINDOWPOS3SVPROC WindowPos3sv;
|
||||||
} GladGLContext;
|
} GladGLContext;
|
||||||
|
|
||||||
|
GLAD_API_CALL int
|
||||||
GLAD_API_CALL int gladLoadGLContextUserPtr(GladGLContext *context, GLADuserptrloadfunc load, void *userptr);
|
gladLoadGLContextUserPtr(GladGLContext *context, GLADuserptrloadfunc load, void *userptr);
|
||||||
GLAD_API_CALL int gladLoadGLContext(GladGLContext *context, GLADloadfunc load);
|
GLAD_API_CALL int
|
||||||
|
gladLoadGLContext(GladGLContext *context, GLADloadfunc load);
|
||||||
|
|
||||||
#ifdef GLAD_GL
|
#ifdef GLAD_GL
|
||||||
|
|
||||||
GLAD_API_CALL int gladLoaderLoadGLContext(GladGLContext *context);
|
GLAD_API_CALL int
|
||||||
GLAD_API_CALL void gladLoaderUnloadGL(void);
|
gladLoaderLoadGLContext(GladGLContext *context);
|
||||||
|
GLAD_API_CALL void
|
||||||
|
gladLoaderUnloadGL(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
2
third-party/miniupnp
vendored
2
third-party/miniupnp
vendored
Submodule third-party/miniupnp updated: e439318cf7...014c9df8ee
2
third-party/moonlight-common-c
vendored
2
third-party/moonlight-common-c
vendored
Submodule third-party/moonlight-common-c updated: c9426a6a71...d3cb8131d1
2
third-party/nanors
vendored
2
third-party/nanors
vendored
Submodule third-party/nanors updated: e9e242e98e...395e5ada44
45
third-party/nvfbc/NvFBC.h
vendored
45
third-party/nvfbc/NvFBC.h
vendored
@@ -1525,7 +1525,8 @@ typedef struct _NVFBC_TOGL_GRAB_FRAME_PARAMS {
|
|||||||
* A NULL terminated error message, or an empty string. Its maximum length
|
* A NULL terminated error message, or an empty string. Its maximum length
|
||||||
* is NVFBC_ERROR_STR_LEN.
|
* is NVFBC_ERROR_STR_LEN.
|
||||||
*/
|
*/
|
||||||
const char *NVFBCAPI NvFBCGetLastErrorStr(const NVFBC_SESSION_HANDLE sessionHandle);
|
const char *NVFBCAPI
|
||||||
|
NvFBCGetLastErrorStr(const NVFBC_SESSION_HANDLE sessionHandle);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Allocates a new handle for an NvFBC client.
|
* \brief Allocates a new handle for an NvFBC client.
|
||||||
@@ -1551,7 +1552,8 @@ const char *NVFBCAPI NvFBCGetLastErrorStr(const NVFBC_SESSION_HANDLE sessionHand
|
|||||||
* ::NVFBC_ERR_GL
|
* ::NVFBC_ERR_GL
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCCreateHandle(NVFBC_SESSION_HANDLE *pSessionHandle, NVFBC_CREATE_HANDLE_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCCreateHandle(NVFBC_SESSION_HANDLE *pSessionHandle, NVFBC_CREATE_HANDLE_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destroys the handle of an NvFBC client.
|
* \brief Destroys the handle of an NvFBC client.
|
||||||
@@ -1577,7 +1579,8 @@ NVFBCSTATUS NVFBCAPI NvFBCCreateHandle(NVFBC_SESSION_HANDLE *pSessionHandle, NVF
|
|||||||
* ::NVFBC_ERR_CONTEXT \n
|
* ::NVFBC_ERR_CONTEXT \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCDestroyHandle(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_HANDLE_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCDestroyHandle(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_HANDLE_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the current status of the display driver.
|
* \brief Gets the current status of the display driver.
|
||||||
@@ -1596,7 +1599,8 @@ NVFBCSTATUS NVFBCAPI NvFBCDestroyHandle(const NVFBC_SESSION_HANDLE sessionHandle
|
|||||||
* ::NVFBC_ERR_INTERNAL \n
|
* ::NVFBC_ERR_INTERNAL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCGetStatus(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_GET_STATUS_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCGetStatus(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_GET_STATUS_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Binds the FBC context to the calling thread.
|
* \brief Binds the FBC context to the calling thread.
|
||||||
@@ -1630,7 +1634,8 @@ NVFBCSTATUS NVFBCAPI NvFBCGetStatus(const NVFBC_SESSION_HANDLE sessionHandle, NV
|
|||||||
* ::NVFBC_ERR_INTERNAL \n
|
* ::NVFBC_ERR_INTERNAL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCBindContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_BIND_CONTEXT_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCBindContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_BIND_CONTEXT_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Releases the FBC context from the calling thread.
|
* \brief Releases the FBC context from the calling thread.
|
||||||
@@ -1651,7 +1656,8 @@ NVFBCSTATUS NVFBCAPI NvFBCBindContext(const NVFBC_SESSION_HANDLE sessionHandle,
|
|||||||
* ::NVFBC_ERR_INTERNAL \n
|
* ::NVFBC_ERR_INTERNAL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCReleaseContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_RELEASE_CONTEXT_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCReleaseContext(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_RELEASE_CONTEXT_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates a capture session for an FBC client.
|
* \brief Creates a capture session for an FBC client.
|
||||||
@@ -1686,7 +1692,8 @@ NVFBCSTATUS NVFBCAPI NvFBCReleaseContext(const NVFBC_SESSION_HANDLE sessionHandl
|
|||||||
* ::NVFBC_ERR_MUST_RECREATE \n
|
* ::NVFBC_ERR_MUST_RECREATE \n
|
||||||
* ::NVFBC_ERR_INTERNAL
|
* ::NVFBC_ERR_INTERNAL
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCCreateCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_CREATE_CAPTURE_SESSION_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCCreateCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_CREATE_CAPTURE_SESSION_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destroys a capture session for an FBC client.
|
* \brief Destroys a capture session for an FBC client.
|
||||||
@@ -1710,7 +1717,8 @@ NVFBCSTATUS NVFBCAPI NvFBCCreateCaptureSession(const NVFBC_SESSION_HANDLE sessio
|
|||||||
* ::NVFBC_ERR_INTERNAL \n
|
* ::NVFBC_ERR_INTERNAL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCDestroyCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_CAPTURE_SESSION_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCDestroyCaptureSession(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_DESTROY_CAPTURE_SESSION_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets up a capture to system memory session.
|
* \brief Sets up a capture to system memory session.
|
||||||
@@ -1742,7 +1750,8 @@ NVFBCSTATUS NVFBCAPI NvFBCDestroyCaptureSession(const NVFBC_SESSION_HANDLE sessi
|
|||||||
* ::NVFBC_ERR_OUT_OF_MEMORY \n
|
* ::NVFBC_ERR_OUT_OF_MEMORY \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToSysSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_SETUP_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToSysSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_SETUP_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Captures a frame to a buffer in system memory.
|
* \brief Captures a frame to a buffer in system memory.
|
||||||
@@ -1782,7 +1791,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToSysSetUp(const NVFBC_SESSION_HANDLE sessionHandle, N
|
|||||||
* \see NvFBCCreateCaptureSession \n
|
* \see NvFBCCreateCaptureSession \n
|
||||||
* \see NvFBCToSysSetUp
|
* \see NvFBCToSysSetUp
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToSysGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_GRAB_FRAME_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToSysGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOSYS_GRAB_FRAME_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets up a capture to video memory session.
|
* \brief Sets up a capture to video memory session.
|
||||||
@@ -1809,7 +1819,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToSysGrabFrame(const NVFBC_SESSION_HANDLE sessionHandl
|
|||||||
* ::NVFBC_ERR_GL \n
|
* ::NVFBC_ERR_GL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToCudaSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_SETUP_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToCudaSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_SETUP_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Captures a frame to a CUDA device in video memory.
|
* \brief Captures a frame to a CUDA device in video memory.
|
||||||
@@ -1838,7 +1849,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToCudaSetUp(const NVFBC_SESSION_HANDLE sessionHandle,
|
|||||||
* \see NvFBCCreateCaptureSession \n
|
* \see NvFBCCreateCaptureSession \n
|
||||||
* \see NvFBCToCudaSetUp
|
* \see NvFBCToCudaSetUp
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToCudaGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_GRAB_FRAME_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToCudaGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOCUDA_GRAB_FRAME_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets up a capture to OpenGL buffer in video memory session.
|
* \brief Sets up a capture to OpenGL buffer in video memory session.
|
||||||
@@ -1865,7 +1877,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToCudaGrabFrame(const NVFBC_SESSION_HANDLE sessionHand
|
|||||||
* ::NVFBC_ERR_GL \n
|
* ::NVFBC_ERR_GL \n
|
||||||
* ::NVFBC_ERR_X
|
* ::NVFBC_ERR_X
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToGLSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_SETUP_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToGLSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_SETUP_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Captures a frame to an OpenGL buffer in video memory.
|
* \brief Captures a frame to an OpenGL buffer in video memory.
|
||||||
@@ -1893,7 +1906,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToGLSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NV
|
|||||||
* \see NvFBCCreateCaptureSession \n
|
* \see NvFBCCreateCaptureSession \n
|
||||||
* \see NvFBCToCudaSetUp
|
* \see NvFBCToCudaSetUp
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCToGLGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_GRAB_FRAME_PARAMS *pParams);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCToGLGrabFrame(const NVFBC_SESSION_HANDLE sessionHandle, NVFBC_TOGL_GRAB_FRAME_PARAMS *pParams);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \cond FBC_PFN
|
* \cond FBC_PFN
|
||||||
@@ -1966,7 +1980,8 @@ typedef struct
|
|||||||
* ::NVFBC_ERR_INVALID_PTR \n
|
* ::NVFBC_ERR_INVALID_PTR \n
|
||||||
* ::NVFBC_ERR_API_VERSION
|
* ::NVFBC_ERR_API_VERSION
|
||||||
*/
|
*/
|
||||||
NVFBCSTATUS NVFBCAPI NvFBCCreateInstance(NVFBC_API_FUNCTION_LIST *pFunctionList);
|
NVFBCSTATUS NVFBCAPI
|
||||||
|
NvFBCCreateInstance(NVFBC_API_FUNCTION_LIST *pFunctionList);
|
||||||
/*!
|
/*!
|
||||||
* \ingroup FBC_FUNC
|
* \ingroup FBC_FUNC
|
||||||
*
|
*
|
||||||
|
|||||||
845
third-party/nvfbc/helper_math.h
vendored
845
third-party/nvfbc/helper_math.h
vendored
File diff suppressed because it is too large
Load Diff
@@ -31,12 +31,14 @@ int device_state_filter = DEVICE_STATE_ACTIVE;
|
|||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
template <class T>
|
template <class T>
|
||||||
void Release(T *p) {
|
void
|
||||||
|
Release(T *p) {
|
||||||
p->Release();
|
p->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void co_task_free(T *p) {
|
void
|
||||||
|
co_task_free(T *p) {
|
||||||
CoTaskMemFree((LPVOID) p);
|
CoTaskMemFree((LPVOID) p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,8 @@ public:
|
|||||||
PROPVARIANT prop;
|
PROPVARIANT prop;
|
||||||
};
|
};
|
||||||
|
|
||||||
const wchar_t *no_null(const wchar_t *str) {
|
const wchar_t *
|
||||||
|
no_null(const wchar_t *str) {
|
||||||
return str ? str : L"Unknown";
|
return str ? str : L"Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +103,8 @@ struct format_t {
|
|||||||
SPEAKER_SIDE_RIGHT }
|
SPEAKER_SIDE_RIGHT }
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
void
|
||||||
|
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
||||||
wave_format->nChannels = format.channels;
|
wave_format->nChannels = format.channels;
|
||||||
wave_format->nBlockAlign = wave_format->nChannels * wave_format->wBitsPerSample / 8;
|
wave_format->nBlockAlign = wave_format->nChannels * wave_format->wBitsPerSample / 8;
|
||||||
wave_format->nAvgBytesPerSec = wave_format->nSamplesPerSec * wave_format->nBlockAlign;
|
wave_format->nAvgBytesPerSec = wave_format->nSamplesPerSec * wave_format->nBlockAlign;
|
||||||
@@ -110,7 +114,8 @@ void set_wave_format(audio::wave_format_t &wave_format, const format_t &format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
audio_client_t
|
||||||
|
make_audio_client(device_t &device, const format_t &format) {
|
||||||
audio_client_t audio_client;
|
audio_client_t audio_client;
|
||||||
auto status = device->Activate(
|
auto status = device->Activate(
|
||||||
IID_IAudioClient,
|
IID_IAudioClient,
|
||||||
@@ -171,7 +176,8 @@ audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
|||||||
return audio_client;
|
return audio_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_device(device_t &device) {
|
void
|
||||||
|
print_device(device_t &device) {
|
||||||
audio::wstring_t wstring;
|
audio::wstring_t wstring;
|
||||||
DWORD device_state;
|
DWORD device_state;
|
||||||
|
|
||||||
@@ -231,14 +237,16 @@ void print_device(device_t &device) {
|
|||||||
}
|
}
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
|
|
||||||
void print_help() {
|
void
|
||||||
|
print_help() {
|
||||||
std::cout
|
std::cout
|
||||||
<< "==== Help ===="sv << std::endl
|
<< "==== Help ===="sv << std::endl
|
||||||
<< "Usage:"sv << std::endl
|
<< "Usage:"sv << std::endl
|
||||||
<< " audio-info [Active|Disabled|Unplugged|Not-Present]" << std::endl;
|
<< " audio-info [Active|Disabled|Unplugged|Not-Present]" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY);
|
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY);
|
||||||
|
|
||||||
auto fg = util::fail_guard([]() {
|
auto fg = util::fail_guard([]() {
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
namespace dxgi {
|
namespace dxgi {
|
||||||
template <class T>
|
template <class T>
|
||||||
void Release(T *dxgi) {
|
void
|
||||||
|
Release(T *dxgi) {
|
||||||
dxgi->Release();
|
dxgi->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +25,8 @@ using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDup
|
|||||||
|
|
||||||
} // namespace dxgi
|
} // namespace dxgi
|
||||||
|
|
||||||
LSTATUS set_gpu_preference(int preference) {
|
LSTATUS
|
||||||
|
set_gpu_preference(int preference) {
|
||||||
// The GPU preferences key uses app path as the value name.
|
// The GPU preferences key uses app path as the value name.
|
||||||
WCHAR executable_path[MAX_PATH];
|
WCHAR executable_path[MAX_PATH];
|
||||||
GetModuleFileNameW(NULL, executable_path, ARRAYSIZE(executable_path));
|
GetModuleFileNameW(NULL, executable_path, ARRAYSIZE(executable_path));
|
||||||
@@ -46,7 +48,8 @@ LSTATUS set_gpu_preference(int preference) {
|
|||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output) {
|
HRESULT
|
||||||
|
test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output) {
|
||||||
D3D_FEATURE_LEVEL featureLevels[] {
|
D3D_FEATURE_LEVEL featureLevels[] {
|
||||||
D3D_FEATURE_LEVEL_11_1,
|
D3D_FEATURE_LEVEL_11_1,
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
D3D_FEATURE_LEVEL_11_0,
|
||||||
@@ -85,7 +88,8 @@ HRESULT test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output)
|
|||||||
return output1->DuplicateOutput((IUnknown *) device.get(), &dup);
|
return output1->DuplicateOutput((IUnknown *) device.get(), &dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
|
|
||||||
// Display name may be omitted
|
// Display name may be omitted
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
namespace dxgi {
|
namespace dxgi {
|
||||||
template <class T>
|
template <class T>
|
||||||
void Release(T *dxgi) {
|
void
|
||||||
|
Release(T *dxgi) {
|
||||||
dxgi->Release();
|
dxgi->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +23,8 @@ using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
|||||||
|
|
||||||
} // namespace dxgi
|
} // namespace dxgi
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
|
|
||||||
dxgi::factory1_t::pointer factory_p {};
|
dxgi::factory1_t::pointer factory_p {};
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
* To run a command, such as 'ipconfig /flushdns', with administrative privileges, execute:
|
* To run a command, such as 'ipconfig /flushdns', with administrative privileges, execute:
|
||||||
* elevator.exe cmd /C "ipconfig /flushdns"
|
* elevator.exe cmd /C "ipconfig /flushdns"
|
||||||
*/
|
*/
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
// Check if the user provided at least one argument (the command to run)
|
// Check if the user provided at least one argument (the command to run)
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
std::cout << "Usage: " << argv[0] << " <command> [arguments]" << std::endl;
|
std::cout << "Usage: " << argv[0] << " <command> [arguments]" << std::endl;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user