clang: adjust formatting rules (#1015)
This commit is contained in:
parent
79cf382cd9
commit
21eb4eb6dd
103 changed files with 26883 additions and 25173 deletions
|
|
@ -7,7 +7,7 @@
|
|||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
|
|
@ -18,8 +18,9 @@ AllowShortFunctionsOnASingleLine: All
|
|||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AlignTrailingComments: false
|
||||
AlwaysBreakAfterReturnType: All
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
|
|
@ -37,32 +38,32 @@ BraceWrapping:
|
|||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 2
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: 2
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: Never
|
||||
SpacesInCStyleCastParentheses: 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;
|
||||
};
|
||||
|
||||
static int start_audio_control(audio_ctx_t &ctx);
|
||||
static void stop_audio_control(audio_ctx_t &);
|
||||
static int
|
||||
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;
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
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 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 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;
|
||||
switch (channels) {
|
||||
case 2:
|
||||
|
|
@ -239,7 +245,8 @@ int map_stream(int channels, bool quality) {
|
|||
return STEREO;
|
||||
}
|
||||
|
||||
int start_audio_control(audio_ctx_t &ctx) {
|
||||
int
|
||||
start_audio_control(audio_ctx_t &ctx) {
|
||||
auto fg = util::fail_guard([]() {
|
||||
BOOST_LOG(warning) << "There will be no audio"sv;
|
||||
});
|
||||
|
|
@ -266,7 +273,8 @@ int start_audio_control(audio_ctx_t &ctx) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void stop_audio_control(audio_ctx_t &ctx) {
|
||||
void
|
||||
stop_audio_control(audio_ctx_t &ctx) {
|
||||
// restore audio-sink if applicable
|
||||
if (!ctx.restore_sink) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ struct config_t {
|
|||
|
||||
using buffer_t = util::buffer_t<std::uint8_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
|
||||
|
||||
#endif
|
||||
|
|
|
|||
32
src/cbs.cpp
32
src/cbs.cpp
|
|
@ -12,7 +12,8 @@ extern "C" {
|
|||
|
||||
using namespace std::literals;
|
||||
namespace cbs {
|
||||
void close(CodedBitstreamContext *c) {
|
||||
void
|
||||
close(CodedBitstreamContext *c) {
|
||||
ff_cbs_close(&c);
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +32,8 @@ public:
|
|||
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);
|
||||
|
||||
o.data = nullptr;
|
||||
|
|
@ -40,7 +42,6 @@ public:
|
|||
return *this;
|
||||
};
|
||||
|
||||
|
||||
~frag_t() {
|
||||
if (data || units) {
|
||||
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;
|
||||
auto err = ff_cbs_insert_unit_content(&frag, -1, nal, uh, nullptr);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
ff_cbs_init(&cbs_ctx, codec_id, nullptr);
|
||||
|
||||
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 {};
|
||||
|
||||
/* 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_height = (FFALIGN(ctx->height, 16) / 16) * 16;
|
||||
|
||||
|
||||
sps.nal_unit_header.nal_ref_idc = 3;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (ff_cbs_init(&ctx, AV_CODEC_ID_H265, nullptr)) {
|
||||
return {};
|
||||
|
|
@ -184,7 +188,6 @@ hevc_t make_sps_hevc(const AVCodecContext *avctx, const AVPacket *packet) {
|
|||
return {};
|
||||
}
|
||||
|
||||
|
||||
auto vps_p = ((CodedBitstreamH265Context *) ctx->priv_data)->active_vps;
|
||||
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.matrix_coefficients = avctx->colorspace;
|
||||
|
||||
|
||||
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_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;
|
||||
ff_cbs_init(&write_ctx, AV_CODEC_ID_H265, nullptr);
|
||||
|
||||
|
||||
return hevc_t {
|
||||
nal_t {
|
||||
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;
|
||||
if (ff_cbs_init(&ctx, AV_CODEC_ID_H264, nullptr)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
make_sps_h264(ctx),
|
||||
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;
|
||||
if (ff_cbs_init(&ctx, (AVCodecID) codec_id, nullptr)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -22,13 +22,16 @@ struct h264_t {
|
|||
nal_t sps;
|
||||
};
|
||||
|
||||
hevc_t make_sps_hevc(const AVCodecContext *ctx, const AVPacket *packet);
|
||||
h264_t make_sps_h264(const AVCodecContext *ctx, const AVPacket *packet);
|
||||
hevc_t
|
||||
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
|
||||
*/
|
||||
bool validate_sps(const AVPacket *packet, int codec_id);
|
||||
bool
|
||||
validate_sps(const AVPacket *packet, int codec_id);
|
||||
} // namespace cbs
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
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) \
|
||||
if (preset == #x##sv) return x
|
||||
_CONVERT_(p1);
|
||||
|
|
@ -85,7 +86,8 @@ std::optional<preset_e> preset_from_view(const std::string_view &preset) {
|
|||
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) \
|
||||
if (tune == #x##sv) return x
|
||||
_CONVERT_(hq);
|
||||
|
|
@ -96,7 +98,8 @@ std::optional<tune_e> tune_from_view(const std::string_view &tune) {
|
|||
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) \
|
||||
if (rc == #x##sv) return x
|
||||
_CONVERT_(constqp);
|
||||
|
|
@ -106,7 +109,8 @@ std::optional<rc_e> rc_from_view(const std::string_view &rc) {
|
|||
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 == "cabac"sv || coder == "ac"sv) return cabac;
|
||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||
|
|
@ -194,7 +198,8 @@ enum coder_e : int {
|
|||
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) \
|
||||
if (quality_type == #x##sv) return codec == 0 ? (int) quality_hevc_e::x : (int) quality_h264_e::x
|
||||
_CONVERT_(quality);
|
||||
|
|
@ -204,7 +209,8 @@ std::optional<int> quality_from_view(const std::string_view &quality_type, int c
|
|||
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) \
|
||||
if (rc == #x##sv) return codec == 0 ? (int) rc_hevc_e::x : (int) rc_h264_e::x
|
||||
_CONVERT_(cqp);
|
||||
|
|
@ -215,7 +221,8 @@ std::optional<int> rc_from_view(const std::string_view &rc, int codec) {
|
|||
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) \
|
||||
if (rc == #x##sv) return codec == 0 ? (int) usage_hevc_e::x : (int) usage_h264_e::x
|
||||
_CONVERT_(transcoding);
|
||||
|
|
@ -226,7 +233,8 @@ std::optional<int> usage_from_view(const std::string_view &rc, int codec) {
|
|||
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 == "cabac"sv || coder == "ac"sv) return cabac;
|
||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||
|
|
@ -252,7 +260,8 @@ enum cavlc_e : int {
|
|||
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) \
|
||||
if (preset == #x##sv) return x
|
||||
_CONVERT_(veryslow);
|
||||
|
|
@ -266,7 +275,8 @@ std::optional<int> preset_from_view(const std::string_view &preset) {
|
|||
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 == "cabac"sv || coder == "ac"sv) return disabled;
|
||||
if (coder == "cavlc"sv || coder == "vlc"sv) return enabled;
|
||||
|
|
@ -283,7 +293,8 @@ enum coder_e : int {
|
|||
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 == "cabac"sv || coder == "ac"sv) return cabac;
|
||||
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||
|
|
@ -291,19 +302,22 @@ int coder_from_view(const std::string_view &coder) {
|
|||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
return 1;
|
||||
|
|
@ -431,19 +445,23 @@ sunshine_t sunshine {
|
|||
{}, // prep commands
|
||||
};
|
||||
|
||||
bool endline(char ch) {
|
||||
bool
|
||||
endline(char ch) {
|
||||
return ch == '\r' || ch == '\n';
|
||||
}
|
||||
|
||||
bool space_tab(char ch) {
|
||||
bool
|
||||
space_tab(char ch) {
|
||||
return ch == ' ' || ch == '\t';
|
||||
}
|
||||
|
||||
bool whitespace(char ch) {
|
||||
bool
|
||||
whitespace(char 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;
|
||||
|
||||
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>
|
||||
It skip_list(It skipper, It end) {
|
||||
It
|
||||
skip_list(It skipper, It end) {
|
||||
int stack = 1;
|
||||
while (skipper != end && stack) {
|
||||
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::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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (it == std::end(vars)) {
|
||||
return;
|
||||
|
|
@ -547,7 +568,8 @@ void string_f(std::unordered_map<std::string, std::string> &vars, const std::str
|
|||
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;
|
||||
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
|
||||
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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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>
|
||||
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;
|
||||
string_f(vars, name, tmp);
|
||||
if (!tmp.empty()) {
|
||||
|
|
@ -651,7 +678,8 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
|||
}
|
||||
|
||||
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;
|
||||
string_f(vars, name, tmp);
|
||||
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_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); });
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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_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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
while (*line != '\0') {
|
||||
switch (*line) {
|
||||
|
|
@ -861,7 +899,8 @@ int apply_flags(const char *line) {
|
|||
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())) {
|
||||
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;
|
||||
|
||||
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 {
|
||||
prep_cmd_t(std::string &&do_cmd, std::string &&undo_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)) {}
|
||||
prep_cmd_t(std::string &&do_cmd, std::string &&undo_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 undo_cmd;
|
||||
};
|
||||
|
|
@ -155,7 +157,9 @@ extern nvhttp_t nvhttp;
|
|||
extern input_t input;
|
||||
extern sunshine_t sunshine;
|
||||
|
||||
int parse(int argc, char *argv[]);
|
||||
std::unordered_map<std::string, std::string> parse_config(const std::string_view &file_content);
|
||||
int
|
||||
parse(int argc, char *argv[]);
|
||||
std::unordered_map<std::string, std::string>
|
||||
parse_config(const std::string_view &file_content);
|
||||
} // namespace config
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ enum class op_e {
|
|||
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) << "DESTINATION :: "sv << request->path;
|
||||
|
||||
|
|
@ -69,7 +70,8 @@ void print_req(const req_https_t &request) {
|
|||
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();
|
||||
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
||||
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);
|
||||
}
|
||||
|
||||
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 ip_type = net::from_address(address);
|
||||
|
||||
|
|
@ -132,7 +136,8 @@ bool authenticate(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
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"
|
||||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -156,7 +162,8 @@ void getIndexPage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -166,7 +173,8 @@ void getPinPage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -179,7 +187,8 @@ void getAppsPage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -189,7 +198,8 @@ void getClientsPage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -199,7 +209,8 @@ void getConfigPage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -209,7 +220,8 @@ void getPasswordPage(resp_https_t response, req_https_t request) {
|
|||
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);
|
||||
if (!config::sunshine.username.empty()) {
|
||||
send_redirect(response, request, "/");
|
||||
|
|
@ -220,7 +232,8 @@ void getWelcomePage(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -230,7 +243,8 @@ void getTroubleshootingPage(resp_https_t response, req_https_t request) {
|
|||
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 - use mime_types map
|
||||
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);
|
||||
}
|
||||
|
||||
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 - use mime_types map
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
fs::path webDirPath(WEB_DIR);
|
||||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -299,7 +317,8 @@ void getApps(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -380,7 +400,8 @@ void saveApp(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -428,7 +449,8 @@ void deleteApp(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
std::stringstream ss;
|
||||
|
|
@ -489,7 +511,8 @@ void uploadCover(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -580,7 +605,8 @@ void restart(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -683,7 +711,8 @@ void unpairAll(resp_https_t response, req_https_t request) {
|
|||
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;
|
||||
|
||||
print_req(request);
|
||||
|
|
@ -700,7 +729,8 @@ void closeApp(resp_https_t response, req_https_t request) {
|
|||
outputTree.put("status", true);
|
||||
}
|
||||
|
||||
void start() {
|
||||
void
|
||||
start() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
|
||||
auto port_https = map_port(PORT_HTTPS);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
#define WEB_DIR SUNSHINE_ASSETS_DIR "/web/"
|
||||
|
||||
|
||||
namespace confighttp {
|
||||
constexpr auto PORT_HTTPS = 1;
|
||||
void start();
|
||||
void
|
||||
start();
|
||||
} // namespace confighttp
|
||||
|
||||
// mime types map
|
||||
|
|
|
|||
|
|
@ -6,15 +6,18 @@
|
|||
namespace crypto {
|
||||
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() } {}
|
||||
void cert_chain_t::add(x509_t &&cert) {
|
||||
cert_chain_t::cert_chain_t():
|
||||
_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_add_cert(x509_store.get(), cert.get());
|
||||
_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);
|
||||
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
for (auto &[_, x509_store] : _certs) {
|
||||
auto fg = util::fail_guard([this]() {
|
||||
|
|
@ -72,7 +76,8 @@ const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
|||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -162,7 +170,8 @@ int gcm_t::decrypt(const std::string_view &tagged_cipher, std::vector<std::uint8
|
|||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -196,7 +205,8 @@ int gcm_t::encrypt(const std::string_view &plaintext, std::uint8_t *tagged_ciphe
|
|||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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]() {
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -282,18 +294,19 @@ int cbc_t::encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_
|
|||
return size + len;
|
||||
}
|
||||
|
||||
ecb_t::ecb_t(const aes_t &key, bool padding)
|
||||
: cipher_t { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new(), key, padding } {}
|
||||
ecb_t::ecb_t(const aes_t &key, bool padding):
|
||||
cipher_t { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new(), key, padding } {}
|
||||
|
||||
cbc_t::cbc_t(const aes_t &key, bool padding)
|
||||
: cipher_t { nullptr, nullptr, key, padding } {}
|
||||
cbc_t::cbc_t(const aes_t &key, bool padding):
|
||||
cipher_t { nullptr, nullptr, key, padding } {}
|
||||
|
||||
gcm_t::gcm_t(const crypto::aes_t &key, bool padding)
|
||||
: cipher_t { nullptr, nullptr, key, padding } {}
|
||||
gcm_t::gcm_t(const crypto::aes_t &key, bool padding):
|
||||
cipher_t { nullptr, nullptr, key, padding } {}
|
||||
|
||||
} // 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sha256_t hash(const std::string_view &plaintext) {
|
||||
sha256_t
|
||||
hash(const std::string_view &plaintext) {
|
||||
sha256_t hsh;
|
||||
EVP_Digest(plaintext.data(), plaintext.size(), hsh.data(), nullptr, EVP_sha256(), nullptr);
|
||||
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_write(io.get(), x.data(), x.size());
|
||||
|
|
@ -326,7 +341,8 @@ x509_t x509(const std::string_view &x) {
|
|||
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_write(io.get(), k.data(), k.size());
|
||||
|
|
@ -337,7 +353,8 @@ pkey_t pkey(const std::string_view &k) {
|
|||
return p;
|
||||
}
|
||||
|
||||
std::string pem(x509_t &x509) {
|
||||
std::string
|
||||
pem(x509_t &x509) {
|
||||
bio_t bio { BIO_new(BIO_s_mem()) };
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
std::string pem(pkey_t &pkey) {
|
||||
std::string
|
||||
pem(pkey_t &pkey) {
|
||||
bio_t bio { BIO_new(BIO_s_mem()) };
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
std::string_view signature(const x509_t &x) {
|
||||
std::string_view
|
||||
signature(const x509_t &x) {
|
||||
// X509_ALGOR *_ = 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 };
|
||||
}
|
||||
|
||||
std::string rand(std::size_t bytes) {
|
||||
std::string
|
||||
rand(std::size_t bytes) {
|
||||
std::string r;
|
||||
r.resize(bytes);
|
||||
|
||||
|
|
@ -375,7 +395,8 @@ std::string rand(std::size_t bytes) {
|
|||
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() };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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() };
|
||||
pkey_ctx_t ctx { EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) };
|
||||
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) };
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void md_ctx_destroy(EVP_MD_CTX *ctx) {
|
||||
void
|
||||
md_ctx_destroy(EVP_MD_CTX *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);
|
||||
|
||||
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;
|
||||
|
||||
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>;
|
||||
|
||||
|
|
@ -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 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);
|
||||
pkey_t pkey(const std::string_view &k);
|
||||
std::string pem(x509_t &x509);
|
||||
std::string pem(pkey_t &pkey);
|
||||
x509_t
|
||||
x509(const std::string_view &x);
|
||||
pkey_t
|
||||
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);
|
||||
bool verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature);
|
||||
std::vector<uint8_t>
|
||||
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 rand_alphabet(std::size_t bytes,
|
||||
std::string
|
||||
rand(std::size_t bytes);
|
||||
std::string
|
||||
rand_alphabet(std::size_t bytes,
|
||||
const std::string_view &alphabet = std::string_view { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!%&()=-" });
|
||||
|
||||
class cert_chain_t {
|
||||
public:
|
||||
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:
|
||||
std::vector<std::pair<x509_t, x509_store_t>> _certs;
|
||||
|
|
@ -68,7 +83,8 @@ private:
|
|||
|
||||
namespace cipher {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -86,19 +102,23 @@ class ecb_t : public cipher_t {
|
|||
public:
|
||||
ecb_t() = 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);
|
||||
|
||||
int 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);
|
||||
int
|
||||
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 {
|
||||
public:
|
||||
gcm_t() = 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);
|
||||
|
||||
|
|
@ -108,16 +128,19 @@ public:
|
|||
* return -1 on error
|
||||
* 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 {
|
||||
public:
|
||||
cbc_t() = 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);
|
||||
|
||||
|
|
@ -127,7 +150,8 @@ public:
|
|||
* return -1 on error
|
||||
* 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 crypto
|
||||
|
|
|
|||
|
|
@ -31,14 +31,17 @@ using namespace std::literals;
|
|||
namespace fs = std::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
int reload_user_creds(const std::string &file);
|
||||
bool user_creds_exist(const std::string &file);
|
||||
int
|
||||
reload_user_creds(const std::string &file);
|
||||
bool
|
||||
user_creds_exist(const std::string &file);
|
||||
|
||||
std::string unique_id;
|
||||
net::net_e origin_pin_allowed;
|
||||
net::net_e origin_web_ui_allowed;
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
bool clean_slate = config::sunshine.flags[config::flag::FRESH_STATE];
|
||||
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);
|
||||
|
|
@ -64,7 +67,8 @@ int init() {
|
|||
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;
|
||||
|
||||
if (fs::exists(file)) {
|
||||
|
|
@ -93,7 +97,8 @@ int save_user_creds(const std::string &file, const std::string &username, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool user_creds_exist(const std::string &file) {
|
||||
bool
|
||||
user_creds_exist(const std::string &file) {
|
||||
if (!fs::exists(file)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -112,7 +117,8 @@ bool user_creds_exist(const std::string &file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int reload_user_creds(const std::string &file) {
|
||||
int
|
||||
reload_user_creds(const std::string &file) {
|
||||
pt::ptree inputTree;
|
||||
try {
|
||||
pt::read_json(file, inputTree);
|
||||
|
|
@ -127,7 +133,8 @@ int reload_user_creds(const std::string &file) {
|
|||
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 cert_path = cert;
|
||||
|
||||
|
|
@ -182,7 +189,8 @@ int create_creds(const std::string &pkey, const std::string &cert) {
|
|||
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();
|
||||
if (!curl) {
|
||||
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;
|
||||
}
|
||||
|
||||
std::string url_escape(const std::string &url) {
|
||||
std::string
|
||||
url_escape(const std::string &url) {
|
||||
CURL *curl = curl_easy_init();
|
||||
char *string = curl_easy_escape(curl, url.c_str(), url.length());
|
||||
std::string result(string);
|
||||
|
|
@ -218,7 +227,8 @@ std::string url_escape(const std::string &url) {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string url_get_host(const std::string &url) {
|
||||
std::string
|
||||
url_get_host(const std::string &url) {
|
||||
CURLU *curlu = curl_url();
|
||||
curl_url_set(curlu, CURLUPART_URL, url.c_str(), url.length());
|
||||
char *host;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,25 @@
|
|||
|
||||
namespace http {
|
||||
|
||||
int init();
|
||||
int create_creds(const std::string &pkey, const std::string &cert);
|
||||
int save_user_creds(
|
||||
int
|
||||
init();
|
||||
int
|
||||
create_creds(const std::string &pkey, const std::string &cert);
|
||||
int
|
||||
save_user_creds(
|
||||
const std::string &file,
|
||||
const std::string &username,
|
||||
const std::string &password,
|
||||
bool run_our_mouth = false);
|
||||
|
||||
int reload_user_creds(const std::string &file);
|
||||
bool 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);
|
||||
int
|
||||
reload_user_creds(const std::string &file);
|
||||
bool
|
||||
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 net::net_e origin_pin_allowed;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ enum class button_state_e {
|
|||
};
|
||||
|
||||
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) {
|
||||
if (!gamepad_mask[x]) {
|
||||
gamepad_mask[x] = true;
|
||||
|
|
@ -53,7 +54,8 @@ int alloc_id(std::bitset<N> &gamepad_mask) {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -64,14 +66,16 @@ static std::array<std::uint8_t, 5> mouse_press {};
|
|||
static platf::input_t platf_input;
|
||||
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::free_gamepad(platf_input, id);
|
||||
|
||||
free_id(gamepadMask, id);
|
||||
}
|
||||
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() {
|
||||
if (id >= 0) {
|
||||
task_pool.push([id = this->id]() {
|
||||
|
|
@ -105,8 +109,8 @@ struct input_t {
|
|||
|
||||
input_t(
|
||||
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event,
|
||||
platf::rumble_queue_t rumble_queue)
|
||||
: shortcutFlags {},
|
||||
platf::rumble_queue_t rumble_queue):
|
||||
shortcutFlags {},
|
||||
active_gamepad_state {},
|
||||
gamepads(MAX_GAMEPADS),
|
||||
touch_port_event { std::move(touch_port_event) },
|
||||
|
|
@ -135,7 +139,8 @@ struct input_t {
|
|||
* On nothing
|
||||
* return 0
|
||||
*/
|
||||
inline int apply_shortcut(short keyCode) {
|
||||
inline int
|
||||
apply_shortcut(short keyCode) {
|
||||
constexpr auto VK_F1 = 0x70;
|
||||
constexpr auto VK_F13 = 0x7C;
|
||||
|
||||
|
|
@ -155,7 +160,8 @@ inline int apply_shortcut(short keyCode) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||
void
|
||||
print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin relative mouse move packet--"sv << 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;
|
||||
}
|
||||
|
||||
void print(PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
||||
void
|
||||
print(PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin absolute mouse move packet--"sv << 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;
|
||||
}
|
||||
|
||||
void print(PNV_MOUSE_BUTTON_PACKET packet) {
|
||||
void
|
||||
print(PNV_MOUSE_BUTTON_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin mouse button packet--"sv << 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;
|
||||
}
|
||||
|
||||
void print(PNV_SCROLL_PACKET packet) {
|
||||
void
|
||||
print(PNV_SCROLL_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin mouse scroll packet--"sv << std::endl
|
||||
<< "scrollAmt1 ["sv << util::endian::big(packet->scrollAmt1) << ']' << std::endl
|
||||
<< "--end mouse scroll packet--"sv;
|
||||
}
|
||||
|
||||
void print(PSS_HSCROLL_PACKET packet) {
|
||||
void
|
||||
print(PSS_HSCROLL_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin mouse hscroll packet--"sv << std::endl
|
||||
<< "scrollAmount ["sv << util::endian::big(packet->scrollAmount) << ']' << std::endl
|
||||
<< "--end mouse hscroll packet--"sv;
|
||||
}
|
||||
|
||||
void print(PNV_KEYBOARD_PACKET packet) {
|
||||
void
|
||||
print(PNV_KEYBOARD_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin keyboard packet--"sv << 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;
|
||||
}
|
||||
|
||||
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));
|
||||
BOOST_LOG(debug)
|
||||
<< "--begin unicode packet--"sv << std::endl
|
||||
|
|
@ -213,7 +225,8 @@ void print(PNV_UNICODE_PACKET packet) {
|
|||
<< "--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
|
||||
BOOST_LOG(verbose)
|
||||
<< "--begin controller packet--"sv << std::endl
|
||||
|
|
@ -229,7 +242,8 @@ void print(PNV_MULTI_CONTROLLER_PACKET packet) {
|
|||
<< "--end controller packet--"sv;
|
||||
}
|
||||
|
||||
void print(void *payload) {
|
||||
void
|
||||
print(void *payload) {
|
||||
auto header = (PNV_INPUT_HEADER) payload;
|
||||
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
short map_keycode(short keycode) {
|
||||
short
|
||||
map_keycode(short keycode) {
|
||||
auto it = config::input.keybindings.find(keycode);
|
||||
if (it != std::end(config::input.keybindings)) {
|
||||
return it->second;
|
||||
|
|
@ -394,7 +412,8 @@ short map_keycode(short keycode) {
|
|||
/**
|
||||
* 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) {
|
||||
case VKEY_SHIFT:
|
||||
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_press[key_code]) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
void passthrough(PNV_SCROLL_PACKET packet) {
|
||||
void
|
||||
passthrough(PNV_SCROLL_PACKET packet) {
|
||||
if (!config::input.mouse) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -490,7 +512,8 @@ void passthrough(PNV_SCROLL_PACKET packet) {
|
|||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -498,7 +521,8 @@ void passthrough(PSS_HSCROLL_PACKET packet) {
|
|||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -507,7 +531,8 @@ void passthrough(PNV_UNICODE_PACKET packet) {
|
|||
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;
|
||||
if (!xorGamepadMask) {
|
||||
return 0;
|
||||
|
|
@ -548,7 +573,8 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
|||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -650,7 +676,8 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET pa
|
|||
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();
|
||||
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));
|
||||
}
|
||||
|
||||
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(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();
|
||||
|
||||
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>(
|
||||
mail->event<input::touch_port_t>(mail::touch_port),
|
||||
mail->queue<platf::rumble_t>(mail::rumble));
|
||||
|
|
|
|||
16
src/input.h
16
src/input.h
|
|
@ -11,14 +11,18 @@
|
|||
namespace input {
|
||||
struct input_t;
|
||||
|
||||
void print(void *input);
|
||||
void reset(std::shared_ptr<input_t> &input);
|
||||
void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data);
|
||||
void
|
||||
print(void *input);
|
||||
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 {
|
||||
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;
|
||||
|
||||
struct NoDelete {
|
||||
void operator()(void *) {}
|
||||
void
|
||||
operator()(void *) {}
|
||||
};
|
||||
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
||||
|
|
@ -69,7 +70,8 @@ BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
|||
* print_help("sunshine");
|
||||
* ```
|
||||
*/
|
||||
void print_help(const char *name) {
|
||||
void
|
||||
print_help(const char *name) {
|
||||
std::cout
|
||||
<< "Usage: "sv << name << " [options] [/path/to/configuration_file] [--cmd]"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 {
|
||||
int entry(const char *name, int argc, char *argv[]) {
|
||||
int
|
||||
entry(const char *name, int argc, char *argv[]) {
|
||||
print_help(name);
|
||||
return 0;
|
||||
}
|
||||
} // namespace help
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
} // namespace version
|
||||
|
||||
|
||||
/**
|
||||
* @brief Flush the log.
|
||||
*
|
||||
|
|
@ -112,24 +115,28 @@ int entry(const char *name, int argc, char *argv[]) {
|
|||
* log_flush();
|
||||
* ```
|
||||
*/
|
||||
void log_flush() {
|
||||
void
|
||||
log_flush() {
|
||||
sink->flush();
|
||||
}
|
||||
|
||||
std::map<int, std::function<void()>> signal_handlers;
|
||||
void on_signal_forwarder(int sig) {
|
||||
void
|
||||
on_signal_forwarder(int sig) {
|
||||
signal_handlers.at(sig)();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
std::signal(sig, on_signal_forwarder);
|
||||
}
|
||||
|
||||
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) {
|
||||
print_help(name);
|
||||
return 0;
|
||||
|
|
@ -148,7 +155,8 @@ std::map<std::string_view, std::function<int(const char *name, int argc, char **
|
|||
};
|
||||
|
||||
#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) {
|
||||
case WM_ENDSESSION: {
|
||||
// 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});
|
||||
* ```
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
task_pool_util::TaskPool::task_id_t force_shutdown = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -395,7 +404,8 @@ int main(int argc, char *argv[]) {
|
|||
* 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)) {
|
||||
BOOST_LOG(debug) << "Missing file: " << path;
|
||||
return {};
|
||||
|
|
@ -425,7 +435,8 @@ std::string read_file(const char *path) {
|
|||
* 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);
|
||||
|
||||
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 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 not already in use by another application
|
||||
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;
|
||||
|
||||
// functions
|
||||
int main(int argc, char *argv[]);
|
||||
void log_flush();
|
||||
void open_url(const std::string &url);
|
||||
void tray_open_ui_cb(struct tray_menu *item);
|
||||
void tray_donate_github_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);
|
||||
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);
|
||||
int
|
||||
main(int argc, char *argv[]);
|
||||
void
|
||||
log_flush();
|
||||
void
|
||||
open_url(const std::string &url);
|
||||
void
|
||||
tray_open_ui_cb(struct tray_menu *item);
|
||||
void
|
||||
tray_donate_github_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);
|
||||
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
|
||||
namespace mail {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ private:
|
|||
move_type _to_move;
|
||||
|
||||
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;
|
||||
|
||||
|
|
@ -24,9 +25,11 @@ public:
|
|||
*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);
|
||||
|
||||
return *this;
|
||||
|
|
@ -38,13 +41,15 @@ public:
|
|||
};
|
||||
|
||||
template <class T>
|
||||
MoveByCopy<T> cmove(T &movable) {
|
||||
MoveByCopy<T>
|
||||
cmove(T &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
|
||||
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)));
|
||||
}
|
||||
} // namespace move_by_copy_util
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
using namespace std::literals;
|
||||
namespace net {
|
||||
// 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 {
|
||||
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)
|
||||
};
|
||||
|
||||
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 end = std::end(ip_str);
|
||||
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"
|
||||
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 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) };
|
||||
}
|
||||
|
||||
net_e from_enum_string(const std::string_view &view) {
|
||||
net_e
|
||||
from_enum_string(const std::string_view &view) {
|
||||
if (view == "wan") {
|
||||
return WAN;
|
||||
}
|
||||
|
|
@ -60,7 +64,8 @@ net_e from_enum_string(const std::string_view &view) {
|
|||
|
||||
return PC;
|
||||
}
|
||||
net_e from_address(const std::string_view &view) {
|
||||
net_e
|
||||
from_address(const std::string_view &view) {
|
||||
auto addr = ip(view);
|
||||
|
||||
for (auto [ip_low, ip_high] : pc_ips) {
|
||||
|
|
@ -78,7 +83,8 @@ net_e from_address(const std::string_view &view) {
|
|||
return WAN;
|
||||
}
|
||||
|
||||
std::string_view to_enum_string(net_e net) {
|
||||
std::string_view
|
||||
to_enum_string(net_e net) {
|
||||
switch (net) {
|
||||
case PC:
|
||||
return "pc"sv;
|
||||
|
|
@ -92,14 +98,16 @@ std::string_view to_enum_string(net_e net) {
|
|||
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_port(&addr, port);
|
||||
|
||||
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) {
|
||||
ENetPeer *peer = &peer_ref;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
#include "utility.h"
|
||||
|
||||
namespace net {
|
||||
void free_host(ENetHost *host);
|
||||
void
|
||||
free_host(ENetHost *host);
|
||||
|
||||
using host_t = util::safe_ptr<ENetHost, free_host>;
|
||||
using peer_t = ENetPeer *;
|
||||
|
|
@ -22,12 +23,16 @@ enum net_e : int {
|
|||
WAN
|
||||
};
|
||||
|
||||
net_e from_enum_string(const std::string_view &view);
|
||||
std::string_view to_enum_string(net_e net);
|
||||
net_e
|
||||
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
|
||||
|
||||
#endif // SUNSHINE_NETWORK_H
|
||||
|
|
|
|||
|
|
@ -38,14 +38,15 @@ namespace pt = boost::property_tree;
|
|||
|
||||
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
||||
public:
|
||||
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file)
|
||||
: SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, 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) {}
|
||||
|
||||
std::function<int(SSL *)> verify;
|
||||
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
|
||||
|
||||
protected:
|
||||
void after_bind() override {
|
||||
void
|
||||
after_bind() override {
|
||||
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();
|
||||
|
||||
if (verify) {
|
||||
|
|
@ -58,7 +59,8 @@ protected:
|
|||
}
|
||||
|
||||
// This is Server<HTTPS>::accept() with SSL validation support added
|
||||
void accept() override {
|
||||
void
|
||||
accept() override {
|
||||
auto connection = create_connection(*io_service, context);
|
||||
|
||||
acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const SimpleWeb::error_code &ec) {
|
||||
|
|
@ -147,7 +149,8 @@ enum class op_e {
|
|||
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);
|
||||
if (it == std::end(args)) {
|
||||
throw std::out_of_range(name);
|
||||
|
|
@ -155,7 +158,8 @@ std::string get_arg(const args_t &args, const char *name) {
|
|||
return it->second;
|
||||
}
|
||||
|
||||
void save_state() {
|
||||
void
|
||||
save_state() {
|
||||
pt::ptree root;
|
||||
|
||||
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)) {
|
||||
BOOST_LOG(info) << "File "sv << config::nvhttp.file_state << " doesn't exist"sv;
|
||||
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) {
|
||||
case op_e::ADD: {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
tree.put("root.paired", 0);
|
||||
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.<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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 pairingsecret = util::from_hex_vec(get_arg(args, "clientpairingsecret"), true);
|
||||
|
|
@ -401,7 +412,8 @@ struct tunnel<SimpleWeb::HTTP> {
|
|||
};
|
||||
|
||||
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) << "METHOD :: "sv << request->method;
|
||||
|
|
@ -421,7 +433,8 @@ void print_req(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> reque
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
pt::ptree tree;
|
||||
|
|
@ -440,7 +453,8 @@ void not_found(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> resp
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
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(std::string pin) {
|
||||
bool
|
||||
pin(std::string pin) {
|
||||
pt::ptree tree;
|
||||
if (map_id_sess.empty()) {
|
||||
return false;
|
||||
|
|
@ -551,7 +566,8 @@ bool pin(std::string pin) {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
response->close_connection_after_response = true;
|
||||
|
|
@ -576,7 +592,8 @@ void pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response,
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
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 clientID = args.find("uniqueid"s);
|
||||
|
||||
|
||||
if (clientID != std::end(args)) {
|
||||
if (auto it = map_id_client.find(clientID->second); it != std::end(map_id_client)) {
|
||||
pair_status = 1;
|
||||
|
|
@ -659,7 +675,8 @@ void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> res
|
|||
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);
|
||||
|
||||
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);
|
||||
|
||||
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("localAudioPlayMode"s) == std::end(args) ||
|
||||
args.find("appid"s) == std::end(args)) {
|
||||
|
||||
tree.put("root.resume", 0);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
pt::ptree tree;
|
||||
|
|
@ -796,7 +814,6 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||
if (
|
||||
args.find("rikey"s) == std::end(args) ||
|
||||
args.find("rikeyid"s) == std::end(args)) {
|
||||
|
||||
tree.put("root.resume", 0);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
pt::ptree tree;
|
||||
|
|
@ -839,8 +857,8 @@ void cancel(resp_https_t response, req_https_t request) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void appasset(resp_https_t response, req_https_t request) {
|
||||
void
|
||||
appasset(resp_https_t response, req_https_t request) {
|
||||
print_req<SimpleWeb::HTTPS>(request);
|
||||
|
||||
auto args = request->parse_query_string();
|
||||
|
|
@ -861,7 +879,8 @@ void appasset(resp_https_t response, req_https_t request) {
|
|||
* nvhttp::start();
|
||||
* ```
|
||||
*/
|
||||
void start() {
|
||||
void
|
||||
start() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
|
||||
auto port_http = map_port(PORT_HTTP);
|
||||
|
|
@ -905,7 +924,6 @@ void start() {
|
|||
auto fg = util::fail_guard([&]() {
|
||||
char subject_name[256];
|
||||
|
||||
|
||||
X509_NAME_oneline(X509_get_subject_name(x509), subject_name, sizeof(subject_name));
|
||||
|
||||
BOOST_LOG(debug) << subject_name << " -- "sv << (verified ? "verified"sv : "denied"sv);
|
||||
|
|
@ -1007,7 +1025,8 @@ void start() {
|
|||
* nvhttp::erase_all_clients();
|
||||
* ```
|
||||
*/
|
||||
void erase_all_clients() {
|
||||
void
|
||||
erase_all_clients() {
|
||||
map_id_client.clear();
|
||||
save_state();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,12 @@ constexpr auto PORT_HTTP = 0;
|
|||
constexpr auto PORT_HTTPS = -5;
|
||||
|
||||
// functions
|
||||
void start();
|
||||
bool pin(std::string pin);
|
||||
void erase_all_clients();
|
||||
void
|
||||
start();
|
||||
bool
|
||||
pin(std::string pin);
|
||||
void
|
||||
erase_all_clients();
|
||||
} // namespace nvhttp
|
||||
|
||||
#endif // SUNSHINE_NVHTTP_H
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ constexpr std::uint16_t Y = 0x8000;
|
|||
struct rumble_t {
|
||||
KITTY_DEFAULT_CONSTR(rumble_t)
|
||||
|
||||
rumble_t(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq)
|
||||
: id { id }, lowfreq { lowfreq }, highfreq { highfreq } {}
|
||||
rumble_t(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq):
|
||||
id { id }, lowfreq { lowfreq }, highfreq { highfreq } {}
|
||||
|
||||
std::uint16_t id;
|
||||
std::uint16_t lowfreq;
|
||||
|
|
@ -130,7 +130,8 @@ enum class pix_fmt_e {
|
|||
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;
|
||||
#define _CONVERT(x) \
|
||||
case pix_fmt_e::x: \
|
||||
|
|
@ -174,8 +175,10 @@ public:
|
|||
|
||||
img_t(img_t &&) = delete;
|
||||
img_t(const img_t &) = delete;
|
||||
img_t &operator=(img_t &&) = delete;
|
||||
img_t &operator=(const img_t &) = delete;
|
||||
img_t &
|
||||
operator=(img_t &&) = delete;
|
||||
img_t &
|
||||
operator=(const img_t &) = delete;
|
||||
|
||||
std::uint8_t *data {};
|
||||
std::int32_t width {};
|
||||
|
|
@ -204,29 +207,34 @@ struct hwdevice_t {
|
|||
void *data {};
|
||||
AVFrame *frame {};
|
||||
|
||||
virtual int convert(platf::img_t &img) {
|
||||
virtual int
|
||||
convert(platf::img_t &img) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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?";
|
||||
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
|
||||
*/
|
||||
virtual void init_hwframes(AVHWFramesContext *frames) {};
|
||||
virtual void
|
||||
init_hwframes(AVHWFramesContext *frames) {};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
|
@ -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)>;
|
||||
|
||||
display_t() noexcept : offset_x { 0 }, offset_y { 0 } {}
|
||||
display_t() noexcept:
|
||||
offset_x { 0 }, offset_y { 0 } {}
|
||||
|
||||
/**
|
||||
* snapshot_cb --> the callback
|
||||
|
|
@ -267,21 +276,27 @@ public:
|
|||
* capture_e::error on error
|
||||
* 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>();
|
||||
}
|
||||
|
||||
virtual bool is_hdr() {
|
||||
virtual bool
|
||||
is_hdr() {
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -297,34 +312,44 @@ public:
|
|||
|
||||
class mic_t {
|
||||
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;
|
||||
};
|
||||
|
||||
class audio_control_t {
|
||||
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;
|
||||
};
|
||||
|
||||
void freeInput(void *);
|
||||
void
|
||||
freeInput(void *);
|
||||
|
||||
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::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const);
|
||||
std::string
|
||||
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
|
||||
|
|
@ -335,12 +360,15 @@ std::unique_ptr<audio_control_t> audio_control();
|
|||
*
|
||||
* 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
|
||||
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 {
|
||||
low,
|
||||
|
|
@ -348,14 +376,19 @@ enum class thread_priority_e : int {
|
|||
high,
|
||||
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
|
||||
void streaming_will_start();
|
||||
void streaming_will_stop();
|
||||
void
|
||||
streaming_will_start();
|
||||
void
|
||||
streaming_will_stop();
|
||||
|
||||
bool restart_supported();
|
||||
bool restart();
|
||||
bool
|
||||
restart_supported();
|
||||
bool
|
||||
restart();
|
||||
|
||||
struct batched_send_info_t {
|
||||
const char *buffer;
|
||||
|
|
@ -366,37 +399,53 @@ struct batched_send_info_t {
|
|||
boost::asio::ip::address &target_address;
|
||||
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 {
|
||||
audio,
|
||||
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();
|
||||
void move_mouse(input_t &input, int deltaX, int deltaY);
|
||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);
|
||||
void button_mouse(input_t &input, int button, bool release);
|
||||
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);
|
||||
input_t
|
||||
input();
|
||||
void
|
||||
move_mouse(input_t &input, int deltaX, int deltaY);
|
||||
void
|
||||
abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);
|
||||
void
|
||||
button_mouse(input_t &input, int button, bool release);
|
||||
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);
|
||||
void free_gamepad(input_t &input, int nr);
|
||||
int
|
||||
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_TYPE "_nvstream._tcp"
|
||||
|
||||
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
|
||||
|
||||
#endif //SUNSHINE_COMMON_H
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ constexpr pa_channel_position_t position_mapping[] {
|
|||
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;
|
||||
|
||||
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 {
|
||||
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 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>();
|
||||
|
||||
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;
|
||||
|
||||
template <class T>
|
||||
void pa_free(T *p) {
|
||||
void
|
||||
pa_free(T *p) {
|
||||
pa_xfree(p);
|
||||
}
|
||||
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)>;
|
||||
|
||||
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;
|
||||
|
||||
// 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)>;
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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::thread worker;
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
events = std::make_unique<safe::event_t<ctx_event_e>>();
|
||||
loop.reset(pa_mainloop_new());
|
||||
ctx.reset(pa_context_new(pa_mainloop_get_api(loop.get()), "sunshine"));
|
||||
|
|
@ -245,7 +255,8 @@ public:
|
|||
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>();
|
||||
|
||||
op_t op {
|
||||
|
|
@ -261,7 +272,8 @@ public:
|
|||
return *alarm->status();
|
||||
}
|
||||
|
||||
int unload_null(std::uint32_t i) {
|
||||
int
|
||||
unload_null(std::uint32_t i) {
|
||||
if (i == PA_INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -282,7 +294,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::optional<sink_t> sink_info() override {
|
||||
std::optional<sink_t>
|
||||
sink_info() override {
|
||||
constexpr auto stereo = "sink-sunshine-stereo";
|
||||
constexpr auto surround51 = "sink-sunshine-surround51";
|
||||
constexpr auto surround71 = "sink-sunshine-surround71";
|
||||
|
|
@ -382,7 +395,8 @@ public:
|
|||
return std::make_optional(std::move(sink));
|
||||
}
|
||||
|
||||
std::string get_default_sink_name() {
|
||||
std::string
|
||||
get_default_sink_name() {
|
||||
std::string sink_name;
|
||||
auto alarm = safe::make_alarm<int>();
|
||||
|
||||
|
|
@ -404,7 +418,8 @@ public:
|
|||
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;
|
||||
auto alarm = safe::make_alarm<int>();
|
||||
|
||||
|
|
@ -435,7 +450,8 @@ public:
|
|||
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:
|
||||
// 1. Config sink
|
||||
// 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));
|
||||
}
|
||||
|
||||
int set_sink(const std::string &sink) override {
|
||||
int
|
||||
set_sink(const std::string &sink) override {
|
||||
auto alarm = safe::make_alarm<int>();
|
||||
|
||||
BOOST_LOG(info) << "Setting default sink to: ["sv << sink << "]"sv;
|
||||
|
|
@ -495,7 +512,8 @@ public:
|
|||
};
|
||||
} // 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>();
|
||||
|
||||
if (audio->init()) {
|
||||
|
|
|
|||
|
|
@ -30,11 +30,13 @@ namespace cuda {
|
|||
constexpr auto cudaDevAttrMaxThreadsPerBlock = (CUdevice_attribute) 1;
|
||||
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;
|
||||
}
|
||||
|
||||
void cff(CudaFunctions *cf) {
|
||||
void
|
||||
cff(CudaFunctions *cf) {
|
||||
cuda_free_functions(&cf);
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +44,8 @@ using cdf_t = util::safe_ptr<CudaFunctions, cff>;
|
|||
|
||||
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) {
|
||||
const char *name;
|
||||
const char *description;
|
||||
|
|
@ -57,7 +60,8 @@ inline static int check(CUresult result, const std::string_view &sv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void freeStream(CUstream stream) {
|
||||
void
|
||||
freeStream(CUstream stream) {
|
||||
CU_CHECK_IGNORE(cdf->cuStreamDestroy(stream), "Couldn't destroy cuda stream");
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +70,8 @@ public:
|
|||
tex_t tex;
|
||||
};
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
auto status = cuda_load_functions(&cdf, nullptr);
|
||||
if (status) {
|
||||
BOOST_LOG(error) << "Couldn't load cuda: "sv << status;
|
||||
|
|
@ -81,7 +86,8 @@ int init() {
|
|||
|
||||
class cuda_t: public platf::hwdevice_t {
|
||||
public:
|
||||
int init(int in_width, int in_height) {
|
||||
int
|
||||
init(int in_width, int in_height) {
|
||||
if (!cdf) {
|
||||
BOOST_LOG(warning) << "cuda not initialized"sv;
|
||||
return -1;
|
||||
|
|
@ -95,7 +101,8 @@ public:
|
|||
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->frame = frame;
|
||||
|
||||
|
|
@ -133,7 +140,8 @@ public:
|
|||
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);
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -178,11 +187,13 @@ public:
|
|||
|
||||
class cuda_ram_t: public cuda_t {
|
||||
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());
|
||||
}
|
||||
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -202,12 +213,14 @@ public:
|
|||
|
||||
class cuda_vram_t: public cuda_t {
|
||||
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());
|
||||
}
|
||||
};
|
||||
|
||||
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()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -232,12 +245,14 @@ namespace nvfbc {
|
|||
static PNVFBCCREATEINSTANCE createInstance {};
|
||||
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;
|
||||
}
|
||||
|
||||
static void *handle { nullptr };
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
if (funcs_loaded) return 0;
|
||||
|
|
@ -304,18 +319,21 @@ class handle_t {
|
|||
|
||||
public:
|
||||
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();
|
||||
}
|
||||
|
||||
handle_t &operator=(handle_t &&other) {
|
||||
handle_t &
|
||||
operator=(handle_t &&other) {
|
||||
std::swap(handle_flags, other.handle_flags);
|
||||
std::swap(handle, other.handle);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
static std::optional<handle_t> make() {
|
||||
static std::optional<handle_t>
|
||||
make() {
|
||||
NVFBC_CREATE_HANDLE_PARAMS params { NVFBC_CREATE_HANDLE_PARAMS_VER };
|
||||
|
||||
handle_t handle;
|
||||
|
|
@ -331,11 +349,13 @@ public:
|
|||
return std::move(handle);
|
||||
}
|
||||
|
||||
const char *last_error() {
|
||||
const char *
|
||||
last_error() {
|
||||
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 };
|
||||
|
||||
auto status = func.nvFBCGetStatus(handle, ¶ms);
|
||||
|
|
@ -348,7 +368,8 @@ public:
|
|||
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)) {
|
||||
BOOST_LOG(error) << "Failed to start capture session: "sv << last_error();
|
||||
return -1;
|
||||
|
|
@ -368,7 +389,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int stop() {
|
||||
int
|
||||
stop() {
|
||||
if (!handle_flags[SESSION_CAPTURE]) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -386,7 +408,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int reset() {
|
||||
int
|
||||
reset() {
|
||||
if (!handle_flags[SESSION_HANDLE]) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -415,7 +438,8 @@ public:
|
|||
|
||||
class display_t: public platf::display_t {
|
||||
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();
|
||||
if (!handle) {
|
||||
return -1;
|
||||
|
|
@ -479,7 +503,8 @@ public:
|
|||
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();
|
||||
|
||||
// Force display_t::capture to initialize handle_t::capture
|
||||
|
|
@ -522,7 +547,8 @@ public:
|
|||
}
|
||||
|
||||
// Reinitialize the capture session.
|
||||
platf::capture_e reinit(bool cursor) {
|
||||
platf::capture_e
|
||||
reinit(bool cursor) {
|
||||
if (handle.stop()) {
|
||||
return platf::capture_e::error;
|
||||
}
|
||||
|
|
@ -591,7 +617,8 @@ public:
|
|||
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) {
|
||||
auto status = reinit(cursor);
|
||||
if (status != platf::capture_e::ok) {
|
||||
|
|
@ -626,11 +653,13 @@ public:
|
|||
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);
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
img->data = nullptr;
|
||||
|
|
@ -649,7 +678,8 @@ public:
|
|||
return img;
|
||||
};
|
||||
|
||||
int dummy_img(platf::img_t *) override {
|
||||
int
|
||||
dummy_img(platf::img_t *) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -664,7 +694,8 @@ public:
|
|||
} // namespace cuda
|
||||
|
||||
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) {
|
||||
BOOST_LOG(error) << "Could not initialize nvfbc display with the given hw device type"sv;
|
||||
return nullptr;
|
||||
|
|
@ -679,7 +710,8 @@ std::shared_ptr<display_t> nvfbc_display(mem_type_e hwdevice_type, const std::st
|
|||
return display;
|
||||
}
|
||||
|
||||
std::vector<std::string> nvfbc_display_names() {
|
||||
std::vector<std::string>
|
||||
nvfbc_display_names() {
|
||||
if (cuda::init() || cuda::nvfbc::init()) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@ class img_t;
|
|||
namespace cuda {
|
||||
|
||||
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);
|
||||
int init();
|
||||
std::shared_ptr<platf::hwdevice_t>
|
||||
make_hwdevice(int width, int height, bool vram);
|
||||
int
|
||||
init();
|
||||
} // namespace cuda
|
||||
|
||||
typedef struct cudaArray *cudaArray_t;
|
||||
|
|
@ -34,18 +37,21 @@ namespace cuda {
|
|||
|
||||
class freeCudaPtr_t {
|
||||
public:
|
||||
void operator()(void *ptr);
|
||||
void
|
||||
operator()(void *ptr);
|
||||
};
|
||||
|
||||
class freeCudaStream_t {
|
||||
public:
|
||||
void operator()(cudaStream_t ptr);
|
||||
void
|
||||
operator()(cudaStream_t ptr);
|
||||
};
|
||||
|
||||
using ptr_t = std::unique_ptr<void, freeCudaPtr_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 {
|
||||
int width, height;
|
||||
|
|
@ -54,16 +60,19 @@ struct viewport_t {
|
|||
|
||||
class tex_t {
|
||||
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 &operator=(tex_t &&other);
|
||||
tex_t &
|
||||
operator=(tex_t &&other);
|
||||
|
||||
~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;
|
||||
|
||||
|
|
@ -84,15 +93,20 @@ public:
|
|||
*
|
||||
* 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
|
||||
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 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);
|
||||
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
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ using namespace std::literals;
|
|||
namespace gl {
|
||||
GladGLContext ctx;
|
||||
|
||||
void drain_errors(const std::string_view &prefix) {
|
||||
void
|
||||
drain_errors(const std::string_view &prefix) {
|
||||
GLenum err;
|
||||
while ((err = ctx.GetError()) != GL_NO_ERROR) {
|
||||
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 };
|
||||
|
||||
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 };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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.ReadBuffer(GL_COLOR_ATTACHMENT0 + id);
|
||||
gl::ctx.BindTexture(GL_TEXTURE_2D, texture);
|
||||
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;
|
||||
ctx.GetShaderiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
|
|
@ -90,7 +95,8 @@ std::string shader_t::err_str() {
|
|||
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;
|
||||
|
||||
auto data = source.data();
|
||||
|
|
@ -110,11 +116,13 @@ util::Either<shader_t, std::string> shader_t::compile(const std::string_view &so
|
|||
return shader;
|
||||
}
|
||||
|
||||
GLuint shader_t::handle() const {
|
||||
GLuint
|
||||
shader_t::handle() const {
|
||||
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._block = block;
|
||||
buffer._size = data.size();
|
||||
|
|
@ -127,20 +135,24 @@ buffer_t buffer_t::make(util::buffer_t<GLint> &&offsets, const char *block, cons
|
|||
return buffer;
|
||||
}
|
||||
|
||||
GLuint buffer_t::handle() const {
|
||||
GLuint
|
||||
buffer_t::handle() const {
|
||||
return _buffer.el;
|
||||
}
|
||||
|
||||
const char *buffer_t::block() const {
|
||||
const char *
|
||||
buffer_t::block() const {
|
||||
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.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 };
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::string program_t::err_str() {
|
||||
std::string
|
||||
program_t::err_str() {
|
||||
int length;
|
||||
ctx.GetProgramiv(handle(), GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
|
|
@ -166,7 +179,8 @@ std::string program_t::err_str() {
|
|||
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._program.el = ctx.CreateProgram();
|
||||
|
|
@ -193,14 +207,16 @@ util::Either<program_t, std::string> program_t::link(const shader_t &vert, const
|
|||
return program;
|
||||
}
|
||||
|
||||
void program_t::bind(const buffer_t &buffer) {
|
||||
void
|
||||
program_t::bind(const buffer_t &buffer) {
|
||||
ctx.UseProgram(handle());
|
||||
auto i = ctx.GetUniformBlockIndex(handle(), buffer.block());
|
||||
|
||||
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);
|
||||
if (i == GL_INVALID_INDEX) {
|
||||
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() });
|
||||
}
|
||||
|
||||
GLuint program_t::handle() const {
|
||||
GLuint
|
||||
program_t::handle() const {
|
||||
return _program.el;
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +275,8 @@ namespace gbm {
|
|||
device_destroy_fn device_destroy;
|
||||
create_device_fn create_device;
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
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_HI_EXT = 0x344A;
|
||||
|
||||
bool fail() {
|
||||
bool
|
||||
fail() {
|
||||
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_WAYLAND_KHR = 0x31D8;
|
||||
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;
|
||||
}
|
||||
|
||||
std::optional<ctx_t> make_ctx(display_t::pointer display) {
|
||||
std::optional<ctx_t>
|
||||
make_ctx(display_t::pointer display) {
|
||||
constexpr int conf_attr[] {
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE
|
||||
};
|
||||
|
|
@ -434,7 +455,8 @@ struct plane_attr_t {
|
|||
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) {
|
||||
case 0:
|
||||
return {
|
||||
|
|
@ -474,7 +496,8 @@ inline plane_attr_t get_plane(std::uint32_t plane_indice) {
|
|||
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];
|
||||
int atti = 0;
|
||||
attribs[atti++] = EGL_WIDTH;
|
||||
|
|
@ -531,7 +554,8 @@ std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface
|
|||
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] {
|
||||
{ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_R8,
|
||||
EGL_WIDTH, r8.width,
|
||||
|
|
@ -578,7 +602,8 @@ std::optional<nv12_t> import_target(display_t::pointer egl_display, std::array<f
|
|||
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;
|
||||
switch (colorspace) {
|
||||
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);
|
||||
}
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
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 = [&]() {
|
||||
std::swap(offsetX, this->offsetX);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
gl::ctx.BindTexture(GL_TEXTURE_2D, tex[0]);
|
||||
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));
|
||||
}
|
||||
|
||||
void sws_t::load_ram(platf::img_t &img) {
|
||||
void
|
||||
sws_t::load_ram(platf::img_t &img) {
|
||||
loaded_texture = tex[0];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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...
|
||||
const bool copy = offset_x || offset_y || img.sd.width != in_width || img.sd.height != in_height;
|
||||
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);
|
||||
|
||||
GLenum attachments[] {
|
||||
|
|
@ -864,6 +895,7 @@ int sws_t::convert(gl::frame_buf_t &fb) {
|
|||
}
|
||||
} // namespace egl
|
||||
|
||||
void free_frame(AVFrame *frame) {
|
||||
void
|
||||
free_frame(AVFrame *frame) {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,30 +17,35 @@
|
|||
#define gl_drain_errors_helper(x) gl::drain_errors(x)
|
||||
#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
|
||||
extern "C" struct _XDisplay;
|
||||
|
||||
struct AVFrame;
|
||||
void free_frame(AVFrame *frame);
|
||||
void
|
||||
free_frame(AVFrame *frame);
|
||||
|
||||
using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
||||
|
||||
namespace gl {
|
||||
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> {
|
||||
using util::buffer_t<GLuint>::buffer_t;
|
||||
|
||||
public:
|
||||
tex_t(tex_t &&) = default;
|
||||
tex_t &operator=(tex_t &&) = default;
|
||||
tex_t &
|
||||
operator=(tex_t &&) = default;
|
||||
|
||||
~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> {
|
||||
|
|
@ -48,13 +53,16 @@ class frame_buf_t : public util::buffer_t<GLuint> {
|
|||
|
||||
public:
|
||||
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();
|
||||
|
||||
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;
|
||||
for (auto fb : (*this)) {
|
||||
ctx.BindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
|
|
@ -66,7 +74,8 @@ public:
|
|||
}
|
||||
|
||||
template <class It>
|
||||
void bind(It it_begin, It it_end) {
|
||||
void
|
||||
bind(It it_begin, It it_end) {
|
||||
using namespace std::literals;
|
||||
if (std::distance(it_begin, it_end) > size()) {
|
||||
BOOST_LOG(warning) << "To many elements to bind"sv;
|
||||
|
|
@ -87,7 +96,8 @@ public:
|
|||
/**
|
||||
* 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 {
|
||||
|
|
@ -98,11 +108,14 @@ class shader_t {
|
|||
});
|
||||
|
||||
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:
|
||||
shader_internal_t _shader;
|
||||
|
|
@ -116,14 +129,19 @@ class buffer_t {
|
|||
});
|
||||
|
||||
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 update(std::string_view *members, std::size_t count, std::size_t offset = 0);
|
||||
void
|
||||
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:
|
||||
const char *_block;
|
||||
|
|
@ -143,15 +161,20 @@ class program_t {
|
|||
});
|
||||
|
||||
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:
|
||||
program_internal_t _program;
|
||||
|
|
@ -168,7 +191,8 @@ extern create_device_fn create_device;
|
|||
|
||||
using gbm_t = util::dyn_safe_ptr<device, &device_destroy>;
|
||||
|
||||
int init();
|
||||
int
|
||||
init();
|
||||
|
||||
} // namespace gbm
|
||||
|
||||
|
|
@ -230,14 +254,18 @@ struct surface_descriptor_t {
|
|||
std::uint32_t offsets[4];
|
||||
};
|
||||
|
||||
display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display);
|
||||
std::optional<ctx_t> make_ctx(display_t::pointer display);
|
||||
display_t
|
||||
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,
|
||||
const surface_descriptor_t &xrgb);
|
||||
|
||||
std::optional<nv12_t> import_target(
|
||||
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);
|
||||
|
|
@ -258,7 +286,8 @@ public:
|
|||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
void
|
||||
reset() {
|
||||
for (auto x = 0; x < 4; ++x) {
|
||||
if (sd.fds[x] >= 0) {
|
||||
close(sd.fds[x]);
|
||||
|
|
@ -276,19 +305,26 @@ public:
|
|||
|
||||
class sws_t {
|
||||
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> make(int in_width, int in_height, int out_width, int out_heigth);
|
||||
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>
|
||||
make(int in_width, int in_height, int out_width, int out_heigth);
|
||||
|
||||
// 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
|
||||
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 load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture);
|
||||
void
|
||||
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 second texture is the cursor image
|
||||
|
|
@ -313,7 +349,8 @@ public:
|
|||
std::uint64_t serial;
|
||||
};
|
||||
|
||||
bool fail();
|
||||
bool
|
||||
fail();
|
||||
} // namespace egl
|
||||
|
||||
#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(FakeKeyEvent, int, (Display * dpy, unsigned int keycode, Bool is_press, unsigned long delay));
|
||||
|
||||
static int init() {
|
||||
static int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -83,7 +84,8 @@ static int init() {
|
|||
}
|
||||
} // namespace tst
|
||||
|
||||
static int init() {
|
||||
static int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -144,7 +146,8 @@ constexpr auto UNKNOWN = 0;
|
|||
* @brief Initializes the keycode constants for translating
|
||||
* 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 {};
|
||||
|
||||
#ifdef SUNSHINE_BUILD_X11
|
||||
|
|
@ -301,28 +304,32 @@ constexpr touch_port_t target_touch_port {
|
|||
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 {
|
||||
l.first * 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 {
|
||||
l.first / 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.second += r.second;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static inline void print(const ff_envelope &envelope) {
|
||||
static inline void
|
||||
print(const ff_envelope &envelope) {
|
||||
BOOST_LOG(debug)
|
||||
<< "Envelope:"sv << 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;
|
||||
}
|
||||
|
||||
static inline void print(const ff_replay &replay) {
|
||||
static inline void
|
||||
print(const ff_replay &replay) {
|
||||
BOOST_LOG(debug)
|
||||
<< "Replay:"sv << std::endl
|
||||
<< " length: "sv << replay.length << std::endl
|
||||
<< " delay: "sv << replay.delay;
|
||||
}
|
||||
|
||||
static inline void print(const ff_trigger &trigger) {
|
||||
static inline void
|
||||
print(const ff_trigger &trigger) {
|
||||
BOOST_LOG(debug)
|
||||
<< "Trigger:"sv << std::endl
|
||||
<< " button: "sv << trigger.button << std::endl
|
||||
<< " interval: "sv << trigger.interval;
|
||||
}
|
||||
|
||||
static inline void print(const ff_effect &effect) {
|
||||
static inline void
|
||||
print(const ff_effect &effect) {
|
||||
BOOST_LOG(debug)
|
||||
<< std::endl
|
||||
<< std::endl
|
||||
|
|
@ -392,7 +402,6 @@ static inline void print(const ff_effect &effect) {
|
|||
<< " weak_magnitude: " << effect.u.rumble.weak_magnitude;
|
||||
break;
|
||||
|
||||
|
||||
case FF_SPRING:
|
||||
BOOST_LOG(debug)
|
||||
<< "FF_SPRING:" << std::endl
|
||||
|
|
@ -439,21 +448,20 @@ class effect_t {
|
|||
public:
|
||||
KITTY_DEFAULT_CONSTR_MOVE(effect_t)
|
||||
|
||||
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 {} {}
|
||||
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 {} {}
|
||||
|
||||
class data_t {
|
||||
public:
|
||||
KITTY_DEFAULT_CONSTR(data_t)
|
||||
|
||||
data_t(const ff_effect &effect)
|
||||
: delay { effect.replay.delay },
|
||||
data_t(const ff_effect &effect):
|
||||
delay { effect.replay.delay },
|
||||
length { effect.replay.length },
|
||||
end_point { std::chrono::steady_clock::time_point::min() },
|
||||
envelope {},
|
||||
start {},
|
||||
end {} {
|
||||
|
||||
switch (effect.type) {
|
||||
case FF_CONSTANT:
|
||||
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;
|
||||
|
||||
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) {
|
||||
return {};
|
||||
}
|
||||
|
|
@ -534,11 +544,13 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
void activate() {
|
||||
void
|
||||
activate() {
|
||||
end_point = std::chrono::steady_clock::now() + delay + length;
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
void
|
||||
deactivate() {
|
||||
end_point = std::chrono::steady_clock::time_point::min();
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +569,8 @@ public:
|
|||
} 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 {};
|
||||
for (auto &[_, data] : id_to_data) {
|
||||
weak_strong += data.rumble(tp);
|
||||
|
|
@ -570,7 +583,8 @@ public:
|
|||
return old_rumble;
|
||||
}
|
||||
|
||||
void upload(const ff_effect &effect) {
|
||||
void
|
||||
upload(const ff_effect &effect) {
|
||||
print(effect);
|
||||
|
||||
auto it = id_to_data.find(effect.id);
|
||||
|
|
@ -586,7 +600,8 @@ public:
|
|||
it->second = data;
|
||||
}
|
||||
|
||||
void activate(int id) {
|
||||
void
|
||||
activate(int id) {
|
||||
auto it = id_to_data.find(id);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
};
|
||||
|
||||
void broadcastRumble(safe::queue_t<mail_evdev_t> &ctx);
|
||||
int startRumble(rumble_ctx_t &ctx) {
|
||||
void
|
||||
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) };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stopRumble(rumble_ctx_t &ctx) {
|
||||
void
|
||||
stopRumble(rumble_ctx_t &ctx) {
|
||||
ctx.rumble_queue_queue.stop();
|
||||
|
||||
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 {
|
||||
public:
|
||||
void clear_touchscreen() {
|
||||
void
|
||||
clear_touchscreen() {
|
||||
std::filesystem::path touch_path { appdata() / "sunshine_touchscreen"sv };
|
||||
|
||||
if (std::filesystem::is_symlink(touch_path)) {
|
||||
|
|
@ -658,7 +679,8 @@ public:
|
|||
touch_input.reset();
|
||||
}
|
||||
|
||||
void clear_keyboard() {
|
||||
void
|
||||
clear_keyboard() {
|
||||
std::filesystem::path key_path { appdata() / "sunshine_keyboard"sv };
|
||||
|
||||
if (std::filesystem::is_symlink(key_path)) {
|
||||
|
|
@ -668,7 +690,8 @@ public:
|
|||
keyboard_input.reset();
|
||||
}
|
||||
|
||||
void clear_mouse() {
|
||||
void
|
||||
clear_mouse() {
|
||||
std::filesystem::path mouse_path { appdata() / "sunshine_mouse"sv };
|
||||
|
||||
if (std::filesystem::is_symlink(mouse_path)) {
|
||||
|
|
@ -678,7 +701,8 @@ public:
|
|||
mouse_input.reset();
|
||||
}
|
||||
|
||||
void clear_gamepad(int nr) {
|
||||
void
|
||||
clear_gamepad(int nr) {
|
||||
auto &[dev, _] = gamepads[nr];
|
||||
|
||||
if (!dev) {
|
||||
|
|
@ -700,7 +724,8 @@ public:
|
|||
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);
|
||||
|
||||
if (err) {
|
||||
|
|
@ -713,7 +738,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int create_touchscreen() {
|
||||
int
|
||||
create_touchscreen() {
|
||||
int err = libevdev_uinput_create_from_device(touch_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &touch_input);
|
||||
|
||||
if (err) {
|
||||
|
|
@ -726,7 +752,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int create_keyboard() {
|
||||
int
|
||||
create_keyboard() {
|
||||
int err = libevdev_uinput_create_from_device(keyboard_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &keyboard_input);
|
||||
|
||||
if (err) {
|
||||
|
|
@ -739,7 +766,8 @@ public:
|
|||
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]);
|
||||
|
||||
int err = libevdev_uinput_create_from_device(gamepad_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &input);
|
||||
|
|
@ -775,7 +803,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
void
|
||||
clear() {
|
||||
clear_touchscreen();
|
||||
clear_keyboard();
|
||||
clear_mouse();
|
||||
|
|
@ -812,7 +841,8 @@ public:
|
|||
#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;
|
||||
polls_recv.reserve(polls.size());
|
||||
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<pollfd_t> polls;
|
||||
|
||||
|
|
@ -971,7 +1002,6 @@ void broadcastRumble(safe::queue_t<mail_evdev_t> &rumble_queue_queue) {
|
|||
});
|
||||
|
||||
if (effect_it != std::end(effects)) {
|
||||
|
||||
auto poll_it = std::begin(polls) + (effect_it - std::begin(effects));
|
||||
|
||||
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);
|
||||
* ```
|
||||
*/
|
||||
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
|
||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||
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);
|
||||
* ```
|
||||
*/
|
||||
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();
|
||||
if (!touchscreen) {
|
||||
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
|
||||
* ```
|
||||
*/
|
||||
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
|
||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||
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
|
||||
* ```
|
||||
*/
|
||||
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();
|
||||
if (!mouse) {
|
||||
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
|
||||
* ```
|
||||
*/
|
||||
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
|
||||
unsigned int x_button = 0;
|
||||
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
|
||||
* ```
|
||||
*/
|
||||
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();
|
||||
if (!mouse) {
|
||||
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);
|
||||
* ```
|
||||
*/
|
||||
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
|
||||
Display *xdisplay = ((input_raw_t *) input.get())->display;
|
||||
if (!xdisplay) {
|
||||
|
|
@ -1246,7 +1283,8 @@ static void x_scroll(input_t &input, int distance, int button_pos, int button_ne
|
|||
* 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;
|
||||
|
||||
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);
|
||||
* ```
|
||||
*/
|
||||
void hscroll(input_t &input, int high_res_distance) {
|
||||
void
|
||||
hscroll(input_t &input, int high_res_distance) {
|
||||
int distance = high_res_distance / 120;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static keycode_t keysym(std::uint16_t modcode) {
|
||||
static keycode_t
|
||||
keysym(std::uint16_t modcode) {
|
||||
if (modcode <= keycodes.size()) {
|
||||
return keycodes[modcode];
|
||||
}
|
||||
|
|
@ -1303,7 +1343,8 @@ static keycode_t keysym(std::uint16_t modcode) {
|
|||
* 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
|
||||
auto keycode = keysym(modcode);
|
||||
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
|
||||
* ```
|
||||
*/
|
||||
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();
|
||||
if (!keyboard) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_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
|
||||
*/
|
||||
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;
|
||||
ss << std::hex << std::setfill('0');
|
||||
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
|
||||
* 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();
|
||||
if (!kb) {
|
||||
return;
|
||||
|
|
@ -1429,18 +1474,20 @@ void unicode(input_t &input, char *utf8, int size) {
|
|||
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));
|
||||
}
|
||||
|
||||
void free_gamepad(input_t &input, int nr) {
|
||||
void
|
||||
free_gamepad(input_t &input, int 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]);
|
||||
|
||||
|
||||
auto bf = gamepad_state.buttonFlags ^ gamepad_state_old.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();
|
||||
* ```
|
||||
*/
|
||||
evdev_t keyboard() {
|
||||
evdev_t
|
||||
keyboard() {
|
||||
evdev_t dev { libevdev_new() };
|
||||
|
||||
libevdev_set_uniq(dev.get(), "Sunshine Keyboard");
|
||||
|
|
@ -1535,7 +1583,8 @@ evdev_t keyboard() {
|
|||
* auto my_mouse = mouse();
|
||||
* ```
|
||||
*/
|
||||
evdev_t mouse() {
|
||||
evdev_t
|
||||
mouse() {
|
||||
evdev_t dev { libevdev_new() };
|
||||
|
||||
libevdev_set_uniq(dev.get(), "Sunshine Mouse");
|
||||
|
|
@ -1585,7 +1634,8 @@ evdev_t mouse() {
|
|||
* auto my_touchscreen = touchscreen();
|
||||
* ```
|
||||
*/
|
||||
evdev_t touchscreen() {
|
||||
evdev_t
|
||||
touchscreen() {
|
||||
evdev_t dev { libevdev_new() };
|
||||
|
||||
libevdev_set_uniq(dev.get(), "Sunshine Touch");
|
||||
|
|
@ -1597,7 +1647,6 @@ evdev_t touchscreen() {
|
|||
|
||||
libevdev_enable_property(dev.get(), INPUT_PROP_DIRECT);
|
||||
|
||||
|
||||
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_TOOL_PEN, nullptr); // Needed to be enabled for BTN_TOOL_FINGER to work.
|
||||
|
|
@ -1635,7 +1684,8 @@ evdev_t touchscreen() {
|
|||
* auto my_x360 = x360();
|
||||
* ```
|
||||
*/
|
||||
evdev_t x360() {
|
||||
evdev_t
|
||||
x360() {
|
||||
evdev_t dev { libevdev_new() };
|
||||
|
||||
input_absinfo stick {
|
||||
|
|
@ -1711,7 +1761,8 @@ evdev_t x360() {
|
|||
* auto my_input = input();
|
||||
* ```
|
||||
*/
|
||||
input_t input() {
|
||||
input_t
|
||||
input() {
|
||||
input_t result { new input_raw_t() };
|
||||
auto &gp = *(input_raw_t *) result.get();
|
||||
|
||||
|
|
@ -1749,12 +1800,14 @@ input_t input() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void freeInput(void *p) {
|
||||
void
|
||||
freeInput(void *p) {
|
||||
auto *input = (input_raw_t *) p;
|
||||
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 };
|
||||
|
||||
return gamepads;
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ public:
|
|||
|
||||
class wrapper_fb {
|
||||
public:
|
||||
wrapper_fb(drmModeFB *fb)
|
||||
: fb { fb }, fb_id { fb->fb_id }, width { fb->width }, height { fb->height } {
|
||||
wrapper_fb(drmModeFB *fb):
|
||||
fb { fb }, fb_id { fb->fb_id }, width { fb->width }, height { fb->height } {
|
||||
pixel_format = DRM_FORMAT_XRGB8888;
|
||||
modifier = DRM_FORMAT_MOD_INVALID;
|
||||
std::fill_n(handles, 4, 0);
|
||||
|
|
@ -62,8 +62,8 @@ public:
|
|||
pitches[0] = fb->pitch;
|
||||
}
|
||||
|
||||
wrapper_fb(drmModeFB2 *fb2)
|
||||
: fb2 { fb2 }, fb_id { fb2->fb_id }, width { fb2->width }, height { fb2->height } {
|
||||
wrapper_fb(drmModeFB2 *fb2):
|
||||
fb2 { fb2 }, fb_id { fb2->fb_id }, width { fb2->width }, height { fb2->height } {
|
||||
pixel_format = fb2->pixel_format;
|
||||
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_height;
|
||||
|
||||
std::string_view plane_type(std::uint64_t val) {
|
||||
std::string_view
|
||||
plane_type(std::uint64_t val) {
|
||||
switch (val) {
|
||||
case DRM_PLANE_TYPE_OVERLAY:
|
||||
return "DRM_PLANE_TYPE_OVERLAY"sv;
|
||||
|
|
@ -149,7 +150,8 @@ struct card_descriptor_t {
|
|||
|
||||
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) \
|
||||
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> {
|
||||
public:
|
||||
plane_it_t(int fd, std::uint32_t *plane_p, std::uint32_t *end)
|
||||
: fd { fd }, plane_p { plane_p }, end { end } {
|
||||
plane_it_t(int fd, std::uint32_t *plane_p, std::uint32_t *end):
|
||||
fd { fd }, plane_p { plane_p }, end { end } {
|
||||
inc();
|
||||
}
|
||||
|
||||
plane_it_t(int fd, std::uint32_t *end)
|
||||
: fd { fd }, plane_p { end }, end { end } {}
|
||||
plane_it_t(int fd, std::uint32_t *end):
|
||||
fd { fd }, plane_p { end }, end { end } {}
|
||||
|
||||
void inc() {
|
||||
void
|
||||
inc() {
|
||||
this->plane.reset();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
plane_t::pointer get() {
|
||||
plane_t::pointer
|
||||
get() {
|
||||
return plane.get();
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +228,8 @@ class card_t {
|
|||
public:
|
||||
using connector_interal_t = util::safe_ptr<drmModeConnector, drmModeFreeConnector>;
|
||||
|
||||
int init(const char *path) {
|
||||
int
|
||||
init(const char *path) {
|
||||
cap_sys_admin admin;
|
||||
fd.el = open(path, O_RDWR);
|
||||
|
||||
|
|
@ -250,7 +256,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
fb_t fb(plane_t::pointer plane) {
|
||||
fb_t
|
||||
fb(plane_t::pointer plane) {
|
||||
cap_sys_admin admin;
|
||||
|
||||
auto fb2 = drmModeGetFB2(fd.el, plane->fb_id);
|
||||
|
|
@ -266,19 +273,23 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
crtc_t crtc(std::uint32_t id) {
|
||||
crtc_t
|
||||
crtc(std::uint32_t 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);
|
||||
}
|
||||
|
||||
res_t res() {
|
||||
res_t
|
||||
res() {
|
||||
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);
|
||||
for (auto &[prop, val] : props) {
|
||||
if (prop->name == "type"sv) {
|
||||
|
|
@ -294,7 +305,8 @@ public:
|
|||
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);
|
||||
for (auto &[prop, val] : props) {
|
||||
if (prop->name == "rotation"sv) {
|
||||
|
|
@ -306,11 +318,13 @@ public:
|
|||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
if (!resources) {
|
||||
BOOST_LOG(error) << "Couldn't get connector resources"sv;
|
||||
|
|
@ -343,7 +357,8 @@ public:
|
|||
return monitors;
|
||||
}
|
||||
|
||||
file_t handleFD(std::uint32_t handle) {
|
||||
file_t
|
||||
handleFD(std::uint32_t handle) {
|
||||
file_t fb_fd;
|
||||
|
||||
auto status = drmPrimeHandleToFD(fd.el, handle, 0 /* flags */, &fb_fd.el);
|
||||
|
|
@ -354,7 +369,8 @@ public:
|
|||
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);
|
||||
|
||||
std::vector<std::pair<prop_t, std::uint64_t>> props;
|
||||
|
|
@ -367,40 +383,47 @@ public:
|
|||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
plane_t operator[](std::uint32_t index) {
|
||||
plane_t
|
||||
operator[](std::uint32_t index) {
|
||||
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
||||
}
|
||||
|
||||
std::uint32_t count() {
|
||||
std::uint32_t
|
||||
count() {
|
||||
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 };
|
||||
}
|
||||
|
||||
plane_it_t end() const {
|
||||
plane_it_t
|
||||
end() const {
|
||||
return plane_it_t { fd.el, plane_res->planes + plane_res->count_planes };
|
||||
}
|
||||
|
||||
|
||||
file_t fd;
|
||||
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;
|
||||
|
||||
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) {
|
||||
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
|
||||
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 {
|
||||
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;
|
||||
|
||||
int monitor_index = util::from_view(display_name);
|
||||
|
|
@ -593,7 +619,8 @@ public:
|
|||
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);
|
||||
|
||||
auto fb = card.fb(plane.get());
|
||||
|
|
@ -660,9 +687,11 @@ public:
|
|||
|
||||
class display_ram_t: public display_t {
|
||||
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) {
|
||||
BOOST_LOG(warning) << "libgbm not initialized"sv;
|
||||
return -1;
|
||||
|
|
@ -693,7 +722,8 @@ public:
|
|||
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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -728,7 +758,8 @@ public:
|
|||
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) {
|
||||
return va::make_hwdevice(width, height, false);
|
||||
}
|
||||
|
|
@ -736,7 +767,8 @@ public:
|
|||
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];
|
||||
|
||||
egl::surface_descriptor_t sd;
|
||||
|
|
@ -770,7 +802,8 @@ public:
|
|||
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>();
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
|
@ -781,7 +814,8 @@ public:
|
|||
return img;
|
||||
}
|
||||
|
||||
int dummy_img(platf::img_t *img) override {
|
||||
int
|
||||
dummy_img(platf::img_t *img) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -792,9 +826,11 @@ public:
|
|||
|
||||
class display_vram_t: public display_t {
|
||||
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) {
|
||||
return va::make_hwdevice(width, height, dup(card.fd.el), img_offset_x, img_offset_y, true);
|
||||
}
|
||||
|
|
@ -803,7 +839,8 @@ public:
|
|||
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>();
|
||||
|
||||
img->serial = std::numeric_limits<decltype(img->serial)>::max();
|
||||
|
|
@ -816,11 +853,13 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -855,7 +894,8 @@ public:
|
|||
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];
|
||||
|
||||
auto img = (egl::img_descriptor_t *) img_out_base;
|
||||
|
|
@ -888,7 +928,8 @@ public:
|
|||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -908,7 +949,8 @@ public:
|
|||
|
||||
} // 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
|
@ -939,7 +980,8 @@ std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::stri
|
|||
*
|
||||
* 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();
|
||||
|
||||
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
|
||||
std::vector<std::string> kms_display_names() {
|
||||
std::vector<std::string>
|
||||
kms_display_names() {
|
||||
int count = 0;
|
||||
|
||||
if (!fs::exists("/dev/dri")) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ namespace bp = boost::process;
|
|||
window_system_e window_system;
|
||||
|
||||
namespace dyn {
|
||||
void *handle(const std::vector<const char *> &libs) {
|
||||
void *
|
||||
handle(const std::vector<const char *> &libs) {
|
||||
void *handle;
|
||||
|
||||
for (auto lib : libs) {
|
||||
|
|
@ -60,7 +61,8 @@ void *handle(const std::vector<const char *> &libs) {
|
|||
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;
|
||||
for (auto &func : funcs) {
|
||||
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 {
|
||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||
|
||||
ifaddr_t get_ifaddrs() {
|
||||
ifaddr_t
|
||||
get_ifaddrs() {
|
||||
ifaddrs *p { nullptr };
|
||||
|
||||
getifaddrs(&p);
|
||||
|
|
@ -88,7 +91,8 @@ ifaddr_t get_ifaddrs() {
|
|||
return ifaddr_t { p };
|
||||
}
|
||||
|
||||
fs::path appdata() {
|
||||
fs::path
|
||||
appdata() {
|
||||
const char *homedir;
|
||||
if ((homedir = getenv("HOME")) == nullptr) {
|
||||
homedir = getpwuid(geteuid())->pw_dir;
|
||||
|
|
@ -97,7 +101,8 @@ fs::path appdata() {
|
|||
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];
|
||||
|
||||
auto family = ip_addr->sa_family;
|
||||
|
|
@ -114,7 +119,8 @@ std::string from_sockaddr(const sockaddr *const ip_addr) {
|
|||
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];
|
||||
|
||||
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 } };
|
||||
}
|
||||
|
||||
std::string get_mac_address(const std::string_view &address) {
|
||||
std::string
|
||||
get_mac_address(const std::string_view &address) {
|
||||
auto ifaddrs = get_ifaddrs();
|
||||
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!group) {
|
||||
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
|
||||
}
|
||||
|
||||
void streaming_will_start() {
|
||||
void
|
||||
streaming_will_start() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void streaming_will_stop() {
|
||||
void
|
||||
streaming_will_stop() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
bool restart_supported() {
|
||||
bool
|
||||
restart_supported() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool restart() {
|
||||
bool
|
||||
restart() {
|
||||
// Restart not supported yet
|
||||
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;
|
||||
|
||||
// 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 {
|
||||
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() {
|
||||
int reset_val = -1;
|
||||
|
|
@ -364,7 +379,8 @@ private:
|
|||
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 level;
|
||||
|
|
@ -423,42 +439,55 @@ enum source_e : std::size_t {
|
|||
static std::bitset<source::MAX_FLAGS> sources;
|
||||
|
||||
#ifdef SUNSHINE_BUILD_CUDA
|
||||
std::vector<std::string> 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);
|
||||
std::vector<std::string>
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUNSHINE_BUILD_WAYLAND
|
||||
std::vector<std::string> 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);
|
||||
std::vector<std::string>
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUNSHINE_BUILD_DRM
|
||||
std::vector<std::string> 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);
|
||||
std::vector<std::string>
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUNSHINE_BUILD_X11
|
||||
std::vector<std::string> 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);
|
||||
std::vector<std::string>
|
||||
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();
|
||||
}
|
||||
#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
|
||||
// display using NvFBC only supports mem_type_e::cuda
|
||||
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 {};
|
||||
}
|
||||
|
||||
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
|
||||
if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) {
|
||||
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;
|
||||
}
|
||||
|
||||
std::unique_ptr<deinit_t> init() {
|
||||
std::unique_ptr<deinit_t>
|
||||
init() {
|
||||
// These are allowed to fail.
|
||||
gbm::init();
|
||||
va::init();
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ extern window_system_e window_system;
|
|||
namespace dyn {
|
||||
typedef void (*apiproc)(void);
|
||||
|
||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
||||
void *handle(const std::vector<const char *> &libs);
|
||||
int
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -195,8 +195,8 @@ simple_poll_quit_fn simple_poll_quit;
|
|||
simple_poll_new_fn simple_poll_new;
|
||||
simple_poll_free_fn simple_poll_free;
|
||||
|
||||
|
||||
int init_common() {
|
||||
int
|
||||
init_common() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -229,7 +229,8 @@ int init_common() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init_client() {
|
||||
int
|
||||
init_client() {
|
||||
if (init_common()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -270,7 +271,8 @@ int init_client() {
|
|||
namespace platf::publish {
|
||||
|
||||
template <class T>
|
||||
void free(T *p) {
|
||||
void
|
||||
free(T *p) {
|
||||
avahi::free(p);
|
||||
}
|
||||
|
||||
|
|
@ -286,9 +288,11 @@ client_t client;
|
|||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
auto fg = util::fail_guard([]() {
|
||||
|
|
@ -366,7 +371,8 @@ void create_services(avahi::Client *c) {
|
|||
fg.disable();
|
||||
}
|
||||
|
||||
void client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||
void
|
||||
client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||
switch (state) {
|
||||
case avahi::CLIENT_S_RUNNING:
|
||||
create_services(c);
|
||||
|
|
@ -388,7 +394,8 @@ class deinit_t : public ::platf::deinit_t {
|
|||
public:
|
||||
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 {
|
||||
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()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ extern "C" {
|
|||
#if !VA_CHECK_VERSION(1, 9, 0)
|
||||
/* vaSyncBuffer stub allows Sunshine built against libva <2.9.0
|
||||
to link against ffmpeg on libva 2.9.0 or later */
|
||||
VAStatus vaSyncBuffer(
|
||||
VAStatus
|
||||
vaSyncBuffer(
|
||||
VADisplay dpy,
|
||||
VABufferID buf_id,
|
||||
uint64_t timeout_ns) {
|
||||
|
|
@ -193,7 +194,6 @@ enum class entry_e {
|
|||
ProtectedContent = 14,
|
||||
};
|
||||
|
||||
|
||||
typedef VAStatus (*queryConfigEntrypoints_fn)(VADisplay dpy, profile_e profile, entry_e *entrypoint_list, int *num_entrypoints);
|
||||
typedef int (*maxNumEntrypoints_fn)(VADisplay dpy);
|
||||
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>;
|
||||
|
||||
int init_main_va() {
|
||||
int
|
||||
init_main_va() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -255,7 +256,8 @@ int init_main_va() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
if (init_main_va()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -284,11 +286,13 @@ int init() {
|
|||
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 {
|
||||
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);
|
||||
|
||||
if (!va::initialize || !gbm::create_device) {
|
||||
|
|
@ -324,7 +328,8 @@ public:
|
|||
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->frame = frame;
|
||||
|
||||
|
|
@ -345,7 +350,6 @@ public:
|
|||
va::EXPORT_SURFACE_WRITE_ONLY | va::EXPORT_SURFACE_COMPOSED_LAYERS,
|
||||
&prime);
|
||||
if (status) {
|
||||
|
||||
BOOST_LOG(error) << "Couldn't export va surface handle: ["sv << (int) surface << "]: "sv << va::errorStr(status);
|
||||
|
||||
return -1;
|
||||
|
|
@ -390,7 +394,8 @@ public:
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +418,8 @@ public:
|
|||
|
||||
class va_ram_t: public va_t {
|
||||
public:
|
||||
int convert(platf::img_t &img) override {
|
||||
int
|
||||
convert(platf::img_t &img) override {
|
||||
sws.load_ram(img);
|
||||
|
||||
sws.convert(nv12->buf);
|
||||
|
|
@ -423,7 +429,8 @@ public:
|
|||
|
||||
class va_vram_t: public va_t {
|
||||
public:
|
||||
int convert(platf::img_t &img) override {
|
||||
int
|
||||
convert(platf::img_t &img) override {
|
||||
auto &descriptor = (egl::img_descriptor_t &) img;
|
||||
|
||||
if (descriptor.sequence > sequence) {
|
||||
|
|
@ -446,7 +453,8 @@ public:
|
|||
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))) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -499,11 +507,13 @@ typedef struct AVVAAPIDeviceContext {
|
|||
unsigned int driver_quirks;
|
||||
} 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
BOOST_LOG(warning) << "libva not loaded"sv;
|
||||
return -1;
|
||||
|
|
@ -565,7 +575,8 @@ int vaapi_make_hwdevice_ctx(platf::hwdevice_t *base, AVBufferRef **hw_device_buf
|
|||
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;
|
||||
entrypoints.resize(maxNumEntrypoints(display));
|
||||
|
||||
|
|
@ -586,7 +597,8 @@ static bool query(display_t::pointer display, profile_e profile) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool validate(int fd) {
|
||||
bool
|
||||
validate(int fd) {
|
||||
if (init()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -625,7 +637,8 @@ bool validate(int fd) {
|
|||
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) {
|
||||
auto egl = std::make_shared<va::va_vram_t>();
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} // namespace va
|
||||
|
|
|
|||
|
|
@ -15,13 +15,18 @@ namespace va {
|
|||
* offset_y --> Vertical offset of the image in the texture
|
||||
* 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> 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);
|
||||
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, 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
|
||||
bool validate(int fd);
|
||||
bool
|
||||
validate(int fd);
|
||||
|
||||
int init();
|
||||
int
|
||||
init();
|
||||
} // namespace va
|
||||
#endif
|
||||
|
|
@ -23,13 +23,15 @@ namespace wl {
|
|||
|
||||
// Helper to call C++ method from wayland C callback
|
||||
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...);
|
||||
}
|
||||
|
||||
#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) {
|
||||
display_name = std::getenv("WAYLAND_DISPLAY");
|
||||
}
|
||||
|
|
@ -50,16 +52,18 @@ int display_t::init(const char *display_name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void display_t::roundtrip() {
|
||||
void
|
||||
display_t::roundtrip() {
|
||||
wl_display_roundtrip(display_internal.get());
|
||||
}
|
||||
|
||||
wl_registry *display_t::registry() {
|
||||
wl_registry *
|
||||
display_t::registry() {
|
||||
return wl_display_get_registry(display_internal.get());
|
||||
}
|
||||
|
||||
inline monitor_t::monitor_t(wl_output *output)
|
||||
: output { output }, listener {
|
||||
inline monitor_t::monitor_t(wl_output *output):
|
||||
output { output }, listener {
|
||||
&CLASS_CALL(monitor_t, xdg_position),
|
||||
&CLASS_CALL(monitor_t, xdg_size),
|
||||
&CLASS_CALL(monitor_t, xdg_done),
|
||||
|
|
@ -67,52 +71,62 @@ inline monitor_t::monitor_t(wl_output *output)
|
|||
&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;
|
||||
|
||||
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;
|
||||
|
||||
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_y = 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.height = 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;
|
||||
}
|
||||
|
||||
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);
|
||||
zxdg_output_v1_add_listener(xdg_output, &listener, this);
|
||||
}
|
||||
|
||||
interface_t::interface_t() noexcept
|
||||
: output_manager { nullptr }, listener {
|
||||
:
|
||||
output_manager { nullptr },
|
||||
listener {
|
||||
&CLASS_CALL(interface_t, add_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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dmabuf_t::dmabuf_t()
|
||||
: status { READY }, frames {}, current_frame { &frames[0] }, listener {
|
||||
dmabuf_t::dmabuf_t():
|
||||
status { READY }, frames {}, current_frame { &frames[0] }, listener {
|
||||
&CLASS_CALL(dmabuf_t, frame),
|
||||
&CLASS_CALL(dmabuf_t, object),
|
||||
&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);
|
||||
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,
|
||||
std::uint32_t width, std::uint32_t height,
|
||||
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;
|
||||
}
|
||||
|
||||
void dmabuf_t::object(
|
||||
void
|
||||
dmabuf_t::object(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t index,
|
||||
std::int32_t fd,
|
||||
|
|
@ -192,10 +210,10 @@ void dmabuf_t::object(
|
|||
next_frame->sd.offsets[plane_index] = offset;
|
||||
}
|
||||
|
||||
void dmabuf_t::ready(
|
||||
void
|
||||
dmabuf_t::ready(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec) {
|
||||
|
||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||
|
||||
current_frame->destroy();
|
||||
|
|
@ -204,10 +222,10 @@ void dmabuf_t::ready(
|
|||
status = READY;
|
||||
}
|
||||
|
||||
void dmabuf_t::cancel(
|
||||
void
|
||||
dmabuf_t::cancel(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t reason) {
|
||||
|
||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||
|
||||
auto next_frame = get_next_frame();
|
||||
|
|
@ -216,7 +234,8 @@ void dmabuf_t::cancel(
|
|||
status = REINIT;
|
||||
}
|
||||
|
||||
void frame_t::destroy() {
|
||||
void
|
||||
frame_t::destroy() {
|
||||
for (auto x = 0; x < 4; ++x) {
|
||||
if (sd.fds[x] >= 0) {
|
||||
close(sd.fds[x]);
|
||||
|
|
@ -231,7 +250,8 @@ frame_t::frame_t() {
|
|||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static bool validate() {
|
||||
static bool
|
||||
validate() {
|
||||
display_t display;
|
||||
|
||||
return display.init() == 0;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
static bool validated = validate();
|
||||
|
||||
return !validated;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ public:
|
|||
frame_t();
|
||||
egl::surface_descriptor_t sd;
|
||||
|
||||
void destroy();
|
||||
void
|
||||
destroy();
|
||||
};
|
||||
|
||||
class dmabuf_t {
|
||||
|
|
@ -38,16 +39,20 @@ public:
|
|||
dmabuf_t(dmabuf_t &&) = delete;
|
||||
dmabuf_t(const dmabuf_t &) = delete;
|
||||
|
||||
dmabuf_t &operator=(const dmabuf_t &) = delete;
|
||||
dmabuf_t &operator=(dmabuf_t &&) = delete;
|
||||
dmabuf_t &
|
||||
operator=(const dmabuf_t &) = delete;
|
||||
dmabuf_t &
|
||||
operator=(dmabuf_t &&) = delete;
|
||||
|
||||
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();
|
||||
|
||||
void frame(
|
||||
void
|
||||
frame(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t width, std::uint32_t height,
|
||||
std::uint32_t x, std::uint32_t y,
|
||||
|
|
@ -56,7 +61,8 @@ public:
|
|||
std::uint32_t high, std::uint32_t low,
|
||||
std::uint32_t obj_count);
|
||||
|
||||
void object(
|
||||
void
|
||||
object(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t index,
|
||||
std::int32_t fd,
|
||||
|
|
@ -65,15 +71,18 @@ public:
|
|||
std::uint32_t stride,
|
||||
std::uint32_t plane_index);
|
||||
|
||||
void ready(
|
||||
void
|
||||
ready(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
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,
|
||||
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];
|
||||
}
|
||||
|
||||
|
|
@ -90,18 +99,26 @@ public:
|
|||
monitor_t(monitor_t &&) = delete;
|
||||
monitor_t(const monitor_t &) = delete;
|
||||
|
||||
monitor_t &operator=(const monitor_t &) = delete;
|
||||
monitor_t &operator=(monitor_t &&) = delete;
|
||||
monitor_t &
|
||||
operator=(const monitor_t &) = delete;
|
||||
monitor_t &
|
||||
operator=(monitor_t &&) = delete;
|
||||
|
||||
monitor_t(wl_output *output);
|
||||
|
||||
void xdg_name(zxdg_output_v1 *, const char *name);
|
||||
void xdg_description(zxdg_output_v1 *, const char *description);
|
||||
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
|
||||
xdg_name(zxdg_output_v1 *, const char *name);
|
||||
void
|
||||
xdg_description(zxdg_output_v1 *, const char *description);
|
||||
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;
|
||||
|
||||
|
|
@ -129,25 +146,31 @@ public:
|
|||
interface_t(interface_t &&) = delete;
|
||||
interface_t(const interface_t &) = delete;
|
||||
|
||||
interface_t &operator=(const interface_t &) = delete;
|
||||
interface_t &operator=(interface_t &&) = delete;
|
||||
interface_t &
|
||||
operator=(const interface_t &) = delete;
|
||||
interface_t &
|
||||
operator=(interface_t &&) = delete;
|
||||
|
||||
interface_t() noexcept;
|
||||
|
||||
void listen(wl_registry *registry);
|
||||
void
|
||||
listen(wl_registry *registry);
|
||||
|
||||
std::vector<std::unique_ptr<monitor_t>> monitors;
|
||||
|
||||
zwlr_export_dmabuf_manager_v1 *dmabuf_manager;
|
||||
zxdg_output_manager_v1 *output_manager;
|
||||
|
||||
bool operator[](interface_e bit) const {
|
||||
bool
|
||||
operator[](interface_e bit) const {
|
||||
return interface[bit];
|
||||
}
|
||||
|
||||
private:
|
||||
void 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);
|
||||
void
|
||||
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;
|
||||
|
||||
|
|
@ -160,16 +183,20 @@ public:
|
|||
* Initialize display with display_name
|
||||
* 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
|
||||
void roundtrip();
|
||||
void
|
||||
roundtrip();
|
||||
|
||||
// Get the registry associated with the display
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
|
@ -177,9 +204,11 @@ private:
|
|||
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
|
||||
#else
|
||||
|
||||
|
|
@ -192,12 +221,15 @@ public:
|
|||
monitor_t(monitor_t &&) = delete;
|
||||
monitor_t(const monitor_t &) = delete;
|
||||
|
||||
monitor_t &operator=(const monitor_t &) = delete;
|
||||
monitor_t &operator=(monitor_t &&) = delete;
|
||||
monitor_t &
|
||||
operator=(const monitor_t &) = delete;
|
||||
monitor_t &
|
||||
operator=(monitor_t &&) = delete;
|
||||
|
||||
monitor_t(wl_output *output);
|
||||
|
||||
void listen(zxdg_output_manager_v1 *output_manager);
|
||||
void
|
||||
listen(zxdg_output_manager_v1 *output_manager);
|
||||
|
||||
wl_output *output;
|
||||
|
||||
|
|
@ -207,9 +239,11 @@ public:
|
|||
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
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ struct img_t : public platf::img_t {
|
|||
|
||||
class wlr_t: public platf::display_t {
|
||||
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;
|
||||
mem_type = hwdevice_type;
|
||||
|
||||
|
|
@ -73,11 +74,13 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dummy_img(platf::img_t *img) override {
|
||||
int
|
||||
dummy_img(platf::img_t *img) override {
|
||||
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;
|
||||
|
||||
dmabuf.listen(interface.dmabuf_manager, output, cursor);
|
||||
|
|
@ -95,7 +98,6 @@ public:
|
|||
dmabuf.status == dmabuf_t::REINIT ||
|
||||
current_frame->sd.width != width ||
|
||||
current_frame->sd.height != height) {
|
||||
|
||||
return platf::capture_e::reinit;
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +117,8 @@ public:
|
|||
|
||||
class wlr_ram_t: public wlr_t {
|
||||
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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -149,7 +152,8 @@ public:
|
|||
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);
|
||||
if (status != platf::capture_e::ok) {
|
||||
return status;
|
||||
|
|
@ -176,7 +180,8 @@ public:
|
|||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -196,7 +201,8 @@ public:
|
|||
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) {
|
||||
return va::make_hwdevice(width, height, false);
|
||||
}
|
||||
|
|
@ -204,7 +210,8 @@ public:
|
|||
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>();
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
|
@ -221,7 +228,8 @@ public:
|
|||
|
||||
class wlr_vram_t: public wlr_t {
|
||||
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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -255,7 +263,8 @@ public:
|
|||
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);
|
||||
if (status != platf::capture_e::ok) {
|
||||
return status;
|
||||
|
|
@ -277,7 +286,8 @@ public:
|
|||
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>();
|
||||
|
||||
img->sequence = 0;
|
||||
|
|
@ -290,7 +300,8 @@ public:
|
|||
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) {
|
||||
return va::make_hwdevice(width, height, 0, 0, true);
|
||||
}
|
||||
|
|
@ -298,7 +309,8 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +320,8 @@ public:
|
|||
} // namespace wl
|
||||
|
||||
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) {
|
||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||
return nullptr;
|
||||
|
|
@ -331,7 +344,8 @@ std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::strin
|
|||
return wlr;
|
||||
}
|
||||
|
||||
std::vector<std::string> wl_display_names() {
|
||||
std::vector<std::string>
|
||||
wl_display_names() {
|
||||
std::vector<std::string> display_names;
|
||||
|
||||
wl::display_t display;
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@
|
|||
using namespace std::literals;
|
||||
|
||||
namespace platf {
|
||||
int load_xcb();
|
||||
int load_x11();
|
||||
int
|
||||
load_xcb();
|
||||
int
|
||||
load_x11();
|
||||
|
||||
namespace x11 {
|
||||
#define _FN(x, ret, args) \
|
||||
|
|
@ -66,7 +68,8 @@ _FN(FreeScreenResources, void, (XRRScreenResources * resources));
|
|||
_FN(FreeOutputInfo, void, (XRROutputInfo * outputInfo));
|
||||
_FN(FreeCrtcInfo, void, (XRRCrtcInfo * crtcInfo));
|
||||
|
||||
static int init() {
|
||||
static int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -100,7 +103,8 @@ static int init() {
|
|||
namespace fix {
|
||||
_FN(GetCursorImage, XFixesCursorImage *, (Display * dpy));
|
||||
|
||||
static int init() {
|
||||
static int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -126,7 +130,8 @@ static int init() {
|
|||
}
|
||||
} // namespace fix
|
||||
|
||||
static int init() {
|
||||
static int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
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(generate_id, std::uint32_t, (xcb_connection_t * c));
|
||||
|
||||
int init_shm() {
|
||||
int
|
||||
init_shm() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -221,7 +227,8 @@ int init_shm() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -255,8 +262,10 @@ int init() {
|
|||
#undef _FN
|
||||
} // namespace xcb
|
||||
|
||||
void freeImage(XImage *);
|
||||
void freeX(XFixesCursorImage *);
|
||||
void
|
||||
freeImage(XImage *);
|
||||
void
|
||||
freeX(XFixesCursorImage *);
|
||||
|
||||
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>;
|
||||
|
|
@ -270,9 +279,12 @@ using screen_res_t = util::dyn_safe_ptr<_XRRScreenResources, &x11::rr::FreeScre
|
|||
|
||||
class shm_id_t {
|
||||
public:
|
||||
shm_id_t() : id { -1 } {}
|
||||
shm_id_t(int id) : id { id } {}
|
||||
shm_id_t(shm_id_t &&other) noexcept : id(other.id) {
|
||||
shm_id_t():
|
||||
id { -1 } {}
|
||||
shm_id_t(int id):
|
||||
id { id } {}
|
||||
shm_id_t(shm_id_t &&other) noexcept:
|
||||
id(other.id) {
|
||||
other.id = -1;
|
||||
}
|
||||
|
||||
|
|
@ -287,10 +299,13 @@ public:
|
|||
|
||||
class shm_data_t {
|
||||
public:
|
||||
shm_data_t() : data { (void *)-1 } {}
|
||||
shm_data_t(void *data) : data { data } {}
|
||||
shm_data_t():
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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) };
|
||||
|
||||
if (!overlay) {
|
||||
|
|
@ -379,11 +395,13 @@ struct x11_attr_t : public display_t {
|
|||
*/
|
||||
// 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
BOOST_LOG(error) << "Could not open X11 display"sv;
|
||||
return -1;
|
||||
|
|
@ -452,11 +470,13 @@ struct x11_attr_t : public display_t {
|
|||
/**
|
||||
* Called when the display attributes should change.
|
||||
*/
|
||||
void refresh() {
|
||||
void
|
||||
refresh() {
|
||||
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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -491,7 +511,8 @@ struct x11_attr_t : public display_t {
|
|||
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();
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
std::shared_ptr<img_t> alloc_img() override {
|
||||
std::shared_ptr<img_t>
|
||||
alloc_img() override {
|
||||
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) {
|
||||
return va::make_hwdevice(width, height, false);
|
||||
}
|
||||
|
|
@ -534,7 +557,8 @@ struct x11_attr_t : public display_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);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -552,13 +576,15 @@ struct shm_attr_t : public x11_attr_t {
|
|||
|
||||
task_pool_util::TaskPool::task_id_t refresh_task_id;
|
||||
|
||||
void delayed_refresh() {
|
||||
void
|
||||
delayed_refresh() {
|
||||
refresh();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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();
|
||||
|
||||
while (img) {
|
||||
|
|
@ -602,7 +629,8 @@ struct shm_attr_t : public x11_attr_t {
|
|||
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
|
||||
if (xattr.width != env_width || xattr.height != env_height) {
|
||||
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>();
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
|
@ -638,11 +667,13 @@ struct shm_attr_t : public x11_attr_t {
|
|||
return img;
|
||||
}
|
||||
|
||||
int dummy_img(platf::img_t *img) override {
|
||||
int
|
||||
dummy_img(platf::img_t *img) override {
|
||||
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)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -681,12 +712,14 @@ struct shm_attr_t : public x11_attr_t {
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t frame_size() {
|
||||
std::uint32_t
|
||||
frame_size() {
|
||||
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) {
|
||||
BOOST_LOG(error) << "Could not initialize x11 display with the given hw device type"sv;
|
||||
return nullptr;
|
||||
|
|
@ -720,7 +753,8 @@ std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const st
|
|||
return x11_disp;
|
||||
}
|
||||
|
||||
std::vector<std::string> x11_display_names() {
|
||||
std::vector<std::string>
|
||||
x11_display_names() {
|
||||
if (load_x11() || load_xcb()) {
|
||||
BOOST_LOG(error) << "Couldn't init x11 libraries"sv;
|
||||
|
||||
|
|
@ -756,21 +790,25 @@ std::vector<std::string> x11_display_names() {
|
|||
return names;
|
||||
}
|
||||
|
||||
void freeImage(XImage *p) {
|
||||
void
|
||||
freeImage(XImage *p) {
|
||||
XDestroyImage(p);
|
||||
}
|
||||
void freeX(XFixesCursorImage *p) {
|
||||
void
|
||||
freeX(XFixesCursorImage *p) {
|
||||
x11::Free(p);
|
||||
}
|
||||
|
||||
int load_xcb() {
|
||||
int
|
||||
load_xcb() {
|
||||
// This will be called once only
|
||||
static int xcb_status = xcb::init_shm() || xcb::init();
|
||||
|
||||
return xcb_status;
|
||||
}
|
||||
|
||||
int load_x11() {
|
||||
int
|
||||
load_x11() {
|
||||
// This will be called once only
|
||||
static int x11_status =
|
||||
window_system == window_system_e::NONE ||
|
||||
|
|
@ -780,7 +818,8 @@ int load_x11() {
|
|||
}
|
||||
|
||||
namespace x11 {
|
||||
std::optional<cursor_t> cursor_t::make() {
|
||||
std::optional<cursor_t>
|
||||
cursor_t::make() {
|
||||
if (load_x11()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
@ -792,7 +831,8 @@ std::optional<cursor_t> cursor_t::make() {
|
|||
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();
|
||||
|
||||
xcursor_t xcursor = fix::GetCursorImage(display);
|
||||
|
|
@ -819,19 +859,23 @@ void cursor_t::capture(egl::cursor_t &img) {
|
|||
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);
|
||||
}
|
||||
|
||||
xdisplay_t make_display() {
|
||||
xdisplay_t
|
||||
make_display() {
|
||||
return OpenDisplay(nullptr);
|
||||
}
|
||||
|
||||
void freeDisplay(_XDisplay *xdisplay) {
|
||||
void
|
||||
freeDisplay(_XDisplay *xdisplay) {
|
||||
CloseDisplay(xdisplay);
|
||||
}
|
||||
|
||||
void freeCursorCtx(cursor_ctx_t::pointer ctx) {
|
||||
void
|
||||
freeCursorCtx(cursor_ctx_t::pointer ctx) {
|
||||
CloseDisplay((xdisplay_t::pointer) ctx);
|
||||
}
|
||||
} // namespace x11
|
||||
|
|
|
|||
|
|
@ -17,17 +17,21 @@ namespace platf::x11 {
|
|||
|
||||
#ifdef SUNSHINE_BUILD_X11
|
||||
struct cursor_ctx_raw_t;
|
||||
void freeCursorCtx(cursor_ctx_raw_t *ctx);
|
||||
void freeDisplay(_XDisplay *xdisplay);
|
||||
void
|
||||
freeCursorCtx(cursor_ctx_raw_t *ctx);
|
||||
void
|
||||
freeDisplay(_XDisplay *xdisplay);
|
||||
|
||||
using cursor_ctx_t = util::safe_ptr<cursor_ctx_raw_t, freeCursorCtx>;
|
||||
using xdisplay_t = util::safe_ptr<_XDisplay, freeDisplay>;
|
||||
|
||||
class cursor_t {
|
||||
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
|
||||
|
|
@ -35,25 +39,31 @@ public:
|
|||
* img <-- destination image
|
||||
* 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;
|
||||
};
|
||||
|
||||
xdisplay_t make_display();
|
||||
xdisplay_t
|
||||
make_display();
|
||||
#else
|
||||
// It's never something different from nullptr
|
||||
util::safe_ptr<_XDisplay, std::default_delete<_XDisplay>>;
|
||||
|
||||
class cursor_t {
|
||||
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 blend(img_t &, int, int) {}
|
||||
void
|
||||
capture(egl::cursor_t &) {}
|
||||
void
|
||||
blend(img_t &, int, int) {}
|
||||
};
|
||||
|
||||
xdisplay_t make_display() { return nullptr; }
|
||||
xdisplay_t
|
||||
make_display() { return nullptr; }
|
||||
#endif
|
||||
} // namespace platf::x11
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
@implementation AVAudio
|
||||
|
||||
+ (NSArray<AVCaptureDevice *> *)microphones {
|
||||
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) { 10, 15, 0 })]) {
|
||||
// This will generate a warning about AVCaptureDeviceDiscoverySession being
|
||||
// unavailable before macOS 10.15, but we have a guard to prevent it from
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
|
||||
struct CaptureSession {
|
||||
AVCaptureVideoDataOutput *output;
|
||||
NSCondition *captureStopped;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@
|
|||
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
||||
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
fromConnection:(AVCaptureConnection *)connection {
|
||||
|
||||
FrameCallbackBlock callback = [self.captureCallbacks objectForKey:connection];
|
||||
|
||||
if (callback != nil) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ struct av_display_t : public display_t {
|
|||
[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);
|
||||
|
||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||
|
|
@ -76,11 +77,13 @@ struct av_display_t : public display_t {
|
|||
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>();
|
||||
}
|
||||
|
||||
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) {
|
||||
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 av_img = (av_img_t *) img;
|
||||
|
||||
|
|
@ -143,16 +147,19 @@ struct av_display_t : public display_t {
|
|||
* width --> the intended capture width
|
||||
* 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 void setPixelFormat(void *display, OSType pixelFormat) {
|
||||
static void
|
||||
setPixelFormat(void *display, OSType 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) {
|
||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||
return nullptr;
|
||||
|
|
@ -186,7 +193,8 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::s
|
|||
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;
|
||||
|
||||
auto display_array = [AVVideo displayNames];
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ struct KeyCodeMap {
|
|||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +213,8 @@ const KeyCodeMap kKeyCodesMap[] = {
|
|||
};
|
||||
// clang-format on
|
||||
|
||||
int keysym(int keycode) {
|
||||
int
|
||||
keysym(int keycode) {
|
||||
KeyCodeMap key_map;
|
||||
|
||||
key_map.win_keycode = keycode;
|
||||
|
|
@ -227,7 +229,8 @@ int keysym(int 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);
|
||||
|
||||
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_Option || key == kVK_RightOption ||
|
||||
key == kVK_Control || key == kVK_RightControl) {
|
||||
|
||||
CGEventFlags mask;
|
||||
|
||||
switch (key) {
|
||||
|
|
@ -277,29 +279,35 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline CGEventType event_type_mouse(input_t &input) {
|
||||
inline CGEventType
|
||||
event_type_mouse(input_t &input) {
|
||||
auto macos_input = ((macos_input_t *) input.get());
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint64_t time_diff(uint64_t start) {
|
||||
uint64_t
|
||||
time_diff(uint64_t start) {
|
||||
uint64_t elapsed;
|
||||
Nanoseconds elapsedNano;
|
||||
|
||||
|
|
@ -371,7 +383,8 @@ uint64_t time_diff(uint64_t start) {
|
|||
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;
|
||||
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();
|
||||
}
|
||||
|
||||
void scroll(input_t &input, int high_res_distance) {
|
||||
void
|
||||
scroll(input_t &input, int high_res_distance) {
|
||||
CGEventRef upEvent = CGEventCreateScrollWheelEvent(
|
||||
NULL,
|
||||
kCGScrollEventUnitLine,
|
||||
|
|
@ -417,11 +431,13 @@ void scroll(input_t &input, int high_res_distance) {
|
|||
CFRelease(upEvent);
|
||||
}
|
||||
|
||||
void hscroll(input_t &input, int high_res_distance) {
|
||||
void
|
||||
hscroll(input_t &input, int high_res_distance) {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
input_t input() {
|
||||
input_t
|
||||
input() {
|
||||
input_t result { new macos_input_t() };
|
||||
|
||||
auto macos_input = (macos_input_t *) result.get();
|
||||
|
|
@ -455,7 +471,8 @@ input_t input() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void freeInput(void *p) {
|
||||
void
|
||||
freeInput(void *p) {
|
||||
auto *input = (macos_input_t *) p;
|
||||
|
||||
CFRelease(input->source);
|
||||
|
|
@ -465,7 +482,8 @@ void freeInput(void *p) {
|
|||
delete input;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> &supported_gamepads() {
|
||||
std::vector<std::string_view> &
|
||||
supported_gamepads() {
|
||||
static std::vector<std::string_view> gamepads { ""sv };
|
||||
|
||||
return gamepads;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ struct av_mic_t : public mic_t {
|
|||
[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();
|
||||
|
||||
uint32_t length = 0;
|
||||
|
|
@ -40,12 +41,14 @@ struct macos_audio_control_t : public audio_control_t {
|
|||
AVCaptureDevice *audio_capture_device;
|
||||
|
||||
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;
|
||||
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>();
|
||||
const char *audio_sink = "";
|
||||
|
||||
|
|
@ -74,14 +77,16 @@ public:
|
|||
return mic;
|
||||
}
|
||||
|
||||
std::optional<sink_t> sink_info() override {
|
||||
std::optional<sink_t>
|
||||
sink_info() override {
|
||||
sink_t 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>();
|
||||
}
|
||||
} // namespace platf
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@
|
|||
namespace dyn {
|
||||
typedef void (*apiproc)(void);
|
||||
|
||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict = true);
|
||||
void *handle(const std::vector<const char *> &libs);
|
||||
int
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,14 @@ namespace platf {
|
|||
#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.
|
||||
// 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 CGRequestScreenCaptureAccess(void) __attribute__((weak_import));
|
||||
extern "C" bool
|
||||
CGPreflightScreenCaptureAccess(void) __attribute__((weak_import));
|
||||
extern "C" bool
|
||||
CGRequestScreenCaptureAccess(void) __attribute__((weak_import));
|
||||
#endif
|
||||
|
||||
std::unique_ptr<deinit_t> init() {
|
||||
std::unique_ptr<deinit_t>
|
||||
init() {
|
||||
// This will generate a warning about CGPreflightScreenCaptureAccess and
|
||||
// CGRequestScreenCaptureAccess being unavailable before macOS 10.15, but
|
||||
// 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>();
|
||||
}
|
||||
|
||||
fs::path appdata() {
|
||||
fs::path
|
||||
appdata() {
|
||||
const char *homedir;
|
||||
if ((homedir = getenv("HOME")) == nullptr) {
|
||||
homedir = getpwuid(geteuid())->pw_dir;
|
||||
|
|
@ -66,7 +70,8 @@ fs::path appdata() {
|
|||
|
||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||
|
||||
ifaddr_t get_ifaddrs() {
|
||||
ifaddr_t
|
||||
get_ifaddrs() {
|
||||
ifaddrs *p { nullptr };
|
||||
|
||||
getifaddrs(&p);
|
||||
|
|
@ -74,7 +79,8 @@ ifaddr_t get_ifaddrs() {
|
|||
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];
|
||||
|
||||
auto family = ip_addr->sa_family;
|
||||
|
|
@ -91,7 +97,8 @@ std::string from_sockaddr(const sockaddr *const ip_addr) {
|
|||
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];
|
||||
|
||||
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 } };
|
||||
}
|
||||
|
||||
std::string get_mac_address(const std::string_view &address) {
|
||||
std::string
|
||||
get_mac_address(const std::string_view &address) {
|
||||
auto ifaddrs = get_ifaddrs();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!group) {
|
||||
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
|
||||
}
|
||||
|
||||
void streaming_will_start() {
|
||||
void
|
||||
streaming_will_start() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void streaming_will_stop() {
|
||||
void
|
||||
streaming_will_stop() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
bool restart_supported() {
|
||||
bool
|
||||
restart_supported() {
|
||||
// Restart not supported yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool restart() {
|
||||
bool
|
||||
restart() {
|
||||
// Restart not supported yet
|
||||
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
|
||||
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
|
||||
//
|
||||
// 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 dyn {
|
||||
void *handle(const std::vector<const char *> &libs) {
|
||||
void *
|
||||
handle(const std::vector<const char *> &libs) {
|
||||
void *handle;
|
||||
|
||||
for (auto lib : libs) {
|
||||
|
|
@ -229,7 +246,8 @@ void *handle(const std::vector<const char *> &libs) {
|
|||
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;
|
||||
for (auto &func : funcs) {
|
||||
TUPLE_2D_REF(fn, name, func);
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ extern "C" {
|
|||
|
||||
namespace platf {
|
||||
|
||||
void free_frame(AVFrame *frame) {
|
||||
void
|
||||
free_frame(AVFrame *frame) {
|
||||
av_frame_free(&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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
av_frame.reset(frame);
|
||||
|
|
@ -63,10 +66,12 @@ int nv12_zero_device::set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
|||
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');
|
||||
|
||||
this->display = display;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@ public:
|
|||
resolution_fn_t resolution_fn;
|
||||
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 set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx);
|
||||
void set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
||||
int
|
||||
convert(img_t &img);
|
||||
int
|
||||
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx);
|
||||
void
|
||||
set_colorspace(std::uint32_t colorspace, std::uint32_t color_range);
|
||||
};
|
||||
|
||||
} // namespace platf
|
||||
|
|
|
|||
|
|
@ -195,8 +195,8 @@ simple_poll_quit_fn simple_poll_quit;
|
|||
simple_poll_new_fn simple_poll_new;
|
||||
simple_poll_free_fn simple_poll_free;
|
||||
|
||||
|
||||
int init_common() {
|
||||
int
|
||||
init_common() {
|
||||
static void *handle { nullptr };
|
||||
static bool funcs_loaded = false;
|
||||
|
||||
|
|
@ -229,7 +229,8 @@ int init_common() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init_client() {
|
||||
int
|
||||
init_client() {
|
||||
if (init_common()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -270,7 +271,8 @@ int init_client() {
|
|||
namespace platf::publish {
|
||||
|
||||
template <class T>
|
||||
void free(T *p) {
|
||||
void
|
||||
free(T *p) {
|
||||
avahi::free(p);
|
||||
}
|
||||
|
||||
|
|
@ -286,9 +288,11 @@ client_t client;
|
|||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
auto fg = util::fail_guard([]() {
|
||||
|
|
@ -366,7 +371,8 @@ void create_services(avahi::Client *c) {
|
|||
fg.disable();
|
||||
}
|
||||
|
||||
void client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||
void
|
||||
client_callback(avahi::Client *c, avahi::ClientState state, void *) {
|
||||
switch (state) {
|
||||
case avahi::CLIENT_S_RUNNING:
|
||||
create_services(c);
|
||||
|
|
@ -388,7 +394,8 @@ class deinit_t : public ::platf::deinit_t {
|
|||
public:
|
||||
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 {
|
||||
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()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
// http://eretik.omegahg.com/
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
|
@ -39,11 +38,13 @@ class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
|
|||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfig: public IUnknown {
|
||||
public:
|
||||
virtual HRESULT GetMixFormat(
|
||||
virtual HRESULT
|
||||
GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **);
|
||||
|
|
@ -51,7 +52,8 @@ public:
|
|||
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
||||
PCWSTR);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *);
|
||||
|
|
@ -66,25 +68,30 @@ public:
|
|||
PCWSTR,
|
||||
PINT64);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDefaultEndpoint(
|
||||
PCWSTR wszDeviceId,
|
||||
ERole eRole);
|
||||
|
||||
|
|
@ -110,16 +117,19 @@ class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") CPolicyConfigVistaCl
|
|||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfigVista: public IUnknown {
|
||||
public:
|
||||
virtual HRESULT GetMixFormat(
|
||||
virtual HRESULT
|
||||
GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *);
|
||||
|
|
@ -134,25 +144,30 @@ public:
|
|||
PCWSTR,
|
||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDefaultEndpoint(
|
||||
PCWSTR wszDeviceId,
|
||||
ERole eRole);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,12 +37,14 @@ namespace platf::audio {
|
|||
constexpr auto SAMPLE_RATE = 48000;
|
||||
|
||||
template <class T>
|
||||
void Release(T *p) {
|
||||
void
|
||||
Release(T *p) {
|
||||
p->Release();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void co_task_free(T *p) {
|
||||
void
|
||||
co_task_free(T *p) {
|
||||
CoTaskMemFree((LPVOID) p);
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +140,8 @@ static format_t surround_51_side_speakers {
|
|||
SPEAKER_SIDE_RIGHT,
|
||||
};
|
||||
|
||||
WAVEFORMATEXTENSIBLE create_wave_format(const format_t &format) {
|
||||
WAVEFORMATEXTENSIBLE
|
||||
create_wave_format(const format_t &format) {
|
||||
WAVEFORMATEXTENSIBLE wave_format;
|
||||
|
||||
wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
|
|
@ -156,7 +159,8 @@ WAVEFORMATEXTENSIBLE create_wave_format(const format_t &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->wBitsPerSample = 16;
|
||||
|
||||
|
|
@ -184,7 +188,8 @@ int set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
|
|||
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;
|
||||
auto status = device->Activate(
|
||||
IID_IAudioClient,
|
||||
|
|
@ -216,11 +221,13 @@ audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
|||
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";
|
||||
}
|
||||
|
||||
bool validate_device(device_t &device) {
|
||||
bool
|
||||
validate_device(device_t &device) {
|
||||
bool valid = false;
|
||||
|
||||
// Check for any valid format
|
||||
|
|
@ -237,7 +244,8 @@ bool validate_device(device_t &device) {
|
|||
return valid;
|
||||
}
|
||||
|
||||
device_t default_device(device_enum_t &device_enum) {
|
||||
device_t
|
||||
default_device(device_enum_t &device_enum) {
|
||||
device_t device;
|
||||
HRESULT status;
|
||||
status = device_enum->GetDefaultAudioEndpoint(
|
||||
|
|
@ -245,7 +253,6 @@ device_t default_device(device_enum_t &device_enum) {
|
|||
eConsole,
|
||||
&device);
|
||||
|
||||
|
||||
if (FAILED(status)) {
|
||||
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 {
|
||||
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();
|
||||
|
||||
// Refill the sample buffer if needed
|
||||
|
|
@ -278,8 +286,8 @@ public:
|
|||
return capture_e::ok;
|
||||
}
|
||||
|
||||
|
||||
int init(std::uint32_t sample_rate, std::uint32_t frame_size, std::uint32_t channels_out) {
|
||||
int
|
||||
init(std::uint32_t sample_rate, std::uint32_t frame_size, std::uint32_t channels_out) {
|
||||
audio_event.reset(CreateEventA(nullptr, FALSE, FALSE, nullptr));
|
||||
if (!audio_event) {
|
||||
BOOST_LOG(error) << "Couldn't create Event handle"sv;
|
||||
|
|
@ -375,7 +383,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
capture_e _fill_buffer() {
|
||||
capture_e
|
||||
_fill_buffer() {
|
||||
HRESULT status;
|
||||
|
||||
// Total number of samples
|
||||
|
|
@ -465,7 +474,8 @@ public:
|
|||
|
||||
class audio_control_t: public ::platf::audio_control_t {
|
||||
public:
|
||||
std::optional<sink_t> sink_info() override {
|
||||
std::optional<sink_t>
|
||||
sink_info() override {
|
||||
auto virtual_adapter_name = L"Steam Streaming Speakers"sv;
|
||||
|
||||
sink_t sink;
|
||||
|
|
@ -553,7 +563,8 @@ public:
|
|||
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>();
|
||||
|
||||
if (mic->init(sample_rate, frame_size, channels)) {
|
||||
|
|
@ -571,7 +582,8 @@ public:
|
|||
* virtual-(format name)
|
||||
* 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() };
|
||||
|
||||
format_t::type_e type = format_t::none;
|
||||
|
|
@ -628,7 +640,8 @@ public:
|
|||
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);
|
||||
if (!wstring_device_id) {
|
||||
return -1;
|
||||
|
|
@ -647,7 +660,8 @@ public:
|
|||
return failure;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
auto status = CoCreateInstance(
|
||||
CLSID_CPolicyConfigClient,
|
||||
nullptr,
|
||||
|
|
@ -674,10 +688,12 @@ namespace platf {
|
|||
|
||||
// It's not big enough to justify it's own source file :/
|
||||
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>();
|
||||
|
||||
if (control->init()) {
|
||||
|
|
@ -687,7 +703,8 @@ std::unique_ptr<audio_control_t> audio_control() {
|
|||
return control;
|
||||
}
|
||||
|
||||
std::unique_ptr<deinit_t> init() {
|
||||
std::unique_ptr<deinit_t>
|
||||
init() {
|
||||
if (dxgi::init()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ extern const char *format_str[];
|
|||
auto constexpr D3D11_CREATE_DEVICE_FLAGS = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
||||
|
||||
template <class T>
|
||||
void Release(T *dxgi) {
|
||||
void
|
||||
Release(T *dxgi) {
|
||||
dxgi->Release();
|
||||
}
|
||||
|
||||
|
|
@ -78,15 +79,18 @@ struct cursor_t {
|
|||
|
||||
class gpu_cursor_t {
|
||||
public:
|
||||
gpu_cursor_t() : cursor_view { 0, 0, 0, 0, 0.0f, 1.0f } {};
|
||||
void set_pos(LONG rel_x, LONG rel_y, bool visible) {
|
||||
gpu_cursor_t():
|
||||
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.TopLeftY = rel_y;
|
||||
|
||||
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.Height = height;
|
||||
|
||||
|
|
@ -107,17 +111,22 @@ public:
|
|||
bool has_frame {};
|
||||
bool use_dwmflush {};
|
||||
|
||||
capture_e next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
||||
capture_e reset(dup_t::pointer dup_p = dup_t::pointer());
|
||||
capture_e release_frame();
|
||||
capture_e
|
||||
next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
||||
capture_e
|
||||
reset(dup_t::pointer dup_p = dup_t::pointer());
|
||||
capture_e
|
||||
release_frame();
|
||||
|
||||
~duplication_t();
|
||||
};
|
||||
|
||||
class display_base_t: public display_t {
|
||||
public:
|
||||
int 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;
|
||||
int
|
||||
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;
|
||||
|
||||
|
|
@ -142,34 +151,50 @@ public:
|
|||
|
||||
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||
|
||||
virtual bool is_hdr() override;
|
||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
virtual bool
|
||||
is_hdr() override;
|
||||
virtual bool
|
||||
get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
|
||||
protected:
|
||||
int get_pixel_pitch() {
|
||||
int
|
||||
get_pixel_pitch() {
|
||||
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
||||
}
|
||||
|
||||
const char *dxgi_format_to_string(DXGI_FORMAT format);
|
||||
const char *colorspace_to_string(DXGI_COLOR_SPACE_TYPE type);
|
||||
const char *
|
||||
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 int 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;
|
||||
virtual capture_e
|
||||
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||
virtual int
|
||||
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 {
|
||||
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;
|
||||
int dummy_img(img_t *img) 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;
|
||||
std::shared_ptr<img_t>
|
||||
alloc_img() override;
|
||||
int
|
||||
dummy_img(img_t *img) 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;
|
||||
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> {
|
||||
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;
|
||||
int dummy_img(img_t *img_base) 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;
|
||||
std::shared_ptr<img_t>
|
||||
alloc_img() override;
|
||||
int
|
||||
dummy_img(img_t *img_base) 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ using namespace std::literals;
|
|||
namespace platf::dxgi {
|
||||
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();
|
||||
if (capture_status != capture_e::ok) {
|
||||
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();
|
||||
|
||||
dup.reset(dup_p);
|
||||
|
|
@ -61,7 +63,8 @@ capture_e duplication_t::reset(dup_t::pointer dup_p) {
|
|||
return capture_status;
|
||||
}
|
||||
|
||||
capture_e duplication_t::release_frame() {
|
||||
capture_e
|
||||
duplication_t::release_frame() {
|
||||
if (!has_frame) {
|
||||
return capture_e::ok;
|
||||
}
|
||||
|
|
@ -88,7 +91,8 @@ duplication_t::~duplication_t() {
|
|||
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();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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.
|
||||
WCHAR sunshine_path[MAX_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
|
||||
// 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.
|
||||
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.
|
||||
static bool set_gpu_preference = false;
|
||||
if (set_gpu_preference) {
|
||||
|
|
@ -235,7 +241,8 @@ bool probe_for_gpu_preference(const std::string &display_name) {
|
|||
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_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
|
|
@ -283,7 +290,8 @@ bool test_dxgi_duplication(adapter_t &adapter, output_t &output) {
|
|||
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::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;
|
||||
}
|
||||
|
||||
bool display_base_t::is_hdr() {
|
||||
bool
|
||||
display_base_t::is_hdr() {
|
||||
dxgi::output6_t 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;
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
std::memset(&metadata, 0, sizeof(metadata));
|
||||
|
|
@ -781,11 +791,13 @@ const char *format_str[] = {
|
|||
"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];
|
||||
}
|
||||
|
||||
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[] = {
|
||||
"DXGI_COLOR_SPACE_RGB_FULL_G22_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 {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::string> display_names(mem_type_e) {
|
||||
std::vector<std::string>
|
||||
display_names(mem_type_e) {
|
||||
std::vector<std::string> display_names;
|
||||
|
||||
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 width = cursor.shape_info.Width;
|
||||
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_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
|
||||
auto alpha = ((std::uint8_t *) &cursor_pixel)[3];
|
||||
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 width = cursor.shape_info.Width;
|
||||
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) {
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
||||
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;
|
||||
|
||||
HRESULT status;
|
||||
|
|
@ -301,7 +307,8 @@ capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::millise
|
|||
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>();
|
||||
|
||||
// Initialize fields that are format-independent
|
||||
|
|
@ -311,7 +318,8 @@ std::shared_ptr<platf::img_t> display_ram_t::alloc_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 (!dummy && capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -348,16 +357,19 @@ int display_ram_t::dummy_img(platf::img_t *img) {
|
|||
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 };
|
||||
}
|
||||
|
||||
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
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ extern "C" {
|
|||
#include "src/main.h"
|
||||
#include "src/video.h"
|
||||
|
||||
|
||||
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/directx"
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
}
|
||||
|
||||
static void free_frame(AVFrame *frame) {
|
||||
static void
|
||||
free_frame(AVFrame *frame) {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,8 @@ using frame_t = util::safe_ptr<AVFrame, free_frame>;
|
|||
namespace platf::dxgi {
|
||||
|
||||
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");
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
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 {};
|
||||
auto &rt = bdesc.RenderTarget[0];
|
||||
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 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;
|
||||
}
|
||||
|
||||
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 white = 0xFFFFFFFF;
|
||||
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;
|
||||
}
|
||||
|
||||
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 compiled_p;
|
||||
|
||||
|
|
@ -292,17 +297,20 @@ blob_t compile_shader(LPCSTR file, LPCSTR entrypoint, LPCSTR shader_model) {
|
|||
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");
|
||||
}
|
||||
|
||||
blob_t compile_vertex_shader(LPCSTR file) {
|
||||
blob_t
|
||||
compile_vertex_shader(LPCSTR file) {
|
||||
return compile_shader(file, "main_vs", "vs_5_0");
|
||||
}
|
||||
|
||||
class hwdevice_t: public platf::hwdevice_t {
|
||||
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_ctx = img_ctx_map[img.id];
|
||||
|
||||
|
|
@ -341,7 +349,8 @@ public:
|
|||
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) {
|
||||
case 5: // SWS_CS_SMPTE170M
|
||||
color_p = &::video::colors[0];
|
||||
|
|
@ -373,7 +382,8 @@ public:
|
|||
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
|
||||
if (frames->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
|
||||
auto d3d11_frames = (AVD3D11VAFramesContext *) frames->hwctx;
|
||||
|
|
@ -387,7 +397,8 @@ public:
|
|||
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
|
||||
if (hw_device_type == AV_HWDEVICE_TYPE_QSV) {
|
||||
multithread_t mt;
|
||||
|
|
@ -404,7 +415,8 @@ public:
|
|||
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->frame = frame;
|
||||
|
||||
|
|
@ -498,10 +510,10 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init(
|
||||
int
|
||||
init(
|
||||
std::shared_ptr<platf::display_t> display, adapter_t::pointer adapter_p,
|
||||
pix_fmt_e pix_fmt) {
|
||||
|
||||
D3D_FEATURE_LEVEL featureLevels[] {
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
|
|
@ -642,7 +654,8 @@ private:
|
|||
shader_res_t encoder_input_res;
|
||||
keyed_mutex_t encoder_mutex;
|
||||
|
||||
void reset() {
|
||||
void
|
||||
reset() {
|
||||
capture_texture_p = nullptr;
|
||||
encoder_texture.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 (img_ctx.encoder_texture && img.capture_texture.get() == img_ctx.capture_texture_p) {
|
||||
return 0;
|
||||
|
|
@ -733,7 +747,8 @@ public:
|
|||
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
|
||||
if (cursor_img.size() == 0) {
|
||||
cursor.input_res.reset();
|
||||
|
|
@ -777,7 +792,8 @@ bool set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::bu
|
|||
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;
|
||||
|
||||
HRESULT status;
|
||||
|
|
@ -965,7 +981,8 @@ capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::millisec
|
|||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1034,7 +1051,8 @@ int display_vram_t::init(const ::video::config_t &config, const std::string &dis
|
|||
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>();
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
// 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
|
||||
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);
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
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 {
|
||||
// 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.
|
||||
|
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
BOOST_LOG(info) << "Compiling shaders..."sv;
|
||||
scene_vs_hlsl = compile_vertex_shader(SUNSHINE_SHADERS_DIR "/SceneVS.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 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) {
|
||||
return Xbox360Wired;
|
||||
}
|
||||
|
|
@ -30,14 +31,16 @@ static VIGEM_TARGET_TYPE map(const std::string_view &gp) {
|
|||
return DualShock4Wired;
|
||||
}
|
||||
|
||||
void CALLBACK x360_notify(
|
||||
void CALLBACK
|
||||
x360_notify(
|
||||
client_t::pointer client,
|
||||
target_t::pointer target,
|
||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||
std::uint8_t /* led_number */,
|
||||
void *userdata);
|
||||
|
||||
void CALLBACK ds4_notify(
|
||||
void CALLBACK
|
||||
ds4_notify(
|
||||
client_t::pointer client,
|
||||
target_t::pointer target,
|
||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||
|
|
@ -46,7 +49,8 @@ void CALLBACK ds4_notify(
|
|||
|
||||
class vigem_t {
|
||||
public:
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
VIGEM_ERROR status;
|
||||
|
||||
client.reset(vigem_alloc());
|
||||
|
|
@ -63,7 +67,8 @@ public:
|
|||
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];
|
||||
assert(!gp);
|
||||
|
||||
|
|
@ -97,7 +102,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void free_target(int nr) {
|
||||
void
|
||||
free_target(int nr) {
|
||||
auto &[_, gp] = gamepads[nr];
|
||||
|
||||
if (gp && vigem_target_is_attached(gp.get())) {
|
||||
|
|
@ -110,7 +116,8 @@ public:
|
|||
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) {
|
||||
auto &[rumble_queue, gp] = gamepads[x];
|
||||
|
||||
|
|
@ -142,13 +149,13 @@ public:
|
|||
client_t client;
|
||||
};
|
||||
|
||||
void CALLBACK x360_notify(
|
||||
void CALLBACK
|
||||
x360_notify(
|
||||
client_t::pointer client,
|
||||
target_t::pointer target,
|
||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||
std::uint8_t /* led_number */,
|
||||
void *userdata) {
|
||||
|
||||
BOOST_LOG(debug)
|
||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||
<< "smallMotor: "sv << (int) smallMotor;
|
||||
|
|
@ -156,13 +163,13 @@ void CALLBACK x360_notify(
|
|||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, smallMotor, largeMotor);
|
||||
}
|
||||
|
||||
void CALLBACK ds4_notify(
|
||||
void CALLBACK
|
||||
ds4_notify(
|
||||
client_t::pointer client,
|
||||
target_t::pointer target,
|
||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||
DS4_LIGHTBAR_COLOR /* led_color */,
|
||||
void *userdata) {
|
||||
|
||||
BOOST_LOG(debug)
|
||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||
<< "smallMotor: "sv << (int) smallMotor;
|
||||
|
|
@ -180,7 +187,8 @@ struct input_raw_t {
|
|||
HKL active_layout;
|
||||
};
|
||||
|
||||
input_t input() {
|
||||
input_t
|
||||
input() {
|
||||
input_t result { new input_raw_t {} };
|
||||
auto &raw = *(input_raw_t *) result.get();
|
||||
|
||||
|
|
@ -208,7 +216,8 @@ input_t input() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void send_input(INPUT &i) {
|
||||
void
|
||||
send_input(INPUT &i) {
|
||||
retry:
|
||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||
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 {};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||
void
|
||||
move_mouse(input_t &input, int deltaX, int deltaY) {
|
||||
INPUT i {};
|
||||
|
||||
i.type = INPUT_MOUSE;
|
||||
|
|
@ -256,7 +267,8 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||
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;
|
||||
|
||||
INPUT i {};
|
||||
|
|
@ -299,7 +311,8 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||
send_input(i);
|
||||
}
|
||||
|
||||
void scroll(input_t &input, int distance) {
|
||||
void
|
||||
scroll(input_t &input, int distance) {
|
||||
INPUT i {};
|
||||
|
||||
i.type = INPUT_MOUSE;
|
||||
|
|
@ -311,7 +324,8 @@ void scroll(input_t &input, int distance) {
|
|||
send_input(i);
|
||||
}
|
||||
|
||||
void hscroll(input_t &input, int distance) {
|
||||
void
|
||||
hscroll(input_t &input, int distance) {
|
||||
INPUT i {};
|
||||
|
||||
i.type = INPUT_MOUSE;
|
||||
|
|
@ -323,7 +337,8 @@ void hscroll(input_t &input, int distance) {
|
|||
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();
|
||||
|
||||
INPUT i {};
|
||||
|
|
@ -372,7 +387,8 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||
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
|
||||
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();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void free_gamepad(input_t &input, int nr) {
|
||||
void
|
||||
free_gamepad(input_t &input, int nr) {
|
||||
auto raw = (input_raw_t *) input.get();
|
||||
|
||||
if (!raw->vigem) {
|
||||
|
|
@ -420,13 +438,15 @@ void free_gamepad(input_t &input, int 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;
|
||||
|
||||
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;
|
||||
if (flags & DPAD_UP) {
|
||||
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;
|
||||
}
|
||||
|
||||
static DS4_BUTTONS ds4_buttons(const gamepad_state_t &gamepad_state) {
|
||||
static DS4_BUTTONS
|
||||
ds4_buttons(const gamepad_state_t &gamepad_state) {
|
||||
int buttons {};
|
||||
|
||||
auto flags = gamepad_state.buttonFlags;
|
||||
|
|
@ -485,7 +506,8 @@ static DS4_BUTTONS ds4_buttons(const gamepad_state_t &gamepad_state) {
|
|||
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 {};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
auto vigem = ((input_raw_t *) input.get())->vigem;
|
||||
|
||||
// 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;
|
||||
|
||||
delete input;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> &supported_gamepads() {
|
||||
std::vector<std::string_view> &
|
||||
supported_gamepads() {
|
||||
// ds4 == ps4
|
||||
static std::vector<std::string_view> gps {
|
||||
"x360"sv, "ds4"sv, "ps4"sv
|
||||
|
|
|
|||
|
|
@ -63,13 +63,15 @@ decltype(WlanFreeMemory) *fn_WlanFreeMemory = nullptr;
|
|||
decltype(WlanEnumInterfaces) *fn_WlanEnumInterfaces = nullptr;
|
||||
decltype(WlanSetInterface) *fn_WlanSetInterface = nullptr;
|
||||
|
||||
std::filesystem::path appdata() {
|
||||
std::filesystem::path
|
||||
appdata() {
|
||||
WCHAR sunshine_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, sunshine_path, _countof(sunshine_path));
|
||||
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];
|
||||
|
||||
auto family = socket_address->sa_family;
|
||||
|
|
@ -84,7 +86,8 @@ std::string from_sockaddr(const sockaddr *const socket_address) {
|
|||
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];
|
||||
|
||||
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 } };
|
||||
}
|
||||
|
||||
adapteraddrs_t get_adapteraddrs() {
|
||||
adapteraddrs_t
|
||||
get_adapteraddrs() {
|
||||
adapteraddrs_t info { nullptr };
|
||||
ULONG size = 0;
|
||||
|
||||
|
|
@ -113,7 +117,8 @@ adapteraddrs_t get_adapteraddrs() {
|
|||
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();
|
||||
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) {
|
||||
|
|
@ -134,7 +139,8 @@ std::string get_mac_address(const std::string_view &address) {
|
|||
return "00:00:00:00:00:00"s;
|
||||
}
|
||||
|
||||
HDESK syncThreadDesktop() {
|
||||
HDESK
|
||||
syncThreadDesktop() {
|
||||
auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL);
|
||||
if (!hDesk) {
|
||||
auto err = GetLastError();
|
||||
|
|
@ -153,7 +159,8 @@ HDESK syncThreadDesktop() {
|
|||
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];
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
HANDLE duplicate_shell_token() {
|
||||
HANDLE
|
||||
duplicate_shell_token() {
|
||||
// Get the shell window (will usually be owned by explorer.exe)
|
||||
HWND shell_window = GetShellWindow();
|
||||
if (!shell_window) {
|
||||
|
|
@ -229,7 +239,8 @@ HANDLE duplicate_shell_token() {
|
|||
return new_token;
|
||||
}
|
||||
|
||||
PTOKEN_USER get_token_user(HANDLE token) {
|
||||
PTOKEN_USER
|
||||
get_token_user(HANDLE token) {
|
||||
DWORD return_length;
|
||||
if (GetTokenInformation(token, TokenUser, NULL, 0, &return_length) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
auto winerr = GetLastError();
|
||||
|
|
@ -252,11 +263,13 @@ PTOKEN_USER get_token_user(HANDLE token) {
|
|||
return user;
|
||||
}
|
||||
|
||||
void free_token_user(PTOKEN_USER user) {
|
||||
void
|
||||
free_token_user(PTOKEN_USER 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;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) {
|
||||
auto winerr = GetLastError();
|
||||
|
|
@ -284,7 +297,8 @@ bool is_token_same_user_as_process(HANDLE other_token) {
|
|||
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
|
||||
PVOID env_block;
|
||||
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
|
||||
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));
|
||||
offset += wstr.length();
|
||||
}
|
||||
|
||||
std::wstring create_environment_block(bp::environment &env) {
|
||||
std::wstring
|
||||
create_environment_block(bp::environment &env) {
|
||||
int size = 0;
|
||||
for (const auto &entry : env) {
|
||||
auto name = entry.get_name();
|
||||
|
|
@ -355,7 +371,8 @@ std::wstring create_environment_block(bp::environment &env) {
|
|||
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;
|
||||
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
|
||||
|
||||
|
|
@ -372,12 +389,14 @@ LPPROC_THREAD_ATTRIBUTE_LIST allocate_proc_thread_attr_list(DWORD attribute_coun
|
|||
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);
|
||||
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();
|
||||
if (!shell_token) {
|
||||
// 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;
|
||||
|
||||
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;
|
||||
std::call_once(load_wlanapi_once_flag, []() {
|
||||
// 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
|
||||
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
|
||||
return (GetConsoleWindow() == NULL);
|
||||
}
|
||||
|
||||
bool restart() {
|
||||
bool
|
||||
restart() {
|
||||
// Raise SIGINT to trigger the graceful exit logic. The service will
|
||||
// restart us in a few seconds.
|
||||
std::raise(SIGINT);
|
||||
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 = {};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {};
|
||||
|
||||
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
|
||||
// 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;
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
qos_t(QOS_FLOWID flow_id) : flow_id(flow_id) {}
|
||||
qos_t(QOS_FLOWID flow_id):
|
||||
flow_id(flow_id) {}
|
||||
|
||||
virtual ~qos_t() {
|
||||
if (!fn_QOSRemoveSocketFromFlow(qos_handle, (SOCKET) NULL, flow_id, 0)) {
|
||||
|
|
@ -797,7 +825,8 @@ private:
|
|||
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_IN6 saddr_v6;
|
||||
PSOCKADDR dest_addr;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
#include <winnt.h>
|
||||
|
||||
namespace platf {
|
||||
void print_status(const std::string_view &prefix, HRESULT status);
|
||||
HDESK syncThreadDesktop();
|
||||
void
|
||||
print_status(const std::string_view &prefix, HRESULT status);
|
||||
HDESK
|
||||
syncThreadDesktop();
|
||||
} // namespace platf
|
||||
|
||||
#endif
|
||||
|
|
@ -59,7 +59,8 @@ typedef struct _DNS_SERVICE_INSTANCE {
|
|||
} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE;
|
||||
#endif
|
||||
|
||||
typedef VOID WINAPI DNS_SERVICE_REGISTER_COMPLETE(
|
||||
typedef VOID WINAPI
|
||||
DNS_SERVICE_REGISTER_COMPLETE(
|
||||
_In_ DWORD Status,
|
||||
_In_ PVOID pQueryContext,
|
||||
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||
|
|
@ -88,7 +89,8 @@ _FN(_DnsServiceRegister, DWORD, (_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest, _I
|
|||
} /* extern "C" */
|
||||
|
||||
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;
|
||||
|
||||
if (status) {
|
||||
|
|
@ -98,7 +100,8 @@ VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE
|
|||
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>();
|
||||
|
||||
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 {
|
||||
public:
|
||||
mdns_registration_t() : existing_instance(nullptr) {
|
||||
mdns_registration_t():
|
||||
existing_instance(nullptr) {
|
||||
if (service(true, existing_instance)) {
|
||||
BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv;
|
||||
return;
|
||||
|
|
@ -178,7 +182,8 @@ private:
|
|||
PDNS_SERVICE_INSTANCE existing_instance;
|
||||
};
|
||||
|
||||
int load_funcs(HMODULE handle) {
|
||||
int
|
||||
load_funcs(HMODULE handle) {
|
||||
auto fg = util::fail_guard([handle]() {
|
||||
FreeLibrary(handle);
|
||||
});
|
||||
|
|
@ -196,7 +201,8 @@ int load_funcs(HMODULE handle) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<::platf::deinit_t> start() {
|
||||
std::unique_ptr<::platf::deinit_t>
|
||||
start() {
|
||||
HMODULE handle = LoadLibrary("dnsapi.dll");
|
||||
|
||||
if (!handle || load_funcs(handle)) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ namespace pt = boost::property_tree;
|
|||
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -50,7 +51,8 @@ void process_end(bp::child &proc, bp::group &proc_handle) {
|
|||
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
|
||||
#ifdef _WIN32
|
||||
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();
|
||||
}
|
||||
|
||||
int proc_t::execute(int app_id) {
|
||||
int
|
||||
proc_t::execute(int app_id) {
|
||||
// Ensure starting from a clean slate
|
||||
terminate();
|
||||
|
||||
|
|
@ -179,7 +182,8 @@ int proc_t::execute(int app_id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int proc_t::running() {
|
||||
int
|
||||
proc_t::running() {
|
||||
if (placebo || _process.running()) {
|
||||
return _app_id;
|
||||
}
|
||||
|
|
@ -192,7 +196,8 @@ int proc_t::running() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void proc_t::terminate() {
|
||||
void
|
||||
proc_t::terminate() {
|
||||
std::error_code ec;
|
||||
|
||||
// Ensure child process is terminated
|
||||
|
|
@ -230,10 +235,12 @@ void proc_t::terminate() {
|
|||
_pipe.reset();
|
||||
}
|
||||
|
||||
const std::vector<ctx_t> &proc_t::get_apps() const {
|
||||
const std::vector<ctx_t> &
|
||||
proc_t::get_apps() const {
|
||||
return _apps;
|
||||
}
|
||||
std::vector<ctx_t> &proc_t::get_apps() {
|
||||
std::vector<ctx_t> &
|
||||
proc_t::get_apps() {
|
||||
return _apps;
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +248,8 @@ std::vector<ctx_t> &proc_t::get_apps() {
|
|||
// Returns image from assets directory if found there.
|
||||
// Returns default image if image configuration is not set.
|
||||
// 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) {
|
||||
return app.id == std::to_string(app_id);
|
||||
});
|
||||
|
|
@ -254,7 +262,8 @@ proc_t::~proc_t() {
|
|||
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;
|
||||
|
||||
--begin;
|
||||
|
|
@ -275,7 +284,8 @@ std::string_view::iterator find_match(std::string_view::iterator begin, std::str
|
|||
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 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();
|
||||
}
|
||||
|
||||
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()) {
|
||||
return DEFAULT_APP_IMAGE_PATH;
|
||||
}
|
||||
|
|
@ -366,7 +377,8 @@ std::string validate_app_image_path(std::string 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() };
|
||||
if (!ctx) {
|
||||
return std::nullopt;
|
||||
|
|
@ -401,13 +413,15 @@ std::optional<std::string> calculate_sha256(const std::string &filename) {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
uint32_t calculate_crc32(const std::string &input) {
|
||||
uint32_t
|
||||
calculate_crc32(const std::string &input) {
|
||||
boost::crc_32_type result;
|
||||
result.process_bytes(input.data(), input.length());
|
||||
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
|
||||
std::vector<std::string> to_hash;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
try {
|
||||
|
|
@ -550,7 +565,8 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
void refresh(const std::string &file_name) {
|
||||
void
|
||||
refresh(const std::string &file_name) {
|
||||
auto proc_opt = proc::parse(file_name);
|
||||
|
||||
if (proc_opt) {
|
||||
|
|
|
|||
|
|
@ -56,24 +56,31 @@ public:
|
|||
|
||||
proc_t(
|
||||
boost::process::environment &&env,
|
||||
std::vector<ctx_t> &&apps) : _app_id(0),
|
||||
std::vector<ctx_t> &&apps):
|
||||
_app_id(0),
|
||||
_env(std::move(env)),
|
||||
_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
|
||||
*/
|
||||
int running();
|
||||
int
|
||||
running();
|
||||
|
||||
~proc_t();
|
||||
|
||||
const std::vector<ctx_t> &get_apps() const;
|
||||
std::vector<ctx_t> &get_apps();
|
||||
std::string get_app_image(int app_id);
|
||||
const std::vector<ctx_t> &
|
||||
get_apps() const;
|
||||
std::vector<ctx_t> &
|
||||
get_apps();
|
||||
std::string
|
||||
get_app_image(int app_id);
|
||||
|
||||
void terminate();
|
||||
void
|
||||
terminate();
|
||||
|
||||
private:
|
||||
int _app_id;
|
||||
|
|
@ -97,11 +104,15 @@ private:
|
|||
* 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
|
||||
*/
|
||||
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);
|
||||
void refresh(const std::string &file_name);
|
||||
std::optional<proc::proc_t> parse(const std::string &file_name);
|
||||
std::string
|
||||
validate_app_image_path(std::string app_image_path);
|
||||
void
|
||||
refresh(const std::string &file_name);
|
||||
std::optional<proc::proc_t>
|
||||
parse(const std::string &file_name);
|
||||
|
||||
extern proc_t proc;
|
||||
} // namespace proc
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ public:
|
|||
typedef T iterator;
|
||||
typedef std::ptrdiff_t diff_t;
|
||||
|
||||
iterator operator+=(diff_t step) {
|
||||
iterator
|
||||
operator+=(diff_t step) {
|
||||
while (step-- > 0) {
|
||||
++_this();
|
||||
}
|
||||
|
|
@ -24,7 +25,8 @@ public:
|
|||
return _this();
|
||||
}
|
||||
|
||||
iterator operator-=(diff_t step) {
|
||||
iterator
|
||||
operator-=(diff_t step) {
|
||||
while (step-- > 0) {
|
||||
--_this();
|
||||
}
|
||||
|
|
@ -32,19 +34,22 @@ public:
|
|||
return _this();
|
||||
}
|
||||
|
||||
iterator operator+(diff_t step) {
|
||||
iterator
|
||||
operator+(diff_t step) {
|
||||
iterator new_ = _this();
|
||||
|
||||
return new_ += step;
|
||||
}
|
||||
|
||||
iterator operator-(diff_t step) {
|
||||
iterator
|
||||
operator-(diff_t step) {
|
||||
iterator new_ = _this();
|
||||
|
||||
return new_ -= step;
|
||||
}
|
||||
|
||||
diff_t operator-(iterator first) {
|
||||
diff_t
|
||||
operator-(iterator first) {
|
||||
diff_t step = 0;
|
||||
while (first != _this()) {
|
||||
++step;
|
||||
|
|
@ -54,16 +59,19 @@ public:
|
|||
return step;
|
||||
}
|
||||
|
||||
iterator operator++() {
|
||||
iterator
|
||||
operator++() {
|
||||
_this().inc();
|
||||
return _this();
|
||||
}
|
||||
iterator operator--() {
|
||||
iterator
|
||||
operator--() {
|
||||
_this().dec();
|
||||
return _this();
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator
|
||||
operator++(int) {
|
||||
iterator new_ = _this();
|
||||
|
||||
++_this();
|
||||
|
|
@ -71,7 +79,8 @@ public:
|
|||
return new_;
|
||||
}
|
||||
|
||||
iterator operator--(int) {
|
||||
iterator
|
||||
operator--(int) {
|
||||
iterator new_ = _this();
|
||||
|
||||
--_this();
|
||||
|
|
@ -79,34 +88,46 @@ public:
|
|||
return new_;
|
||||
}
|
||||
|
||||
reference operator*() { return *_this().get(); }
|
||||
const reference operator*() const { return *_this().get(); }
|
||||
reference
|
||||
operator*() { return *_this().get(); }
|
||||
const reference
|
||||
operator*() const { return *_this().get(); }
|
||||
|
||||
pointer operator->() { return &*_this(); }
|
||||
const pointer operator->() const { return &*_this(); }
|
||||
pointer
|
||||
operator->() { return &*_this(); }
|
||||
const pointer
|
||||
operator->() const { return &*_this(); }
|
||||
|
||||
bool operator!=(const iterator &other) const {
|
||||
bool
|
||||
operator!=(const iterator &other) const {
|
||||
return !(_this() == other);
|
||||
}
|
||||
|
||||
bool operator<(const iterator &other) const {
|
||||
bool
|
||||
operator<(const iterator &other) const {
|
||||
return !(_this() >= other);
|
||||
}
|
||||
|
||||
bool operator>=(const iterator &other) const {
|
||||
bool
|
||||
operator>=(const iterator &other) const {
|
||||
return _this() == other || _this() > other;
|
||||
}
|
||||
|
||||
bool operator<=(const iterator &other) const {
|
||||
bool
|
||||
operator<=(const iterator &other) const {
|
||||
return _this() == other || _this() < other;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const { return _this().eq(other); };
|
||||
bool operator>(const iterator &other) const { return _this().gt(other); }
|
||||
bool
|
||||
operator==(const iterator &other) const { return _this().eq(other); };
|
||||
bool
|
||||
operator>(const iterator &other) const { return _this().gt(other); }
|
||||
|
||||
private:
|
||||
iterator &_this() { return *static_cast<iterator *>(this); }
|
||||
const iterator &_this() const { return *static_cast<const iterator *>(this); }
|
||||
iterator &
|
||||
_this() { return *static_cast<iterator *>(this); }
|
||||
const iterator &
|
||||
_this() const { return *static_cast<const iterator *>(this); }
|
||||
};
|
||||
|
||||
template <class V, class It>
|
||||
|
|
@ -115,9 +136,11 @@ public:
|
|||
using iterator = It;
|
||||
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;
|
||||
|
||||
if (_pos == _end) {
|
||||
|
|
@ -125,7 +148,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void dec() {
|
||||
void
|
||||
dec() {
|
||||
if (_pos == _begin) {
|
||||
_pos = _end;
|
||||
}
|
||||
|
|
@ -133,11 +157,13 @@ public:
|
|||
--_pos;
|
||||
}
|
||||
|
||||
bool eq(const round_robin_t &other) const {
|
||||
bool
|
||||
eq(const round_robin_t &other) const {
|
||||
return *_pos == *other._pos;
|
||||
}
|
||||
|
||||
pointer get() const {
|
||||
pointer
|
||||
get() const {
|
||||
return &*_pos;
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +175,8 @@ private:
|
|||
};
|
||||
|
||||
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);
|
||||
}
|
||||
} // namespace round_robin_util
|
||||
|
|
|
|||
102
src/rtsp.cpp
102
src/rtsp.cpp
|
|
@ -30,7 +30,8 @@ using asio::ip::udp;
|
|||
using namespace std::literals;
|
||||
|
||||
namespace rtsp_stream {
|
||||
void free_msg(PRTSP_MESSAGE msg) {
|
||||
void
|
||||
free_msg(PRTSP_MESSAGE msg) {
|
||||
freeMessage(msg);
|
||||
|
||||
delete msg;
|
||||
|
|
@ -41,16 +42,20 @@ class rtsp_server_t;
|
|||
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 &&)>;
|
||||
|
||||
void print_msg(PRTSP_MESSAGE msg);
|
||||
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);
|
||||
void
|
||||
print_msg(PRTSP_MESSAGE msg);
|
||||
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> {
|
||||
public:
|
||||
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 } {}
|
||||
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 } {}
|
||||
|
||||
void read() {
|
||||
void
|
||||
read() {
|
||||
if (begin == std::end(msg_buf)) {
|
||||
BOOST_LOG(error) << "RTSP: read(): Exceeded maximum rtsp packet size: "sv << msg_buf.size();
|
||||
|
||||
|
|
@ -69,7 +74,8 @@ public:
|
|||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void read_payload() {
|
||||
void
|
||||
read_payload() {
|
||||
if (begin == std::end(msg_buf)) {
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
auto sock_close = util::fail_guard([&socket]() {
|
||||
|
|
@ -150,7 +157,8 @@ public:
|
|||
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;
|
||||
|
||||
if (ec) {
|
||||
|
|
@ -192,7 +200,8 @@ public:
|
|||
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));
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +221,8 @@ public:
|
|||
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();
|
||||
|
||||
|
|
@ -249,11 +259,13 @@ public:
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (func != std::end(_map_cmd_cb)) {
|
||||
func->second(this, sock, std::move(req));
|
||||
|
|
@ -265,7 +277,8 @@ public:
|
|||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// If a launch event is still pending, don't overwrite it.
|
||||
|
|
@ -303,13 +318,15 @@ public:
|
|||
launch_event.raise(launch_session);
|
||||
}
|
||||
|
||||
int session_count() const {
|
||||
int
|
||||
session_count() const {
|
||||
return config::stream.channels - _slot_count;
|
||||
}
|
||||
|
||||
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 (raised_timeout < std::chrono::steady_clock::now()) {
|
||||
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();
|
||||
|
||||
session_p->reset();
|
||||
|
|
@ -344,7 +362,8 @@ public:
|
|||
++_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();
|
||||
|
||||
for (auto &slot : *_session_slots) {
|
||||
|
|
@ -373,18 +392,21 @@ private:
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
int session_count() {
|
||||
int
|
||||
session_count() {
|
||||
// Ensure session_count is up-to-date
|
||||
server.clear(false);
|
||||
|
||||
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;
|
||||
|
||||
while (bytes_send != sv.size()) {
|
||||
|
|
@ -400,7 +422,8 @@ int send(tcp::socket &sock, const std::string_view &sv) {
|
|||
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);
|
||||
|
||||
// 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 });
|
||||
}
|
||||
|
||||
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 };
|
||||
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);
|
||||
}
|
||||
|
||||
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, {});
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
// 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, {});
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
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] {};
|
||||
|
||||
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.content = port_value.data();
|
||||
|
||||
|
||||
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 {};
|
||||
|
||||
// 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));
|
||||
}
|
||||
catch (std::out_of_range &) {
|
||||
|
||||
respond(sock, &option, 400, "BAD REQUEST", req->sequenceNumber, {});
|
||||
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, {});
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
// 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, {});
|
||||
}
|
||||
|
||||
void rtpThread() {
|
||||
void
|
||||
rtpThread() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
auto broadcast_shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
|
||||
|
||||
|
|
@ -737,7 +766,8 @@ void rtpThread() {
|
|||
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 payload { msg->payload, (size_t) msg->payloadLength };
|
||||
|
|
|
|||
|
|
@ -18,10 +18,13 @@ struct launch_session_t {
|
|||
bool host_audio;
|
||||
};
|
||||
|
||||
void launch_session_raise(launch_session_t launch_session);
|
||||
int session_count();
|
||||
void
|
||||
launch_session_raise(launch_session_t launch_session);
|
||||
int
|
||||
session_count();
|
||||
|
||||
void rtpThread();
|
||||
void
|
||||
rtpThread();
|
||||
|
||||
} // namespace rtsp_stream
|
||||
|
||||
|
|
|
|||
140
src/stream.cpp
140
src/stream.cpp
|
|
@ -68,7 +68,8 @@ enum class socket_e : int {
|
|||
#pragma pack(push, 1)
|
||||
|
||||
struct video_short_frame_header_t {
|
||||
uint8_t *payload() {
|
||||
uint8_t *
|
||||
payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +91,8 @@ static_assert(
|
|||
"Short frame header must be 8 bytes");
|
||||
|
||||
struct video_packet_raw_t {
|
||||
uint8_t *payload() {
|
||||
uint8_t *
|
||||
payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +103,8 @@ struct video_packet_raw_t {
|
|||
};
|
||||
|
||||
struct audio_packet_raw_t {
|
||||
uint8_t *payload() {
|
||||
uint8_t *
|
||||
payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +115,8 @@ struct control_header_v2 {
|
|||
std::uint16_t type;
|
||||
std::uint16_t payloadLength;
|
||||
|
||||
uint8_t *payload() {
|
||||
uint8_t *
|
||||
payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
};
|
||||
|
|
@ -149,14 +153,16 @@ typedef struct control_encrypted_t {
|
|||
// seq is accepted as an arbitrary value in Moonlight
|
||||
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);
|
||||
}
|
||||
// encrypted control_header_v2 and payload data follow
|
||||
} *control_encrypted_p;
|
||||
|
||||
struct audio_fec_packet_raw_t {
|
||||
uint8_t *payload() {
|
||||
uint8_t *
|
||||
payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +172,8 @@ struct audio_fec_packet_raw_t {
|
|||
|
||||
#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;
|
||||
}
|
||||
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 -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 (!(featureSet & 0x20)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
public:
|
||||
int bind(std::uint16_t port) {
|
||||
int
|
||||
bind(std::uint16_t port) {
|
||||
_host = net::host_create(_addr, config::stream.channels, port);
|
||||
|
||||
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();
|
||||
|
||||
_map_addr_session->emplace(addr, std::make_pair(0u, &session));
|
||||
|
|
@ -218,22 +229,27 @@ public:
|
|||
// 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 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:
|
||||
// iterate refers to session
|
||||
// session refers to broadcast_ctx_t
|
||||
// broadcast_ctx_t refers to control_server_t
|
||||
// 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));
|
||||
}
|
||||
|
||||
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);
|
||||
if (enet_peer_send(peer, 0, packet)) {
|
||||
enet_packet_destroy(packet);
|
||||
|
|
@ -244,7 +260,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void flush() {
|
||||
void
|
||||
flush() {
|
||||
enet_host_flush(_host.get());
|
||||
}
|
||||
|
||||
|
|
@ -341,12 +358,12 @@ struct session_t {
|
|||
* returns string_view pointing to payload data
|
||||
*/
|
||||
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(
|
||||
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) {
|
||||
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) };
|
||||
}
|
||||
|
||||
int start_broadcast(broadcast_ctx_t &ctx);
|
||||
void end_broadcast(broadcast_ctx_t &ctx);
|
||||
|
||||
int
|
||||
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);
|
||||
|
||||
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));
|
||||
|
||||
auto lg = _map_addr_session.lock();
|
||||
|
|
@ -408,7 +427,8 @@ session_t *control_server_t::get_session(const net::peer_t peer) {
|
|||
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);
|
||||
if (cb == std::end(_map_type_cb)) {
|
||||
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;
|
||||
auto res = enet_host_service(_host.get(), &event, timeout.count());
|
||||
|
||||
|
|
@ -473,20 +494,24 @@ struct fec_t {
|
|||
size_t blocksize;
|
||||
util::buffer_t<char> shards;
|
||||
|
||||
char *data(size_t el) {
|
||||
char *
|
||||
data(size_t el) {
|
||||
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 };
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t
|
||||
size() const {
|
||||
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 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
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
auto begin = std::begin(original);
|
||||
|
|
@ -585,7 +612,8 @@ std::vector<uint8_t> replace(const std::string_view &original, const std::string
|
|||
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) {
|
||||
BOOST_LOG(warning) << "Couldn't send rumble data, still waiting for PING from Moonlight"sv;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
BOOST_LOG(warning) << "Couldn't send HDR mode, still waiting for PING from Moonlight"sv;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
|
||||
});
|
||||
|
|
@ -874,7 +904,8 @@ void controlBroadcastThread(control_server_t *server) {
|
|||
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_audio_session;
|
||||
|
||||
|
|
@ -926,7 +957,6 @@ void recvThread(broadcast_ctx_t &ctx) {
|
|||
auto type_str = buf_elem ? "AUDIO"sv : "VIDEO"sv;
|
||||
BOOST_LOG(verbose) << "Recv: "sv << peer.address().to_string() << ':' << peer.port() << " :: " << type_str;
|
||||
|
||||
|
||||
populate_peer_to_session();
|
||||
|
||||
// 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 packets = mail::man->queue<video::packet_t>(mail::video_packets);
|
||||
auto timebase = boost::posix_time::microsec_clock::universal_time();
|
||||
|
|
@ -1135,7 +1166,8 @@ void videoBroadcastThread(udp::socket &sock) {
|
|||
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 packets = mail::man->queue<audio::packet_t>(mail::audio_packets);
|
||||
|
||||
|
|
@ -1192,7 +1224,6 @@ void audioBroadcastThread(udp::socket &sock) {
|
|||
try {
|
||||
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;
|
||||
|
||||
auto &fec_packet = session->audio.fec_packet;
|
||||
|
|
@ -1224,7 +1255,8 @@ void audioBroadcastThread(udp::socket &sock) {
|
|||
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 video_port = map_port(VIDEO_STREAM_PORT);
|
||||
auto audio_port = map_port(AUDIO_STREAM_PORT);
|
||||
|
|
@ -1275,7 +1307,8 @@ int start_broadcast(broadcast_ctx_t &ctx) {
|
|||
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);
|
||||
|
||||
broadcast_shutdown_event->raise(true);
|
||||
|
|
@ -1309,7 +1342,8 @@ void end_broadcast(broadcast_ctx_t &ctx) {
|
|||
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 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;
|
||||
}
|
||||
|
||||
void videoThread(session_t *session) {
|
||||
void
|
||||
videoThread(session_t *session) {
|
||||
auto fg = util::fail_guard([&]() {
|
||||
session::stop(*session);
|
||||
});
|
||||
|
|
@ -1402,7 +1437,8 @@ void videoThread(session_t *session) {
|
|||
video::capture(session->mail, session->config.monitor, session);
|
||||
}
|
||||
|
||||
void audioThread(session_t *session) {
|
||||
void
|
||||
audioThread(session_t *session) {
|
||||
auto fg = util::fail_guard([&]() {
|
||||
session::stop(*session);
|
||||
});
|
||||
|
|
@ -1429,11 +1465,13 @@ void audioThread(session_t *session) {
|
|||
namespace session {
|
||||
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);
|
||||
}
|
||||
|
||||
void stop(session_t &session) {
|
||||
void
|
||||
stop(session_t &session) {
|
||||
while_starting_do_nothing(session.state);
|
||||
auto expected = state_e::RUNNING;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
// 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.
|
||||
|
|
@ -1512,7 +1551,8 @@ void join(session_t &session) {
|
|||
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.broadcast_ref = broadcast.ref();
|
||||
|
|
@ -1539,7 +1579,6 @@ int start(session_t &session, const std::string &addr_string) {
|
|||
connections->emplace_back(addr_string, 0);
|
||||
}
|
||||
|
||||
|
||||
session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
|
||||
|
||||
session.audioThread = std::thread { audioThread, &session };
|
||||
|
|
@ -1555,7 +1594,8 @@ int start(session_t &session, const std::string &addr_string) {
|
|||
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 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,
|
||||
};
|
||||
|
||||
std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
||||
int start(session_t &session, const std::string &addr_string);
|
||||
void stop(session_t &session);
|
||||
void join(session_t &session);
|
||||
state_e state(session_t &session);
|
||||
std::shared_ptr<session_t>
|
||||
alloc(config_t &config, crypto::aes_t &gcm_key, crypto::aes_t &iv);
|
||||
int
|
||||
start(session_t &session, const std::string &addr_string);
|
||||
void
|
||||
stop(session_t &session);
|
||||
void
|
||||
join(session_t &session);
|
||||
state_e
|
||||
state(session_t &session);
|
||||
} // namespace session
|
||||
} // namespace stream
|
||||
|
||||
|
|
|
|||
31
src/sync.h
31
src/sync.h
|
|
@ -15,14 +15,17 @@ public:
|
|||
using value_t = T;
|
||||
using mutex_t = M;
|
||||
|
||||
std::lock_guard<mutex_t> lock() {
|
||||
std::lock_guard<mutex_t>
|
||||
lock() {
|
||||
return std::lock_guard { _lock };
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
raw = std::move(other.raw);
|
||||
|
|
@ -33,7 +36,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
sync_t &operator=(sync_t &other) noexcept {
|
||||
sync_t &
|
||||
operator=(sync_t &other) noexcept {
|
||||
std::lock(_lock, other._lock);
|
||||
|
||||
raw = other.raw;
|
||||
|
|
@ -45,7 +49,8 @@ public:
|
|||
}
|
||||
|
||||
template <class V>
|
||||
sync_t &operator=(V &&val) {
|
||||
sync_t &
|
||||
operator=(V &&val) {
|
||||
auto lg = lock();
|
||||
|
||||
raw = val;
|
||||
|
|
@ -53,7 +58,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
sync_t &operator=(const value_t &val) noexcept {
|
||||
sync_t &
|
||||
operator=(const value_t &val) noexcept {
|
||||
auto lg = lock();
|
||||
|
||||
raw = val;
|
||||
|
|
@ -61,7 +67,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
sync_t &operator=(value_t &&val) noexcept {
|
||||
sync_t &
|
||||
operator=(value_t &&val) noexcept {
|
||||
auto lg = lock();
|
||||
|
||||
raw = std::move(val);
|
||||
|
|
@ -69,15 +76,18 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
value_t *operator->() {
|
||||
value_t *
|
||||
operator->() {
|
||||
return &raw;
|
||||
}
|
||||
|
||||
value_t &operator*() {
|
||||
value_t &
|
||||
operator*() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
const value_t &operator*() const {
|
||||
const value_t &
|
||||
operator*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
|
@ -89,5 +99,4 @@ private:
|
|||
|
||||
} // namespace sync_util
|
||||
|
||||
|
||||
#endif // SUNSHINE_SYNC_H
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ namespace system_tray {
|
|||
* @brief Open a url in the default web browser.
|
||||
* @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;
|
||||
|
||||
// if windows
|
||||
|
|
@ -70,7 +71,8 @@ void open_url(const std::string &url) {
|
|||
* @brief Callback for opening the UI from the system tray.
|
||||
* @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;
|
||||
|
||||
// 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.
|
||||
* @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");
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +95,8 @@ void tray_donate_github_cb(struct tray_menu *item) {
|
|||
* @brief Callback for opening MEE6 donation from the system tray.
|
||||
* @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");
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +104,8 @@ void tray_donate_mee6_cb(struct tray_menu *item) {
|
|||
* @brief Callback for opening Patreon from the system tray.
|
||||
* @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");
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +113,8 @@ void tray_donate_patreon_cb(struct tray_menu *item) {
|
|||
* @brief Callback for opening PayPal donation from the system tray.
|
||||
* @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");
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +122,8 @@ void tray_donate_paypal_cb(struct tray_menu *item) {
|
|||
* @brief Callback for exiting Sunshine from the system tray.
|
||||
* @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;
|
||||
|
||||
std::raise(SIGINT);
|
||||
|
|
@ -146,13 +153,13 @@ static struct tray tray = {
|
|||
{ .text = nullptr } },
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create the system tray.
|
||||
* @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.
|
||||
*/
|
||||
int system_tray() {
|
||||
int
|
||||
system_tray() {
|
||||
if (tray_init(&tray) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to create system tray"sv;
|
||||
return 1;
|
||||
|
|
@ -172,7 +179,8 @@ int system_tray() {
|
|||
* @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.
|
||||
*/
|
||||
void run_tray() {
|
||||
void
|
||||
run_tray() {
|
||||
// create the system tray
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
// macOS requires that UI elements be created on the main thread
|
||||
|
|
@ -194,7 +202,8 @@ void run_tray() {
|
|||
* @brief Exit the system tray.
|
||||
* @return 0 after exiting the system tray.
|
||||
*/
|
||||
int end_tray() {
|
||||
int
|
||||
end_tray() {
|
||||
tray_exit();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,27 @@
|
|||
// system_tray namespace
|
||||
namespace system_tray {
|
||||
|
||||
void open_url(const std::string &url);
|
||||
void tray_open_ui_cb(struct tray_menu *item);
|
||||
void tray_donate_github_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);
|
||||
void
|
||||
open_url(const std::string &url);
|
||||
void
|
||||
tray_open_ui_cb(struct tray_menu *item);
|
||||
void
|
||||
tray_donate_github_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 run_tray();
|
||||
int end_tray();
|
||||
int
|
||||
system_tray();
|
||||
int
|
||||
run_tray();
|
||||
int
|
||||
end_tray();
|
||||
|
||||
} // namespace system_tray
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ public:
|
|||
|
||||
inline virtual ~_ImplBase() = default;
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void
|
||||
run() = 0;
|
||||
};
|
||||
|
||||
template <class Function>
|
||||
|
|
@ -29,9 +30,11 @@ class _Impl : public _ImplBase {
|
|||
Function _func;
|
||||
|
||||
public:
|
||||
_Impl(Function &&f) : _func(std::forward<Function>(f)) {}
|
||||
_Impl(Function &&f):
|
||||
_func(std::forward<Function>(f)) {}
|
||||
|
||||
void run() override {
|
||||
void
|
||||
run() override {
|
||||
_func();
|
||||
}
|
||||
};
|
||||
|
|
@ -41,7 +44,6 @@ public:
|
|||
typedef std::unique_ptr<_ImplBase> __task;
|
||||
typedef _ImplBase *task_id_t;
|
||||
|
||||
|
||||
typedef std::chrono::steady_clock::time_point __time_point;
|
||||
|
||||
template <class R>
|
||||
|
|
@ -50,7 +52,8 @@ public:
|
|||
task_id_t task_id;
|
||||
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:
|
||||
|
|
@ -60,9 +63,11 @@ protected:
|
|||
|
||||
public:
|
||||
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(_timer_tasks, other._timer_tasks);
|
||||
|
||||
|
|
@ -70,7 +75,8 @@ public:
|
|||
}
|
||||
|
||||
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");
|
||||
|
||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||
|
|
@ -90,7 +96,8 @@ public:
|
|||
return future;
|
||||
}
|
||||
|
||||
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
void
|
||||
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
auto it = _timer_tasks.cbegin();
|
||||
|
|
@ -107,7 +114,8 @@ public:
|
|||
* @return an id to potentially delay the task
|
||||
*/
|
||||
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");
|
||||
|
||||
using __return = std::invoke_result_t<Function, Args &&...>;
|
||||
|
|
@ -141,7 +149,8 @@ public:
|
|||
* @param duration The delay before executing the task
|
||||
*/
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
auto it = _timer_tasks.begin();
|
||||
|
|
@ -188,7 +198,8 @@ public:
|
|||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::optional<__task> pop() {
|
||||
std::optional<__task>
|
||||
pop() {
|
||||
std::lock_guard lg(_task_mutex);
|
||||
|
||||
if (!_tasks.empty()) {
|
||||
|
|
@ -219,13 +231,15 @@ public:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ready() {
|
||||
bool
|
||||
ready() {
|
||||
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());
|
||||
}
|
||||
|
||||
std::optional<__time_point> next() {
|
||||
std::optional<__time_point>
|
||||
next() {
|
||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
||||
|
||||
if (_timer_tasks.empty()) {
|
||||
|
|
@ -237,7 +251,8 @@ public:
|
|||
|
||||
private:
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ private:
|
|||
bool _continue;
|
||||
|
||||
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) {
|
||||
t = std::thread(&ThreadPool::_main, this);
|
||||
}
|
||||
|
|
@ -38,7 +40,8 @@ public:
|
|||
}
|
||||
|
||||
template <class Function, class... Args>
|
||||
auto push(Function &&newTask, Args &&...args) {
|
||||
auto
|
||||
push(Function &&newTask, Args &&...args) {
|
||||
std::lock_guard lg(_lock);
|
||||
auto future = TaskPool::push(std::forward<Function>(newTask), std::forward<Args>(args)...);
|
||||
|
||||
|
|
@ -46,14 +49,16 @@ public:
|
|||
return future;
|
||||
}
|
||||
|
||||
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
void
|
||||
pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||
std::lock_guard lg(_lock);
|
||||
|
||||
TaskPool::pushDelayed(std::move(task));
|
||||
}
|
||||
|
||||
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);
|
||||
auto future = TaskPool::pushDelayed(std::forward<Function>(newTask), duration, std::forward<Args>(args)...);
|
||||
|
||||
|
|
@ -62,7 +67,8 @@ public:
|
|||
return future;
|
||||
}
|
||||
|
||||
void start(int threads) {
|
||||
void
|
||||
start(int threads) {
|
||||
_continue = true;
|
||||
|
||||
_thread.resize(threads);
|
||||
|
|
@ -72,21 +78,24 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
void
|
||||
stop() {
|
||||
std::lock_guard lg(_lock);
|
||||
|
||||
_continue = false;
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
void join() {
|
||||
void
|
||||
join() {
|
||||
for (auto &t : _thread) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void _main() {
|
||||
void
|
||||
_main() {
|
||||
while (_continue) {
|
||||
if (auto task = this->pop()) {
|
||||
(*task)->run();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ public:
|
|||
using status_t = util::optional_t<T>;
|
||||
|
||||
template <class... Args>
|
||||
void raise(Args &&...args) {
|
||||
void
|
||||
raise(Args &&...args) {
|
||||
std::lock_guard lg { _lock };
|
||||
if (!_continue) {
|
||||
return;
|
||||
|
|
@ -36,7 +37,8 @@ public:
|
|||
}
|
||||
|
||||
// pop and view shoud not be used interchangeably
|
||||
status_t pop() {
|
||||
status_t
|
||||
pop() {
|
||||
std::unique_lock ul { _lock };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -58,7 +60,8 @@ public:
|
|||
|
||||
// pop and view shoud not be used interchangeably
|
||||
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 };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -77,7 +80,8 @@ public:
|
|||
}
|
||||
|
||||
// pop and view shoud not be used interchangeably
|
||||
const status_t &view() {
|
||||
const status_t &
|
||||
view() {
|
||||
std::unique_lock ul { _lock };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -95,11 +99,13 @@ public:
|
|||
return _status;
|
||||
}
|
||||
|
||||
bool peek() {
|
||||
bool
|
||||
peek() {
|
||||
return _continue && (bool) _status;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
void
|
||||
stop() {
|
||||
std::lock_guard lg { _lock };
|
||||
|
||||
_continue = false;
|
||||
|
|
@ -107,7 +113,8 @@ public:
|
|||
_cv.notify_all();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
void
|
||||
reset() {
|
||||
std::lock_guard lg { _lock };
|
||||
|
||||
_continue = true;
|
||||
|
|
@ -115,7 +122,8 @@ public:
|
|||
_status = util::false_v<status_t>;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool running() const {
|
||||
[[nodiscard]] bool
|
||||
running() const {
|
||||
return _continue;
|
||||
}
|
||||
|
||||
|
|
@ -132,16 +140,19 @@ class alarm_raw_t {
|
|||
public:
|
||||
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);
|
||||
|
||||
_status = status;
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
void ring(status_t &&status) {
|
||||
void
|
||||
ring(status_t &&status) {
|
||||
std::lock_guard lg(_lock);
|
||||
|
||||
_status = std::move(status);
|
||||
|
|
@ -149,53 +160,62 @@ public:
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
return _cv.wait_for(ul, rel_time, [this]() { return (bool) status(); });
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return _cv.wait_for(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return _cv.wait_until(ul, rel_time, [this]() { return (bool) status(); });
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return _cv.wait_until(ul, rel_time, [this, &pred]() { return (bool) status() || pred(); });
|
||||
}
|
||||
|
||||
auto wait() {
|
||||
auto
|
||||
wait() {
|
||||
std::unique_lock ul(_lock);
|
||||
_cv.wait(ul, [this]() { return (bool) status(); });
|
||||
}
|
||||
|
||||
template <class Pred>
|
||||
auto wait(Pred &&pred) {
|
||||
auto
|
||||
wait(Pred &&pred) {
|
||||
std::unique_lock ul(_lock);
|
||||
_cv.wait(ul, [this, &pred]() { return (bool) status() || pred(); });
|
||||
}
|
||||
|
||||
const status_t &status() const {
|
||||
const status_t &
|
||||
status() const {
|
||||
return _status;
|
||||
}
|
||||
|
||||
status_t &status() {
|
||||
status_t &
|
||||
status() {
|
||||
return _status;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
void
|
||||
reset() {
|
||||
_status = status_t {};
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +230,8 @@ template<class T>
|
|||
using alarm_t = std::shared_ptr<alarm_raw_t<T>>;
|
||||
|
||||
template <class T>
|
||||
alarm_t<T> make_alarm() {
|
||||
alarm_t<T>
|
||||
make_alarm() {
|
||||
return std::make_shared<alarm_raw_t<T>>();
|
||||
}
|
||||
|
||||
|
|
@ -219,10 +240,12 @@ class queue_t {
|
|||
public:
|
||||
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>
|
||||
void raise(Args &&...args) {
|
||||
void
|
||||
raise(Args &&...args) {
|
||||
std::lock_guard ul { _lock };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -238,12 +261,14 @@ public:
|
|||
_cv.notify_all();
|
||||
}
|
||||
|
||||
bool peek() {
|
||||
bool
|
||||
peek() {
|
||||
return _continue && !_queue.empty();
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -262,7 +287,8 @@ public:
|
|||
return val;
|
||||
}
|
||||
|
||||
status_t pop() {
|
||||
status_t
|
||||
pop() {
|
||||
std::unique_lock ul { _lock };
|
||||
|
||||
if (!_continue) {
|
||||
|
|
@ -283,11 +309,13 @@ public:
|
|||
return val;
|
||||
}
|
||||
|
||||
std::vector<T> &unsafe() {
|
||||
std::vector<T> &
|
||||
unsafe() {
|
||||
return _queue;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
void
|
||||
stop() {
|
||||
std::lock_guard lg { _lock };
|
||||
|
||||
_continue = false;
|
||||
|
|
@ -295,7 +323,8 @@ public:
|
|||
_cv.notify_all();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool running() const {
|
||||
[[nodiscard]] bool
|
||||
running() const {
|
||||
return _continue;
|
||||
}
|
||||
|
||||
|
|
@ -320,14 +349,18 @@ public:
|
|||
struct ptr_t {
|
||||
shared_t *owner;
|
||||
|
||||
ptr_t() : owner { nullptr } {}
|
||||
explicit ptr_t(shared_t *owner) : owner { owner } {}
|
||||
ptr_t():
|
||||
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_t(const ptr_t &ptr) noexcept : owner { ptr.owner } {
|
||||
ptr_t(const ptr_t &ptr) noexcept:
|
||||
owner { ptr.owner } {
|
||||
if (!owner) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -336,7 +369,8 @@ public:
|
|||
tmp.owner = nullptr;
|
||||
}
|
||||
|
||||
ptr_t &operator=(const ptr_t &ptr) noexcept {
|
||||
ptr_t &
|
||||
operator=(const ptr_t &ptr) noexcept {
|
||||
if (!ptr.owner) {
|
||||
release();
|
||||
|
||||
|
|
@ -346,7 +380,8 @@ public:
|
|||
return *this = std::move(*ptr.owner->ref());
|
||||
}
|
||||
|
||||
ptr_t &operator=(ptr_t &&ptr) noexcept {
|
||||
ptr_t &
|
||||
operator=(ptr_t &&ptr) noexcept {
|
||||
if (owner) {
|
||||
release();
|
||||
}
|
||||
|
|
@ -366,7 +401,8 @@ public:
|
|||
return owner != nullptr;
|
||||
}
|
||||
|
||||
void release() {
|
||||
void
|
||||
release() {
|
||||
std::lock_guard lg { owner->_lock };
|
||||
|
||||
if (!--owner->_count) {
|
||||
|
|
@ -377,18 +413,22 @@ public:
|
|||
owner = nullptr;
|
||||
}
|
||||
|
||||
element_type *get() const {
|
||||
element_type *
|
||||
get() const {
|
||||
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
||||
}
|
||||
|
||||
element_type *operator->() {
|
||||
element_type *
|
||||
operator->() {
|
||||
return reinterpret_cast<element_type *>(owner->_object_buf.data());
|
||||
}
|
||||
};
|
||||
|
||||
template <class FC, class FD>
|
||||
shared_t(FC &&fc, FD &&fd) : _construct { std::forward<FC>(fc) }, _destruct { std::forward<FD>(fd) } {}
|
||||
[[nodiscard]] ptr_t ref() {
|
||||
shared_t(FC &&fc, FD &&fd):
|
||||
_construct { std::forward<FC>(fc) }, _destruct { std::forward<FD>(fd) } {}
|
||||
[[nodiscard]] ptr_t
|
||||
ref() {
|
||||
std::lock_guard lg { _lock };
|
||||
|
||||
if (!_count) {
|
||||
|
|
@ -414,7 +454,8 @@ private:
|
|||
};
|
||||
|
||||
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> {
|
||||
std::forward<F_Construct>(fc), std::forward<F_Destruct>(fd)
|
||||
};
|
||||
|
|
@ -425,12 +466,14 @@ using signal_t = event_t<bool>;
|
|||
class 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>
|
||||
class post_t: public T {
|
||||
public:
|
||||
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;
|
||||
|
||||
|
|
@ -440,7 +483,8 @@ public:
|
|||
};
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +497,8 @@ public:
|
|||
using queue_t = std::shared_ptr<post_t<queue_t<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 };
|
||||
|
||||
auto it = id_to_post.find(id);
|
||||
|
|
@ -468,7 +513,8 @@ public:
|
|||
}
|
||||
|
||||
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 };
|
||||
|
||||
auto it = id_to_post.find(id);
|
||||
|
|
@ -482,7 +528,8 @@ public:
|
|||
return post;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
void
|
||||
cleanup() {
|
||||
std::lock_guard lg { mutex };
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
inline void cleanup(mail_raw_t *mail) {
|
||||
inline void
|
||||
cleanup(mail_raw_t *mail) {
|
||||
mail->cleanup();
|
||||
}
|
||||
} // namespace safe
|
||||
|
|
|
|||
14
src/upnp.cpp
14
src/upnp.cpp
|
|
@ -35,12 +35,12 @@ struct mapping_t {
|
|||
bool tcp;
|
||||
};
|
||||
|
||||
void unmap(
|
||||
void
|
||||
unmap(
|
||||
const urls_t &urls,
|
||||
const IGDdatas &data,
|
||||
std::vector<mapping_t>::const_reverse_iterator begin,
|
||||
std::vector<mapping_t>::const_reverse_iterator end) {
|
||||
|
||||
BOOST_LOG(debug) << "Unmapping UPNP ports"sv;
|
||||
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
|
|
@ -61,8 +61,8 @@ void unmap(
|
|||
class deinit_t: public platf::deinit_t {
|
||||
public:
|
||||
using iter_t = std::vector<mapping_t>::const_reverse_iterator;
|
||||
deinit_t(urls_t &&urls, IGDdatas data, std::vector<mapping_t> &&mapping)
|
||||
: urls { std::move(urls) }, data { data }, mapping { std::move(mapping) } {}
|
||||
deinit_t(urls_t &&urls, IGDdatas data, std::vector<mapping_t> &&mapping):
|
||||
urls { std::move(urls) }, data { data }, mapping { std::move(mapping) } {}
|
||||
|
||||
~deinit_t() {
|
||||
BOOST_LOG(info) << "Unmapping UPNP ports..."sv;
|
||||
|
|
@ -75,7 +75,8 @@ public:
|
|||
std::vector<mapping_t> mapping;
|
||||
};
|
||||
|
||||
static std::string_view status_string(int status) {
|
||||
static std::string_view
|
||||
status_string(int status) {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return "No IGD device found"sv;
|
||||
|
|
@ -90,7 +91,8 @@ static std::string_view status_string(int status) {
|
|||
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]) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
#include "platform/common.h"
|
||||
|
||||
namespace upnp {
|
||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> start();
|
||||
[[nodiscard]] std::unique_ptr<platf::deinit_t>
|
||||
start();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
315
src/utility.h
315
src/utility.h
|
|
@ -40,16 +40,21 @@ struct argument_type<T(U)> {
|
|||
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); \
|
||||
return *this; \
|
||||
} \
|
||||
element_type *operator->() { return ⪙ } \
|
||||
const element_type *operator->() const { return ⪙ } \
|
||||
element_type * \
|
||||
operator->() { return ⪙ } \
|
||||
const element_type * \
|
||||
operator->() const { return ⪙ } \
|
||||
\
|
||||
inline element_type release() { \
|
||||
inline element_type \
|
||||
release() { \
|
||||
element_type val = std::move(el); \
|
||||
el = element_type { init_val }; \
|
||||
return val; \
|
||||
|
|
@ -146,8 +151,10 @@ template<class T>
|
|||
class FailGuard {
|
||||
public:
|
||||
FailGuard() = delete;
|
||||
FailGuard(T &&f) noexcept : _func { std::forward<T>(f) } {}
|
||||
FailGuard(FailGuard &&other) noexcept : _func { std::move(other._func) } {
|
||||
FailGuard(T &&f) noexcept:
|
||||
_func { std::forward<T>(f) } {}
|
||||
FailGuard(FailGuard &&other) noexcept:
|
||||
_func { std::move(other._func) } {
|
||||
this->failure = other.failure;
|
||||
|
||||
other.failure = false;
|
||||
|
|
@ -155,8 +162,10 @@ public:
|
|||
|
||||
FailGuard(const FailGuard &) = delete;
|
||||
|
||||
FailGuard &operator=(const FailGuard &) = delete;
|
||||
FailGuard &operator=(FailGuard &&other) = delete;
|
||||
FailGuard &
|
||||
operator=(const FailGuard &) = delete;
|
||||
FailGuard &
|
||||
operator=(FailGuard &&other) = delete;
|
||||
|
||||
~FailGuard() noexcept {
|
||||
if (failure) {
|
||||
|
|
@ -164,7 +173,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void disable() { failure = false; }
|
||||
void
|
||||
disable() { failure = false; }
|
||||
bool failure { true };
|
||||
|
||||
private:
|
||||
|
|
@ -172,12 +182,14 @@ private:
|
|||
};
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] auto fail_guard(T &&f) {
|
||||
[[nodiscard]] auto
|
||||
fail_guard(T &&f) {
|
||||
return FailGuard<T> { std::forward<T>(f) };
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
buf.reserve(data_len);
|
||||
|
|
@ -219,34 +231,43 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
char *begin() { return _hex; }
|
||||
char *end() { return _hex + sizeof(elem_type) * 2; }
|
||||
char *
|
||||
begin() { return _hex; }
|
||||
char *
|
||||
end() { return _hex + sizeof(elem_type) * 2; }
|
||||
|
||||
const char *begin() const { return _hex; }
|
||||
const char *end() const { return _hex + sizeof(elem_type) * 2; }
|
||||
const char *
|
||||
begin() const { return _hex; }
|
||||
const char *
|
||||
end() const { return _hex + sizeof(elem_type) * 2; }
|
||||
|
||||
const char *cbegin() const { return _hex; }
|
||||
const char *cend() const { return _hex + sizeof(elem_type) * 2; }
|
||||
const char *
|
||||
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() };
|
||||
}
|
||||
|
||||
std::string_view to_string_view() const {
|
||||
std::string_view
|
||||
to_string_view() const {
|
||||
return { begin(), sizeof(elem_type) * 2 };
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
std::string hex;
|
||||
hex.resize(str_size);
|
||||
|
||||
|
|
@ -268,17 +289,18 @@ std::string hex_vec(It begin, It end, bool rev = false) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return hex;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
static char constexpr shift_bit = 'a' - 'A';
|
||||
|
|
@ -381,7 +404,8 @@ template<class T>
|
|||
class hash {
|
||||
public:
|
||||
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);
|
||||
|
||||
return std::hash<std::string_view> {}(std::string_view { p, sizeof(value_type) });
|
||||
|
|
@ -389,16 +413,19 @@ public:
|
|||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -423,26 +451,32 @@ class Either : public std::variant<std::monostate, X, Y> {
|
|||
public:
|
||||
using std::variant<std::monostate, X, Y>::variant;
|
||||
|
||||
constexpr bool has_left() const {
|
||||
constexpr bool
|
||||
has_left() const {
|
||||
return std::holds_alternative<X>(*this);
|
||||
}
|
||||
constexpr bool has_right() const {
|
||||
constexpr bool
|
||||
has_right() const {
|
||||
return std::holds_alternative<Y>(*this);
|
||||
}
|
||||
|
||||
X &left() {
|
||||
X &
|
||||
left() {
|
||||
return std::get<X>(*this);
|
||||
}
|
||||
|
||||
Y &right() {
|
||||
Y &
|
||||
right() {
|
||||
return std::get<Y>(*this);
|
||||
}
|
||||
|
||||
const X &left() const {
|
||||
const X &
|
||||
left() const {
|
||||
return std::get<X>(*this);
|
||||
}
|
||||
|
||||
const Y &right() const {
|
||||
const Y &
|
||||
right() const {
|
||||
return std::get<Y>(*this);
|
||||
}
|
||||
};
|
||||
|
|
@ -455,29 +489,36 @@ public:
|
|||
using pointer = element_type *;
|
||||
using deleter_type = D;
|
||||
|
||||
constexpr uniq_ptr() noexcept : _p { nullptr } {}
|
||||
constexpr uniq_ptr(std::nullptr_t) noexcept : _p { nullptr } {}
|
||||
constexpr uniq_ptr() noexcept:
|
||||
_p { nullptr } {}
|
||||
constexpr uniq_ptr(std::nullptr_t) noexcept:
|
||||
_p { nullptr } {}
|
||||
|
||||
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>
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
reset(other.release());
|
||||
|
||||
|
|
@ -485,7 +526,8 @@ public:
|
|||
}
|
||||
|
||||
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");
|
||||
|
||||
reset(uniq.release());
|
||||
|
|
@ -497,7 +539,8 @@ public:
|
|||
reset();
|
||||
}
|
||||
|
||||
void reset(pointer p = pointer()) {
|
||||
void
|
||||
reset(pointer p = pointer()) {
|
||||
if (_p) {
|
||||
_deleter(_p);
|
||||
}
|
||||
|
|
@ -505,45 +548,56 @@ public:
|
|||
_p = p;
|
||||
}
|
||||
|
||||
pointer release() {
|
||||
pointer
|
||||
release() {
|
||||
auto tmp = _p;
|
||||
_p = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
pointer get() {
|
||||
pointer
|
||||
get() {
|
||||
return _p;
|
||||
}
|
||||
|
||||
const pointer get() const {
|
||||
const pointer
|
||||
get() const {
|
||||
return _p;
|
||||
}
|
||||
|
||||
const std::add_lvalue_reference_t<element_type> operator*() const {
|
||||
const std::add_lvalue_reference_t<element_type>
|
||||
operator*() const {
|
||||
return *_p;
|
||||
}
|
||||
std::add_lvalue_reference_t<element_type> operator*() {
|
||||
std::add_lvalue_reference_t<element_type>
|
||||
operator*() {
|
||||
return *_p;
|
||||
}
|
||||
const pointer operator->() const {
|
||||
const pointer
|
||||
operator->() const {
|
||||
return _p;
|
||||
}
|
||||
pointer operator->() {
|
||||
pointer
|
||||
operator->() {
|
||||
return _p;
|
||||
}
|
||||
pointer *operator&() const {
|
||||
pointer *
|
||||
operator&() const {
|
||||
return &_p;
|
||||
}
|
||||
|
||||
pointer *operator&() {
|
||||
pointer *
|
||||
operator&() {
|
||||
return &_p;
|
||||
}
|
||||
|
||||
deleter_type &get_deleter() {
|
||||
deleter_type &
|
||||
get_deleter() {
|
||||
return _deleter;
|
||||
}
|
||||
|
||||
const deleter_type &get_deleter() const {
|
||||
const deleter_type &
|
||||
get_deleter() const {
|
||||
return _deleter;
|
||||
}
|
||||
|
||||
|
|
@ -557,52 +611,62 @@ protected:
|
|||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -610,7 +674,8 @@ template<class P>
|
|||
using shared_t = std::shared_ptr<typename P::element_type>;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
@ -621,14 +686,19 @@ public:
|
|||
using pointer = element_type *;
|
||||
using reference = element_type &;
|
||||
|
||||
wrap_ptr() : _own_ptr { false }, _p { nullptr } {}
|
||||
wrap_ptr(pointer 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 } {
|
||||
wrap_ptr():
|
||||
_own_ptr { false }, _p { nullptr } {}
|
||||
wrap_ptr(pointer 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;
|
||||
}
|
||||
|
||||
wrap_ptr &operator=(wrap_ptr &&other) noexcept {
|
||||
wrap_ptr &
|
||||
operator=(wrap_ptr &&other) noexcept {
|
||||
if (_own_ptr) {
|
||||
delete _p;
|
||||
}
|
||||
|
|
@ -642,7 +712,8 @@ public:
|
|||
}
|
||||
|
||||
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");
|
||||
_own_ptr = true;
|
||||
_p = uniq_ptr.release();
|
||||
|
|
@ -650,7 +721,8 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
wrap_ptr &operator=(pointer p) {
|
||||
wrap_ptr &
|
||||
operator=(pointer p) {
|
||||
if (_own_ptr) {
|
||||
delete _p;
|
||||
}
|
||||
|
|
@ -669,16 +741,20 @@ public:
|
|||
_own_ptr = false;
|
||||
}
|
||||
|
||||
const reference operator*() const {
|
||||
const reference
|
||||
operator*() const {
|
||||
return *_p;
|
||||
}
|
||||
reference operator*() {
|
||||
reference
|
||||
operator*() {
|
||||
return *_p;
|
||||
}
|
||||
const pointer operator->() const {
|
||||
const pointer
|
||||
operator->() const {
|
||||
return _p;
|
||||
}
|
||||
pointer operator->() {
|
||||
pointer
|
||||
operator->() {
|
||||
return _p;
|
||||
}
|
||||
|
||||
|
|
@ -723,54 +799,68 @@ using optional_t = either_t<
|
|||
template <class T>
|
||||
class buffer_t {
|
||||
public:
|
||||
buffer_t() : _els { 0 } {};
|
||||
buffer_t(buffer_t &&o) noexcept : _els { o._els }, _buf { std::move(o._buf) } {
|
||||
buffer_t():
|
||||
_els { 0 } {};
|
||||
buffer_t(buffer_t &&o) noexcept:
|
||||
_els { o._els }, _buf { std::move(o._buf) } {
|
||||
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());
|
||||
}
|
||||
buffer_t &operator=(buffer_t &&o) noexcept {
|
||||
buffer_t &
|
||||
operator=(buffer_t &&o) noexcept {
|
||||
std::swap(_els, o._els);
|
||||
std::swap(_buf, o._buf);
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
explicit buffer_t(size_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) } {
|
||||
explicit buffer_t(size_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);
|
||||
}
|
||||
|
||||
T &operator[](size_t el) {
|
||||
T &
|
||||
operator[](size_t el) {
|
||||
return _buf[el];
|
||||
}
|
||||
|
||||
const T &operator[](size_t el) const {
|
||||
const T &
|
||||
operator[](size_t el) const {
|
||||
return _buf[el];
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t
|
||||
size() const {
|
||||
return _els;
|
||||
}
|
||||
|
||||
void fake_resize(std::size_t els) {
|
||||
void
|
||||
fake_resize(std::size_t els) {
|
||||
_els = els;
|
||||
}
|
||||
|
||||
T *begin() {
|
||||
T *
|
||||
begin() {
|
||||
return _buf.get();
|
||||
}
|
||||
|
||||
const T *begin() const {
|
||||
const T *
|
||||
begin() const {
|
||||
return _buf.get();
|
||||
}
|
||||
|
||||
T *end() {
|
||||
T *
|
||||
end() {
|
||||
return _buf.get() + _els;
|
||||
}
|
||||
|
||||
const T *end() const {
|
||||
const T *
|
||||
end() const {
|
||||
return _buf.get() + _els;
|
||||
}
|
||||
|
||||
|
|
@ -780,7 +870,8 @@ private:
|
|||
};
|
||||
|
||||
template <class T>
|
||||
T either(std::optional<T> &&l, T &&r) {
|
||||
T
|
||||
either(std::optional<T> &&l, T &&r) {
|
||||
if (l) {
|
||||
return std::move(*l);
|
||||
}
|
||||
|
|
@ -797,7 +888,8 @@ template<class T, class ReturnType, typename Function<ReturnType, T>::type funct
|
|||
struct Destroy {
|
||||
typedef T pointer;
|
||||
|
||||
void operator()(pointer p) {
|
||||
void
|
||||
operator()(pointer 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>>;
|
||||
|
||||
template <class T>
|
||||
void c_free(T *p) {
|
||||
void
|
||||
c_free(T *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
template <class T, class ReturnType, ReturnType (**function)(T *)>
|
||||
void dynamic(T *p) {
|
||||
void
|
||||
dynamic(T *p) {
|
||||
(*function)(p);
|
||||
}
|
||||
|
||||
|
|
@ -829,12 +923,14 @@ template<class T>
|
|||
using c_ptr = safe_ptr<T, c_free<T>>;
|
||||
|
||||
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) };
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -872,7 +968,8 @@ struct endian_helper {};
|
|||
template <class T>
|
||||
struct endian_helper<T, std::enable_if_t<
|
||||
!(instantiation_of_v<std::optional, T>)>> {
|
||||
static inline T big(T x) {
|
||||
static inline T
|
||||
big(T x) {
|
||||
if constexpr (endianness<T>::little) {
|
||||
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
||||
|
||||
|
|
@ -882,7 +979,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||
return x;
|
||||
}
|
||||
|
||||
static inline T little(T x) {
|
||||
static inline T
|
||||
little(T x) {
|
||||
if constexpr (endianness<T>::big) {
|
||||
uint8_t *data = reinterpret_cast<uint8_t *>(&x);
|
||||
|
||||
|
|
@ -896,7 +994,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||
template <class T>
|
||||
struct endian_helper<T, std::enable_if_t<
|
||||
instantiation_of_v<std::optional, T>>> {
|
||||
static inline T little(T x) {
|
||||
static inline T
|
||||
little(T x) {
|
||||
if (!x) return x;
|
||||
|
||||
if constexpr (endianness<T>::big) {
|
||||
|
|
@ -908,8 +1007,8 @@ struct endian_helper<T, std::enable_if_t<
|
|||
return x;
|
||||
}
|
||||
|
||||
|
||||
static inline T big(T x) {
|
||||
static inline T
|
||||
big(T x) {
|
||||
if (!x) return x;
|
||||
|
||||
if constexpr (endianness<T>::little) {
|
||||
|
|
@ -923,10 +1022,12 @@ struct endian_helper<T, std::enable_if_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>
|
||||
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 util
|
||||
#endif
|
||||
|
|
|
|||
18
src/uuid.h
18
src/uuid.h
|
|
@ -12,7 +12,8 @@ union uuid_t {
|
|||
std::uint32_t b32[4];
|
||||
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());
|
||||
|
||||
uuid_t buf;
|
||||
|
|
@ -26,7 +27,8 @@ union uuid_t {
|
|||
return buf;
|
||||
}
|
||||
|
||||
static uuid_t generate() {
|
||||
static uuid_t
|
||||
generate() {
|
||||
std::random_device r;
|
||||
|
||||
std::default_random_engine engine { r() };
|
||||
|
|
@ -34,7 +36,8 @@ union uuid_t {
|
|||
return generate(engine);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string string() const {
|
||||
[[nodiscard]] std::string
|
||||
string() const {
|
||||
std::string result;
|
||||
|
||||
result.reserve(sizeof(uuid_t) * 2 + 4);
|
||||
|
|
@ -61,15 +64,18 @@ union uuid_t {
|
|||
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];
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
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 h264_nalu = "\000\000\000\001e"sv;
|
||||
|
||||
void free_ctx(AVCodecContext *ctx) {
|
||||
void
|
||||
free_ctx(AVCodecContext *ctx) {
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
|
||||
void free_frame(AVFrame *frame) {
|
||||
void
|
||||
free_frame(AVFrame *frame) {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
void free_buffer(AVBufferRef *ref) {
|
||||
void
|
||||
free_buffer(AVBufferRef *ref) {
|
||||
av_buffer_unref(&ref);
|
||||
}
|
||||
|
||||
|
|
@ -78,19 +81,25 @@ enum class profile_hevc_e : int {
|
|||
};
|
||||
} // 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);
|
||||
platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt);
|
||||
util::Either<buffer_t, int>
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
class swdevice_t: public platf::hwdevice_t {
|
||||
public:
|
||||
int convert(platf::img_t &img) override {
|
||||
int
|
||||
convert(platf::img_t &img) override {
|
||||
av_frame_make_writable(sw_frame.get());
|
||||
|
||||
const int linesizes[2] {
|
||||
|
|
@ -131,7 +140,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||
int
|
||||
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
|
||||
this->frame = frame;
|
||||
|
||||
// If it's a hwframe, allocate buffers for hardware
|
||||
|
|
@ -147,7 +157,8 @@ public:
|
|||
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_getCoefficients(SWS_CS_DEFAULT), 0,
|
||||
sws_getCoefficients(colorspace), color_range - 1,
|
||||
|
|
@ -157,7 +168,8 @@ public:
|
|||
/**
|
||||
* When preserving aspect ratio, ensure that padding is black
|
||||
*/
|
||||
int prefill() {
|
||||
int
|
||||
prefill() {
|
||||
auto frame = sw_frame ? sw_frame.get() : this->frame;
|
||||
auto width = frame->width;
|
||||
auto height = frame->height;
|
||||
|
|
@ -195,7 +207,8 @@ public:
|
|||
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 (hardware) {
|
||||
sw_frame.reset(av_frame_alloc());
|
||||
|
|
@ -273,7 +286,8 @@ struct encoder_t {
|
|||
MAX_FLAGS
|
||||
};
|
||||
|
||||
static std::string_view from_flag(flag_e flag) {
|
||||
static std::string_view
|
||||
from_flag(flag_e flag) {
|
||||
#define _CONVERT(x) \
|
||||
case flag_e::x: \
|
||||
return #x##sv
|
||||
|
|
@ -300,7 +314,8 @@ struct encoder_t {
|
|||
std::string name;
|
||||
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;
|
||||
|
|
@ -317,11 +332,13 @@ struct encoder_t {
|
|||
std::string name;
|
||||
std::bitset<MAX_FLAGS> capabilities;
|
||||
|
||||
bool operator[](flag_e flag) const {
|
||||
bool
|
||||
operator[](flag_e flag) const {
|
||||
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];
|
||||
}
|
||||
} hevc, h264;
|
||||
|
|
@ -334,7 +351,8 @@ struct encoder_t {
|
|||
class session_t {
|
||||
public:
|
||||
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() {
|
||||
|
|
@ -344,7 +362,8 @@ public:
|
|||
}
|
||||
|
||||
// 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);
|
||||
ctx = std::move(other.ctx);
|
||||
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 };
|
||||
};
|
||||
|
||||
int start_capture_sync(capture_thread_sync_ctx_t &ctx);
|
||||
void 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);
|
||||
int
|
||||
start_capture_sync(capture_thread_sync_ctx_t &ctx);
|
||||
void
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
for (int x = 0; x < 2; ++x) {
|
||||
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,
|
||||
sync_util::sync_t<std::weak_ptr<platf::display_t>> &display_wp,
|
||||
safe::signal_t &reinit_event,
|
||||
|
|
@ -822,7 +847,6 @@ void captureThread(
|
|||
},
|
||||
*round_robin++, &display_cursor);
|
||||
|
||||
|
||||
if (artificial_reinit && status != platf::capture_e::error) {
|
||||
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;
|
||||
|
||||
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.replacements.emplace_back(
|
||||
std::string_view((char *) std::begin(sps.old), sps.old.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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void encode_run(
|
||||
void
|
||||
encode_run(
|
||||
int &frame_nr, // Store progress of the frame number
|
||||
safe::mail_t mail,
|
||||
img_event_t images,
|
||||
|
|
@ -1280,7 +1306,6 @@ void encode_run(
|
|||
safe::signal_t &reinit_event,
|
||||
const encoder_t &encoder,
|
||||
void *channel_data) {
|
||||
|
||||
auto session = make_session(disp.get(), encoder, config, disp->width, disp->height, std::move(hwdevice));
|
||||
if (!session) {
|
||||
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 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
encode_e encode_run_sync(
|
||||
encode_e
|
||||
encode_run_sync(
|
||||
std::vector<std::unique_ptr<sync_session_ctx_t>> &synced_session_ctxs,
|
||||
encode_session_ctx_queue_t &encode_session_ctx_queue) {
|
||||
|
||||
const auto &encoder = encoders.front();
|
||||
auto display_names = platf::display_names(map_base_dev_type(encoder.base_dev_type));
|
||||
int display_p = 0;
|
||||
|
|
@ -1543,7 +1570,8 @@ encode_e encode_run_sync(
|
|||
return encode_e::ok;
|
||||
}
|
||||
|
||||
void captureThreadSync() {
|
||||
void
|
||||
captureThreadSync() {
|
||||
auto ref = capture_thread_sync.ref();
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
||||
void capture_async(
|
||||
void
|
||||
capture_async(
|
||||
safe::mail_t mail,
|
||||
config_t &config,
|
||||
void *channel_data) {
|
||||
|
||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||
|
||||
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,
|
||||
config_t config,
|
||||
void *channel_data) {
|
||||
|
||||
auto idr_events = mail->event<bool>(mail::idr);
|
||||
|
||||
idr_events->raise(true);
|
||||
|
|
@ -1682,7 +1710,8 @@ enum validate_flag_e {
|
|||
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);
|
||||
if (!disp) {
|
||||
return -1;
|
||||
|
|
@ -1740,7 +1769,8 @@ int validate_config(std::shared_ptr<platf::display_t> &disp, const encoder_t &en
|
|||
return flag;
|
||||
}
|
||||
|
||||
bool validate_encoder(encoder_t &encoder) {
|
||||
bool
|
||||
validate_encoder(encoder_t &encoder) {
|
||||
std::shared_ptr<platf::display_t> disp;
|
||||
|
||||
BOOST_LOG(info) << "Trying encoder ["sv << encoder.name << ']';
|
||||
|
|
@ -1868,7 +1898,8 @@ retry:
|
|||
return true;
|
||||
}
|
||||
|
||||
int init() {
|
||||
int
|
||||
init() {
|
||||
bool encoder_found = false;
|
||||
if (!config::video.encoder.empty()) {
|
||||
// If there is a specific encoder specified, use it if it passes validation
|
||||
|
|
@ -1985,7 +2016,8 @@ int init() {
|
|||
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()) };
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
void do_nothing(void *) {}
|
||||
void
|
||||
do_nothing(void *) {}
|
||||
|
||||
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) };
|
||||
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
|
||||
|
||||
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.reinit_event.reset();
|
||||
|
||||
|
|
@ -2096,19 +2133,23 @@ int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) {
|
|||
|
||||
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_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();
|
||||
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) {
|
||||
case AV_HWDEVICE_TYPE_D3D11VA:
|
||||
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;
|
||||
}
|
||||
|
||||
platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt) {
|
||||
platf::pix_fmt_e
|
||||
map_pix_fmt(AVPixelFormat fmt) {
|
||||
switch (fmt) {
|
||||
case AV_PIX_FMT_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;
|
||||
}
|
||||
|
||||
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 Cr_i = 1.0f - Cr;
|
||||
|
|
|
|||
24
src/video.h
24
src/video.h
|
|
@ -15,16 +15,19 @@ struct AVPacket;
|
|||
namespace video {
|
||||
|
||||
struct packet_raw_t {
|
||||
void init_packet() {
|
||||
void
|
||||
init_packet() {
|
||||
this->av_packet = av_packet_alloc();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
explicit packet_raw_t(std::nullptr_t) : channel_data { nullptr } {
|
||||
explicit packet_raw_t(std::nullptr_t):
|
||||
channel_data { nullptr } {
|
||||
init_packet();
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +41,8 @@ struct packet_raw_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;
|
||||
|
|
@ -49,8 +53,10 @@ struct packet_raw_t {
|
|||
using packet_t = std::unique_ptr<packet_raw_t>;
|
||||
|
||||
struct hdr_info_raw_t {
|
||||
explicit hdr_info_raw_t(bool enabled) : enabled { enabled }, metadata {} {};
|
||||
explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata) : enabled { enabled }, metadata { metadata } {};
|
||||
explicit hdr_info_raw_t(bool enabled):
|
||||
enabled { enabled }, metadata {} {};
|
||||
explicit hdr_info_raw_t(bool enabled, const SS_HDR_METADATA &metadata):
|
||||
enabled { enabled }, metadata { metadata } {};
|
||||
|
||||
bool enabled;
|
||||
SS_HDR_METADATA metadata;
|
||||
|
|
@ -84,12 +90,14 @@ struct alignas(16) color_t {
|
|||
|
||||
extern color_t colors[6];
|
||||
|
||||
void capture(
|
||||
void
|
||||
capture(
|
||||
safe::mail_t mail,
|
||||
config_t config,
|
||||
void *channel_data);
|
||||
|
||||
int init();
|
||||
int
|
||||
init();
|
||||
} // namespace video
|
||||
|
||||
#endif // SUNSHINE_VIDEO_H
|
||||
|
|
|
|||
2
third-party/ViGEmClient
vendored
2
third-party/ViGEmClient
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 726404ef5590ea4bfcc7d9fa40cadcb2638a5b82
|
||||
Subproject commit 9e842ba1c3a6efbb90d9b7e9346a55b1a3d10494
|
||||
2
third-party/ffmpeg-linux-aarch64
vendored
2
third-party/ffmpeg-linux-aarch64
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 4a29f4eeaf7d207f171b5afb06327a2b6912b14c
|
||||
Subproject commit 22034b2bafd873308a1857da749eabe9b537b33b
|
||||
2
third-party/ffmpeg-linux-x86_64
vendored
2
third-party/ffmpeg-linux-x86_64
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 05eff5066370a9c223b56ae8c5d0684e0d06a0fe
|
||||
Subproject commit d8f29a064caabdeb78f263a5017a5dbdaa454eb6
|
||||
2
third-party/ffmpeg-macos-aarch64
vendored
2
third-party/ffmpeg-macos-aarch64
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 645dcc56665a5a3c4f7a5284a1e42abc76cb5278
|
||||
Subproject commit 5876c4b765670deaeb6927c1785085bbf1a98b96
|
||||
2
third-party/ffmpeg-macos-x86_64
vendored
2
third-party/ffmpeg-macos-x86_64
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 759f5fc2165ef070bd300edcc691c48ccb8f84f8
|
||||
Subproject commit d75ce5ffeef371cedb6fbbb23ac5603e34c2994b
|
||||
2
third-party/ffmpeg-windows-x86_64
vendored
2
third-party/ffmpeg-windows-x86_64
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit b05f94a92ee0a3de4742f6b4897556b6b84f5dd5
|
||||
Subproject commit c4d6360a59d149b1ea097a5658ab1193e20db643
|
||||
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 EGLNativeWindowType NativeWindowType;
|
||||
|
||||
|
||||
/* 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
|
||||
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
|
||||
|
|
@ -158,7 +157,6 @@ typedef EGLNativeWindowType NativeWindowType;
|
|||
*/
|
||||
typedef khronos_int32_t EGLint;
|
||||
|
||||
|
||||
/* C++ / C typecast macros for special EGL handle values */
|
||||
#if defined(__cplusplus)
|
||||
#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__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
|
|
@ -221,7 +220,6 @@ typedef uint64_t khronos_uint64_t;
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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_
|
||||
#define GLAD_EGL_H_
|
||||
|
||||
|
||||
#define GLAD_EGL
|
||||
#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_WINDOW_BIT 0x0004
|
||||
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
#include <EGL/eglplatform.h>
|
||||
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
struct wl_buffer;
|
||||
|
|
@ -330,7 +327,6 @@ struct wl_display;
|
|||
|
||||
struct wl_resource;
|
||||
|
||||
|
||||
typedef unsigned int EGLBoolean;
|
||||
|
||||
typedef unsigned int EGLenum;
|
||||
|
|
@ -410,7 +406,6 @@ typedef void(GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error, const char *command,
|
|||
|
||||
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
|
||||
|
||||
|
||||
#define EGL_VERSION_1_0 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_0;
|
||||
#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
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
|
||||
|
||||
|
||||
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 *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;
|
||||
#define eglWaitSync glad_eglWaitSync
|
||||
|
||||
|
||||
GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
|
||||
GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load);
|
||||
GLAD_API_CALL int
|
||||
gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
|
||||
GLAD_API_CALL int
|
||||
gladLoadEGL(EGLDisplay display, GLADloadfunc load);
|
||||
|
||||
#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
|
||||
#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_Y 0x0D17
|
||||
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
typedef unsigned int GLenum;
|
||||
|
|
@ -2090,7 +2089,6 @@ typedef GLintptr GLvdpauSurfaceNV;
|
|||
|
||||
typedef void(GLAD_API_PTR *GLVULKANPROCNV)(void);
|
||||
|
||||
|
||||
#define GL_VERSION_1_0 1
|
||||
#define GL_VERSION_1_1 1
|
||||
#define GL_VERSION_1_2 1
|
||||
|
|
@ -4235,15 +4233,17 @@ typedef struct GladGLContext {
|
|||
PFNGLWINDOWPOS3SVPROC WindowPos3sv;
|
||||
} GladGLContext;
|
||||
|
||||
|
||||
GLAD_API_CALL int gladLoadGLContextUserPtr(GladGLContext *context, GLADuserptrloadfunc load, void *userptr);
|
||||
GLAD_API_CALL int gladLoadGLContext(GladGLContext *context, GLADloadfunc load);
|
||||
|
||||
GLAD_API_CALL int
|
||||
gladLoadGLContextUserPtr(GladGLContext *context, GLADuserptrloadfunc load, void *userptr);
|
||||
GLAD_API_CALL int
|
||||
gladLoadGLContext(GladGLContext *context, GLADloadfunc load);
|
||||
|
||||
#ifdef GLAD_GL
|
||||
|
||||
GLAD_API_CALL int gladLoaderLoadGLContext(GladGLContext *context);
|
||||
GLAD_API_CALL void gladLoaderUnloadGL(void);
|
||||
GLAD_API_CALL int
|
||||
gladLoaderLoadGLContext(GladGLContext *context);
|
||||
GLAD_API_CALL void
|
||||
gladLoaderUnloadGL(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
2
third-party/miniupnp
vendored
2
third-party/miniupnp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit e439318cf782e30066d430f27a1365e013a5ab94
|
||||
Subproject commit 014c9df8ee7a36e5bf85aa619062a2d4b95ec8f6
|
||||
2
third-party/moonlight-common-c
vendored
2
third-party/moonlight-common-c
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit c9426a6a71c4162e65dde8c0c71a25f1dbca46ba
|
||||
Subproject commit d3cb8131d12832898af31c4f2484ec1bd6bed0f4
|
||||
2
third-party/nanors
vendored
2
third-party/nanors
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit e9e242e98e27037830490b2a752895ca68f75f8b
|
||||
Subproject commit 395e5ada44dd8d5974eaf6bb6b17f23406e3ca72
|
||||
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
|
||||
* 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.
|
||||
|
|
@ -1551,7 +1552,8 @@ const char *NVFBCAPI NvFBCGetLastErrorStr(const NVFBC_SESSION_HANDLE sessionHand
|
|||
* ::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.
|
||||
|
|
@ -1577,7 +1579,8 @@ NVFBCSTATUS NVFBCAPI NvFBCCreateHandle(NVFBC_SESSION_HANDLE *pSessionHandle, NVF
|
|||
* ::NVFBC_ERR_CONTEXT \n
|
||||
* ::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.
|
||||
|
|
@ -1596,7 +1599,8 @@ NVFBCSTATUS NVFBCAPI NvFBCDestroyHandle(const NVFBC_SESSION_HANDLE sessionHandle
|
|||
* ::NVFBC_ERR_INTERNAL \n
|
||||
* ::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.
|
||||
|
|
@ -1630,7 +1634,8 @@ NVFBCSTATUS NVFBCAPI NvFBCGetStatus(const NVFBC_SESSION_HANDLE sessionHandle, NV
|
|||
* ::NVFBC_ERR_INTERNAL \n
|
||||
* ::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.
|
||||
|
|
@ -1651,7 +1656,8 @@ NVFBCSTATUS NVFBCAPI NvFBCBindContext(const NVFBC_SESSION_HANDLE sessionHandle,
|
|||
* ::NVFBC_ERR_INTERNAL \n
|
||||
* ::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.
|
||||
|
|
@ -1686,7 +1692,8 @@ NVFBCSTATUS NVFBCAPI NvFBCReleaseContext(const NVFBC_SESSION_HANDLE sessionHandl
|
|||
* ::NVFBC_ERR_MUST_RECREATE \n
|
||||
* ::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.
|
||||
|
|
@ -1710,7 +1717,8 @@ NVFBCSTATUS NVFBCAPI NvFBCCreateCaptureSession(const NVFBC_SESSION_HANDLE sessio
|
|||
* ::NVFBC_ERR_INTERNAL \n
|
||||
* ::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.
|
||||
|
|
@ -1742,7 +1750,8 @@ NVFBCSTATUS NVFBCAPI NvFBCDestroyCaptureSession(const NVFBC_SESSION_HANDLE sessi
|
|||
* ::NVFBC_ERR_OUT_OF_MEMORY \n
|
||||
* ::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.
|
||||
|
|
@ -1782,7 +1791,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToSysSetUp(const NVFBC_SESSION_HANDLE sessionHandle, N
|
|||
* \see NvFBCCreateCaptureSession \n
|
||||
* \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.
|
||||
|
|
@ -1809,7 +1819,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToSysGrabFrame(const NVFBC_SESSION_HANDLE sessionHandl
|
|||
* ::NVFBC_ERR_GL \n
|
||||
* ::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.
|
||||
|
|
@ -1838,7 +1849,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToCudaSetUp(const NVFBC_SESSION_HANDLE sessionHandle,
|
|||
* \see NvFBCCreateCaptureSession \n
|
||||
* \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.
|
||||
|
|
@ -1865,7 +1877,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToCudaGrabFrame(const NVFBC_SESSION_HANDLE sessionHand
|
|||
* ::NVFBC_ERR_GL \n
|
||||
* ::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.
|
||||
|
|
@ -1893,7 +1906,8 @@ NVFBCSTATUS NVFBCAPI NvFBCToGLSetUp(const NVFBC_SESSION_HANDLE sessionHandle, NV
|
|||
* \see NvFBCCreateCaptureSession \n
|
||||
* \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
|
||||
|
|
@ -1966,7 +1980,8 @@ typedef struct
|
|||
* ::NVFBC_ERR_INVALID_PTR \n
|
||||
* ::NVFBC_ERR_API_VERSION
|
||||
*/
|
||||
NVFBCSTATUS NVFBCAPI NvFBCCreateInstance(NVFBC_API_FUNCTION_LIST *pFunctionList);
|
||||
NVFBCSTATUS NVFBCAPI
|
||||
NvFBCCreateInstance(NVFBC_API_FUNCTION_LIST *pFunctionList);
|
||||
/*!
|
||||
* \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 {
|
||||
template <class T>
|
||||
void Release(T *p) {
|
||||
void
|
||||
Release(T *p) {
|
||||
p->Release();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void co_task_free(T *p) {
|
||||
void
|
||||
co_task_free(T *p) {
|
||||
CoTaskMemFree((LPVOID) p);
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +67,8 @@ public:
|
|||
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";
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +103,8 @@ struct format_t {
|
|||
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->nBlockAlign = wave_format->nChannels * wave_format->wBitsPerSample / 8;
|
||||
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;
|
||||
auto status = device->Activate(
|
||||
IID_IAudioClient,
|
||||
|
|
@ -171,7 +176,8 @@ audio_client_t make_audio_client(device_t &device, const format_t &format) {
|
|||
return audio_client;
|
||||
}
|
||||
|
||||
void print_device(device_t &device) {
|
||||
void
|
||||
print_device(device_t &device) {
|
||||
audio::wstring_t wstring;
|
||||
DWORD device_state;
|
||||
|
||||
|
|
@ -231,14 +237,16 @@ void print_device(device_t &device) {
|
|||
}
|
||||
} // namespace audio
|
||||
|
||||
void print_help() {
|
||||
void
|
||||
print_help() {
|
||||
std::cout
|
||||
<< "==== Help ===="sv << std::endl
|
||||
<< "Usage:"sv << 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);
|
||||
|
||||
auto fg = util::fail_guard([]() {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
using namespace std::literals;
|
||||
namespace dxgi {
|
||||
template <class T>
|
||||
void Release(T *dxgi) {
|
||||
void
|
||||
Release(T *dxgi) {
|
||||
dxgi->Release();
|
||||
}
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDup
|
|||
|
||||
} // 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.
|
||||
WCHAR executable_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, executable_path, ARRAYSIZE(executable_path));
|
||||
|
|
@ -46,7 +48,8 @@ LSTATUS set_gpu_preference(int preference) {
|
|||
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_11_1,
|
||||
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);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
HRESULT status;
|
||||
|
||||
// Display name may be omitted
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
using namespace std::literals;
|
||||
namespace dxgi {
|
||||
template <class T>
|
||||
void Release(T *dxgi) {
|
||||
void
|
||||
Release(T *dxgi) {
|
||||
dxgi->Release();
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +23,8 @@ using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
|||
|
||||
} // namespace dxgi
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
HRESULT status;
|
||||
|
||||
dxgi::factory1_t::pointer factory_p {};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
* To run a command, such as 'ipconfig /flushdns', with administrative privileges, execute:
|
||||
* 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)
|
||||
if (argc < 2) {
|
||||
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
Loading…
Add table
Add a link
Reference in a new issue